本文介绍了如何让两种构建风格继承自 Android Studio 中的根风格?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我曾经有以下项目风格:

I used to have the following project flavors:

  1. 苹果
  2. 橙色

最初唯一的区别是 applicationId/packageName.现在有一个不同的 java 文件.确切地说,是一个自定义的 ArrayAdapter.解决方案是创建 src/Applesrc/Orange 并且都继承自 src/main.我从 src/main 中删除了 java 文件,并将副本放入 src/Applesrc/Orange 并进行了适当的修改.世界上一切都很好.

Originally the only difference was the applicationId/packageName. Now there is a single java file that is different. A custom ArrayAdapter to be exact. The solution was to create src/Apple and src/Orange and both inherit from src/main. I removed the java file from src/main and put a copy into src/Apple and src/Orange and modified it appropriately. All was good in the world.

快进几周,现在 Apple 和 Orange 之间大约有 10 个 java 文件不同.再次......没什么大不了的.易于处理.将 src/Applesrc/Orange 中的 java 文件分开.

Fast forward a few weeks, now there are about 10 java files that differ between Apple and Orange. Again... no big deal. Easy to handle. Separate java files in src/Apple and src/Orange.

快进到今天.我需要稍微修改一下,因为我想拥有每个版本的免费和高级版本.免费版和高级版仅在 URL 上有所不同.我打算简单地创建新类型,称为:

Fast forward to today. I need to modify things up a bit, because I want to have a free and premium version of each. The free and premium versions only differ by a URL. I was going to simply create the new types called:

  1. Apple免费
  2. ApplePremium
  3. OrangeFree
  4. OrangePremium

但我有一个难题.从现在开始 src/Applesrc/Orange 有 10 个不同的文件已更改...如果我更改 AppleFree 中的任何 java 文件,我必须确保我在 ApplePremium 中也这样做.我有点处于十字路口,希望我的问题在这一点上是有道理的.我提出了三种可能的解决方案,但我不确定我将如何实施它们/正确的方法是什么/解决方案不是我想要的.

I have a dilema though. Since now src/Apple and src/Orange have 10 different files that have been changed... if I change any java file in AppleFree I have to make sure I do the same in ApplePremium. I'm kind of at a crossroads and hope my question makes sense at this point. I have come up with three possible solutions, but I'm not sure how I would implement them/what would be the correct approach/the solution is not what I want.

使用 if 语句if (BuildConfig.FLAVOR==appleFree) {//使用免费网址} else {//使用高级网址}

问题: 两个 Url 在技术上都编译到 apk 中.我不想要这个.

Issue: Both Urls are technically compiled into the apk. I do not want this.

让 src/AppleFree 和 src/ApplePremium 以某种方式从 src/Apple 父目录继承.

Have src/AppleFree and src/ApplePremium inherit from an src/Apple parent directory somehow.

问题:不知道该怎么做.

像这样在 build.gradle 中添加免费和高级网址吗?

Add the free and premium url right in build.gradle like so?

    productFlavors {
            appleFree {
                applicationId "com.example.apple.free"
                versionName "1.0"
                url "http://freeurl.com"
                versionCode 1
            }
            applePremium {
                applicationId "com.example.apple.premium"
                versionName "1.0"
                url "http://premiumurl.com"
                versionCode 1
            }
            orangeFree {
                applicationId "com.example.orange.free"
                versionName "1.0"
                versionCode 1
                url "http://freeurl.com"


            }
            orangePremium {
                applicationId "com.example.orange.premium"
                url "http://premiumurl.com"
                versionName "1.0"
                versionCode 1

            }
        }

问题:不确定如何实现.

任何提示都是有帮助的.

Any tips are helpful.

flavorGroups 'fruit', 'paid'

productFlavors {
    apple {
        flavorGroup 'fruit'
    }
    orange {
        flavorGroup 'fruit'
    }
    free {
        flavorGroup 'paid'
    }
    premium {
        flavorGroup 'paid'
    }
    appleFree {
        applicationId "com.example.apple.free"
        versionName "1.0"
        buildConfigField 'String', 'BASE_URL', 'http://freeurl.com'
        versionCode 1
    }
    applePremium {
        applicationId "com.example.apple.premium"
        versionName "1.0"
        buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com'
        versionCode 1
    }
    orangeFree {
        applicationId "com.example.orange.free"
        versionName "1.0"
        versionCode 1
        buildConfigField 'String', 'BASE_URL', 'http://freeurl.com'
    }
    orangePremium {
        applicationId "com.example.orange.premium"
        buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com'
        versionName "1.0"
        versionCode 1
    }
    }

推荐答案

您的问题有很多可能的解决方案.最原生的 Gradle 解决方案是使用 Flavor Dimensions,如 http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Multi-flavor-variants

There are many possible solutions to your problem. The most native-Gradle solution would be to use Flavor Dimensions, as documented in http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Multi-flavor-variants

这也与您对解决方案 2 的想法类似.

This is also similar to what you were thinking about with Solution 2.

它会像这样工作:

flavorDimensions 'fruit', 'paid'

productFlavors {
    apple {
        dimension 'fruit'
    }
    orange {
        dimension 'fruit'
    }
    free {
        dimension 'paid'
    }
    premium {
        dimension 'paid'
    }
}

这将为您提供构建变体(和源文件夹),在其中组合每个风味维度的所有可能性,保持与您在 flavorDimensions 语句中指定组的顺序相同的顺序(即它是 appleFree,而不是 freeApple),因此:

This will give you build variants (and source folders) where it does the combination of all possibilities out of each flavor dimension, maintaining the same order as how the groups are specified in your flavorDimensions statement (i.e. it's appleFree, not freeApple), thus:

* appleFree
* applePremium
* orangeFree
* orangePremium

在您的 src/ 文件夹中,您可以有以下可能性:

in your src/ folder, you can have these possibilities:

* src/main
* src/apple
* src/orange
* src/free
* src/premium
* src/appleFree
* src/applePremium
* src/orangeFree
* src/orangePremium

解决方案 3

您可以使用 buildConfigField 来指定进入 BuildConfig 类的常量:

You can use the buildConfigField to specify constants that go in the BuildConfig class on a flavor-by-flavor basis:

productFlavors {
    appleFree {
        buildConfigField 'String', 'MY_URL', 'value1'
    }
    applePremium {
        buildConfigField 'String', 'MY_URL', 'value2'
    }
    orangeFree {
        buildConfigField 'String', 'MY_URL', 'value3'
    }
    orangePremium {
        buildConfigField 'String', 'MY_URL', 'value4'
    }

解决方案 1

我试图按照解决方案 1 的方式进行一些工作,但它不适用于您的确切用例.如果您在 Java 中有一个 if 条件来测试声明为 static final 的布尔值,那么编译器可以静态确定代码是否可访问,并将其剥离如果不是.因此:

I was trying to work up something along the lines of Solution 1, but it won't work well for your exact use case. If you have an if condition in Java that tests against a boolean that's declared static final then the compiler can determine statically whether the code is reachable or not, and it will strip it if it's not. Thus:

static final boolean DEBUG = false;

...

if (DEBUG) {
    // do something
}

//do something 中的代码根本不会被编译.这是 Java 编译器有意并记录在案的行为,允许您编写不会编译到发布二进制文件中的昂贵调试代码.正是出于这个原因,BuildConfig.DEBUG 被声明为 static final.

The code in // do something won't get compiled at all. This is an intentional and documented behavior on the part of the Java compiler, and allows you to write expensive debug code that won't get compiled into your release binary. BuildConfig.DEBUG is declared as static final for this exact reason.

有一个BuildConfig.FLAVOR,但它被定义为String,你不会得到同样的好处:

There's a BuildConfig.FLAVOR, but it's defined as String, and you don't get the same benefit:

static final String FLAVOR = "orange";

...

if (FLAVOR.equals("apple")) {
    // do something
}

编译器不够聪明,无法进行静态分析,看到 //do something 无法访问,就不编译了.请注意,它在运行时可以正常工作,但死代码将包含在您的二进制文件中.

The compiler isn't smart enough to do static analysis, see that // do something is unreachable, and not compile it. Note that it will work fine at runtime, but that dead code will be included in your binary.

不过,如果它适合您,您可以从上面窃取 buildConfigField 方法,并在某些变体中定义一个额外的布尔变量,以允许有条件地编译代码.这比定义更复杂像 Solution 3 中那样直接使用字符串,但是如果您发现自己想要区分行为而不费心制作特定于风味的子类,您可以走这条路.

If it suits you, though, you could steal the buildConfigField approach from above and define an extra boolean variable in some variants that could allow code to be conditionally compiled in. This is more complex than defining the string directly as in Solution 3, but if you find yourself wanting to differentiate behavior without going through the trouble of making flavor-specific subclasses, you could go this route.

这篇关于如何让两种构建风格继承自 Android Studio 中的根风格?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-03 20:33
查看更多