我曾经有过以下项目风格:
最初唯一的区别是applicationId/packageName
。现在有一个不同的java文件。准确地说是自定义ArrayAdapter。解决方案是创建src/Apple
和src/Orange
,并且都从src/main
继承。我从src/main
中删除了java文件,并将副本放入src/Apple
和src/Orange
并进行了相应的修改。世界上一切都很好。
快进几周,现在Apple和Orange之间有大约10个不同的java文件。再说......没什么大不了的。易于操作。在src/Apple
和src/Orange
中分隔java文件。
快进到今天。我需要稍微修改一下,因为我希望每个都有免费的高级版本。免费版和高级版仅因URL而异。我打算简单地创建名为的新类型:
但我有一个困境。从现在起src/Apple
和src/Orange
有10个不同的文件已被更改...如果我更改AppleFree
中的任何java文件,我必须确保在{{1}中执行相同的操作}。我有点处于十字路口,希望我的问题在这一点上有意义。我提出了三种可能的解决方案,但我不确定如何实施它们/什么是正确的方法/解决方案不是我想要的。
使用if语句
ApplePremium
问题:两个Urls在技术上都编译成了apk。我不想要这个。
让src / AppleFree和src / ApplePremium以某种方式从src / Apple父目录继承。
问题:不确定我该怎么做。
直接在build.gradle中添加免费和高级网址吗?
if (BuildConfig.FLAVOR==appleFree) {//use free Url} else {// use premium url}
问题:不确定如何开展这项工作。
任何提示都有帮助。
修改
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
}
}
答案 0 :(得分: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'
}
}
这将为您提供构建变体(和源文件夹),它可以在每个样式维度中组合所有可能性,并保持与flavorDimensions
语句中指定组的顺序相同的顺序(即它&# 39; s appleFree
,而不是freeApple
),因此:
* appleFree
* applePremium
* orangeFree
* orangePremium
在 src / 文件夹中,您可以拥有以下这些可能性:
* src/main
* src/apple
* src/orange
* src/free
* src/premium
* src/appleFree
* src/applePremium
* src/orangeFree
* src/orangePremium
解决方案3
您可以使用buildConfigField
逐个指定BuildConfig
类中的常量:
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
的布尔值,那么编译器可以静态地确定代码是否可以访问,并且如果它&#它会剥离它# 39;不是。因此:
static final boolean DEBUG = false;
...
if (DEBUG) {
// do something
}
// do something
中的代码根本无法编译。这是Java编译器的有意和记录的行为,允许您编写昂贵的调试代码,这些代码不会被编译到您的发布二进制文件中。出于这个原因,BuildConfig.DEBUG
被声明为static final
。
有一个BuildConfig.FLAVOR
,但它被定义为String
,你不会得到同样的好处:
static final String FLAVOR = "orange";
...
if (FLAVOR.equals("apple")) {
// do something
}
编译器不够智能,无法进行静态分析,看到// do something
无法访问,也无法编译。 请注意,它在运行时可以正常工作,但是死代码将包含在二进制文件中。
如果它适合你,你可以从上面窃取buildConfigField
方法并在某些变体中定义一个额外的布尔变量,这些变量可以允许有条件地编译代码。这比直接定义字符串更复杂就像在解决方案3 中一样,但是如果你发现自己想要区分行为而不必经历制作特定于风味的子类的麻烦,那么你可以走这条路。