如何从Android Studio中的根风格继承两种构建风格?

EGH*_*HDK 17 android gradle android-studio build.gradle android-gradle-plugin

我曾经有过以下项目风味:

  1. 苹果
  2. 橙子

最初唯一的区别是applicationId/packageName.现在有一个不同的java文件.准确地说是自定义ArrayAdapter.解决方案是创建src/Applesrc/Orange继承src/main.我删除从Java文件src/main并把拷贝到src/Applesrc/Orange和适当修改它.世界上一切都很好.

快进几周,现在大约有10个不同的Apple和Orange之间的java文件.再说......没什么大不了的.易于操作.在src/Apple和中分隔java文件src/Orange.

快进到今天.我需要稍微修改一下,因为我希望每个都有免费的高级版本.免费版和高级版仅因URL而异.我打算简单地创建一个名为的新类型:

  1. AppleFree
  2. ApplePremium
  3. OrangeFree
  4. OrangePremium

我有一个困境.从现在起src/Apple,src/Orange有10个不同的文件已被更改...如果我更改任何java文件,AppleFree我必须确保我做同样的事情ApplePremium.我有点处于十字路口,希望我的问题在这一点上有意义.我提出了三种可能的解决方案,但我不确定如何实现它们/什么是正确的方法/解决方案不是我想要的.

解决方案1:

使用if语句 if (BuildConfig.FLAVOR==appleFree) {//use free Url} else {// use premium url}

问题:两个Urls在技术上都编译成了apk.我不想要这个.

解决方案2:

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

问题:不知道我会怎么做.

解决方案3:

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

    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

            }
        } 
Run Code Online (Sandbox Code Playgroud)

问题:不确定如何使这项工作.

任何提示都有帮助.

编辑:

最终方案?

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
    }
    }
Run Code Online (Sandbox Code Playgroud)

Sco*_*rta 12

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

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

它会像这样工作:

flavorDimensions 'fruit', 'paid'

productFlavors {
    apple {
        dimension 'fruit'
    }
    orange {
        dimension 'fruit'
    }
    free {
        dimension 'paid'
    }
    premium {
        dimension 'paid'
    }
}
Run Code Online (Sandbox Code Playgroud)

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

* appleFree
* applePremium
* orangeFree
* orangePremium
Run Code Online (Sandbox Code Playgroud)

在你的src /文件夹中,你可以有这些可能性:

* src/main
* src/apple
* src/orange
* src/free
* src/premium
* src/appleFree
* src/applePremium
* src/orangeFree
* src/orangePremium
Run Code Online (Sandbox Code Playgroud)

解决方案3

您可以使用它buildConfigFieldBuildConfig逐个指定类中的常量:

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'
    }
Run Code Online (Sandbox Code Playgroud)

解决方案1

我试图按照解决方案1的方式处理某些事情,但它不适用于您的确切用例.如果你if在Java中有一个条件来测试一个声明的布尔值,static final那么编译器可以静态地确定代码是否可以访问,如果不是,它将剥离它.从而:

static final boolean DEBUG = false;

...

if (DEBUG) {
    // do something
}
Run Code Online (Sandbox Code Playgroud)

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

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

static final String FLAVOR = "orange";

...

if (FLAVOR.equals("apple")) {
    // do something
}
Run Code Online (Sandbox Code Playgroud)

编译器不够智能,无法进行静态分析,看不到它// do something,也不能编译它.请注意,它在运行时可以正常工作,但是死代码将包含在二进制文件中.

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