android gradlee buildconfigfield 怎么引用自定义字段

前一篇文章()介绍了Android中几种生成渠道包的方式,基本解决了打包慢的问题。
但是,随着渠道越来越多,不同渠道对应用的要求也不尽相同。例如,有的渠道要求美团客户端的应用名为美团,有的渠道要求应用名为美团团购。又比如,有些渠道要求应用不能使用第三方统计工具(如flurry)。总之,每次打包都需要对这些渠道进行适配。
之前的做法是为每个需要适配的渠道创建一个Git分支,发版时再切换到相应的分支,并合并主分支的代码。适配的渠道比较少的话这种方式还可以接受,如果分支比较多,对开发人员来说简直就是噩梦。还好,自从有了Gradle flavor,一切都变得简单了。本文假定读者使用过Gradle,如果还不了解建议先阅读相关文档。
先来看build.gradle文件中的一段代码:
productFlavors {
minSdkVersion 14
上例定义了一个flavor:flavor1,并指定了应用的minSdkVersion为14(当然还可以配置更多的属性,具体可参考相关文档)。与此同时,Gradle还会为该flavor关联对应的sourceSet,默认位置为src/&flavorName&目录,对应到本例就是src/flavor1。
接下来,要做的就是根据具体的需求在build.gradle文件中配置flavor,并添加必要的代码和资源文件。以flavor1为例,运行gradle
assembleFlavor1命令既可生成所需的适配包。下面主要介绍美团团购Android客户端的一些适配案例。
使用不同的包名
美团团购Android客户端之前有两个版本:手机版(com.meituan.group)和hd版(com.meituan.group.hd),两个版本使用了不同的代码。目前hd版对应的代码已不再维护,希望能直接使用手机版的代码。解决该问题可以有多种方法,不过使用flavor相对比较简单,示例如下:
productFlavors {
applicationId &com.meituan.group.hd&
上面的代码添加了一个名为hd的flavor,并指定了应用的包名为com.meituan.group.hd,运行gradle
assembleHd命令即可生成hd适配包。
控制是否自动更新
美团团购Android客户端在启动时会默认检查客户端是否有更新,如果有更新就会提示用户下载。但是有些渠道和应用市场不允许这种默认行为,所以在适配这些渠道时需要禁止自动更新功能。
解决的思路是提供一个配置字段,应用启动的时候检查该字段的值以决定是否开启自动更新功能。使用flavor可以完美的解决这类问题。
Gradle会在generateSources阶段为flavor生成一个BuildConfig.java文件。BuildConfig类默认提供了一些常量字段,比如应用的版本名(VERSION_NAME),应用的包名(PACKAGE_NAME)等。更强大的是,开发者还可以添加自定义的一些字段。下面的示例假设wandoujia市场默认禁止自动更新功能:
defaultConfig {
buildConfigField &boolean&, &AUTO_UPDATES&, &true&
productFlavors {
wandoujia {
buildConfigField &boolean&, &AUTO_UPDATES&, &false&
上面的代码会在BuildConfig类中生成AUTO_UPDATES布尔常量,默认值为true,在使用wandoujia&flavor时,该值会被设置成false。接下来就可以在代码中使用AUTO_UPDATES常量来判断是否开启自动更新功能了。最后,运行gradle
assembleWandoujia命令即可生成默认不开启自动升级功能的渠道包,是不是很简单。
使用不同的应用名
最常见的一类适配是修改应用的资源。例如,美团团购Android客户端的应用名是美团,但有的渠道需要把应用名修改为美团团购;还有,客户端经常会和一些应用分发市场合作,需要在应用的启动界面中加上第三方市场的Logo,类似这类适配形式还有很多。
Gradle在构建应用时,会优先使用flavor所属dataSet中的同名资源。所以,解决思路就是在flavor的dataSet中添加同名的字符串资源,以覆盖默认的资源。下面以适配wandoujia渠道的应用名为美团团购为例进行介绍。
首先,在build.gradle配置文件中添加如下flavor:
productFlavors {
wandoujia {
上面的配置会默认src/wandoujia目录为wandoujia&flavor的dataSet。
接下来,在src目录内创建wandoujia目录,并添加如下应用名字符串资源(src/wandoujia/res/values/appname.xml):
&resources&
&string name=&app_name&&美团团购&/string&
&/resources&
默认的应用名字符串资源如下(src/main/res/values/strings.xml):
&resources&
&string name=&app_name&&美团&/string&
&/resources&
最后,运行gradle assembleWandoujia命令即可生成应用名为美团团购的应用了。
使用第三方SDK
某些渠道会要求客户端嵌入第三方SDK来满足特定的适配需求。比如360应用市场要求美团团购Android客户端的精品应用模块使用他们提供的SDK。问题的难点在于如何只为特定的渠道添加SDK,其他渠道不引入该SDK。使用flavor可以很好的解决这个问题,下面以为qihu360&flavor引入com.qihoo360.union.sdk:union:1.0&SDK为例进行说明:
productFlavors {
dependencies {
provided 'com.qihoo360.union.sdk:union:1.0'
qihu360Compile 'com.qihoo360.union.sdk:union:1.0'
上例添加了名为qihu360的flavor,并且指定编译和运行时都依赖com.qihoo360.union.sdk:union:1.0。而其他渠道只是在构建的时候依赖该SDK,打包的时候并不会添加它。
接下来,需要在代码中使用反射技术判断应用程序是否添加了该SDK,从而决定是否要显示360 SDK提供的精品应用。部分代码如下:
class MyActivity extends Activity {
private boolean useQihuS
public void onCreate(Bundle savedInstanceState) {
Class.forName(&com.qihoo360.union.sdk.UnionManager&);
useQihuSdk =
} catch (ClassNotFoundException ignored) {
最后,运行gradle assembleQihu360命令即可生成包含360精品应用模块的渠道包了。
适配是一项dirty工作,尤其是适配的渠道比较多的时候。上面介绍了几种使用Gradle flavor进行适配的例子,基本解决了繁杂的适配工作。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:6281次
排名:千里之外
原创:30篇
转载:60篇
(1)(2)(6)(3)(13)(5)(5)(17)(5)(17)(18)Android Studio 0.4.3 发布
Android Studio 0.4.3 发布,此版本更新内容如下:支持最新的 Android Gradle 插件 0.8 版本,不要求强制更新,用户可以继续使用 0.7 版本更新到最新的 IntelliJ 13 EAP build, #133.609 ()
支持 Gradle IDE
Updating from one version of the Gradle plugin t rather than just opening a search window showing .gradle files referencing the plugin, the upgrade quickfix now performs the edits to the plugin dependency and the gradle wrapper properties file directly and in one shot
We now automatically sync with Gradle's model after a build if we detect that the model is stale
Fixed a bug around library syncing (where library dependency classes and resources could suddenly not be found by the IDE)
New lint check which looks for cycles in style definitions, cycles in layout &include& definitions, cycles in resource aliases and cycles in color and drawable definitions.
New lint check for duplicate item definitions inside styles
New lint check for padding symmetry in right-to-left contexts
New lint check for a resource definition pattern which can cause some versions of aapt to crash
The layout editor property sheet now handles setting properties in custom namespaces
Improved threading behavior of layout rendering code (which should make editing in the XML editor with the layout render preview window more responsive)
In addition to creating new locales from the Locale menu you can now open up and edit existing translations
Fixed bug where the layout editor could show stale resource strings
导入 Eclipse
You can now import Eclipse-style projects even if they don't have .classpath and .project files as long as they use the same directory structure
More graceful handling of imports if there is a problem such as a missing dependency
其他 bug 修复
Android Gradle 插件 0.8 版本更新内容如下:Supports Gradle 1.10, requires Build-Tools 19.0.0+Fixed issue 64302: Add renderscript support mode jar to the dependencies in the IDE model.Fixed issue 64094: buildConfigField can now replace previous values inside the same type/flavors.Add support for NDK prebuilts in library projects.Parallelize pre-dexing to speed up clean builds.Incremental dexing re-enabled (though it'll be automatically disabled in some builds for some cases that dx doesn't support yet.)Added 'provided' dependency scope for compile only (not packaged) dependencies.&Additional scope per buildtype and flavors are also available (debugProvided, myFlavorProvided,etc...)Variant API improvements:getPreBuild() returns the prebuild task for the variantgetSourceSets() returns the sorted sourcesets for the task, from lower to higher prioritycreateZipAlignTask(String taskName, File inputFile, File outputFile).This creates and return a new zipalign task. Useful if you have a custom plugin providing custom signing of APKs.&This also makes the assemble task depend on the new zipalign task, and wires variant.getOutputFile() to return the result of the zipalign task.project.android.registerJavaArtifact() now receives a Configuration object to pass the dependencies to the IDE. See artifactApi sample.New &lintVital& task, run automatically as part of assembling release variants, which checks only fatal-severity issuesReplace Java parser in lint with ECJ; must faster and fixes bug where lint could hang on certain source constructsLint HTML report now writes links to source files and images as URLs relative to the report location安装
如果你已经在运行 Android Studio,重启就可以了,或者是通过 帮助—&检查更新(OS X,在 Android Studio 菜单可以看到)。这种安装只会安装一部分分支,不会进行整个 IDE 镜像的安装。如果你想下载个完整安装版本,可以前往
Android Studio 的详细介绍:
Android Studio 的下载地址:
想通过手机客户端(支持 Android、iPhone 和 Windows Phone)访问开源中国:
旧一篇: 1年前
新一篇: 1年前
相关讨论话题
你也许会喜欢
比chrome更新还快
3楼:牛仔豆
好像比之前的流畅多了
4楼:打杂程序猿
这次居然有人比我还早知道!
5楼:rockjava
这货肿么个情况?天天发布吗?
6楼:阿信sxq
话说不是才发布0.4.2么
7楼:阿信sxq
都这么久了,1.0都还没有提上日程?,难道要出到0.?
8楼:abbish
9楼:wangxigui
用过1.0版本的,用不惯,还是换到了eclipse
10楼:kevinleng
现在android develop网站都打不开么, 一直提示403错误
11楼:理工小强
引用来自“rockjava”的评论这货肿么个情况?天天发布吗?更新的太快了点吧 话说这changelog也多了点吧 。。。
12楼:滔哥
这货更新真快
13楼:loyal
bug很多....相当多....
14楼:qiukeren 来自
这么快。。
15楼:jbas
很好,很强大,一直在用。
16楼:卖茄子
快出来看上帝~~~
17楼:guobosheng
之前更新了,还没打开过。。。这么快又来了!
18楼:FoxHu 来自
估计在2014 I/O开发者大会时退出1.0版
19楼:FoxHu
估计在2014 I/O开发者大会时推出1.0版
20楼:Broly
好难用啊这货
与内容无关的评论将被删除,严重者禁用帐号
本周热点资讯
本站最新资讯Android Studio 0.4.3 发布
Android Studio 0.4.3 发布,此版本更新内容如下:支持最新的 Android Gradle 插件 0.8 版本,不要求强制更新,用户可以继续使用 0.7 版本更新到最新的 IntelliJ 13 EAP build, #133.609 ()
支持 Gradle IDE
Updating from one version of the Gradle plugin t rather than just opening a search window showing .gradle files referencing the plugin, the upgrade quickfix now performs the edits to the plugin dependency and the gradle wrapper properties file directly and in one shot
We now automatically sync with Gradle's model after a build if we detect that the model is stale
Fixed a bug around library syncing (where library dependency classes and resources could suddenly not be found by the IDE)
New lint check which looks for cycles in style definitions, cycles in layout &include& definitions, cycles in resource aliases and cycles in color and drawable definitions.
New lint check for duplicate item definitions inside styles
New lint check for padding symmetry in right-to-left contexts
New lint check for a resource definition pattern which can cause some versions of aapt to crash
The layout editor property sheet now handles setting properties in custom namespaces
Improved threading behavior of layout rendering code (which should make editing in the XML editor with the layout render preview window more responsive)
In addition to creating new locales from the Locale menu you can now open up and edit existing translations
Fixed bug where the layout editor could show stale resource strings
导入 Eclipse
You can now import Eclipse-style projects even if they don't have .classpath and .project files as long as they use the same directory structure
More graceful handling of imports if there is a problem such as a missing dependency
其他 bug 修复
Android Gradle 插件 0.8 版本更新内容如下:Supports Gradle 1.10, requires Build-Tools 19.0.0+Fixed issue 64302: Add renderscript support mode jar to the dependencies in the IDE model.Fixed issue 64094: buildConfigField can now replace previous values inside the same type/flavors.Add support for NDK prebuilts in library projects.Parallelize pre-dexing to speed up clean builds.Incremental dexing re-enabled (though it'll be automatically disabled in some builds for some cases that dx doesn't support yet.)Added 'provided' dependency scope for compile only (not packaged) dependencies.&Additional scope per buildtype and flavors are also available (debugProvided, myFlavorProvided,etc...)Variant API improvements:getPreBuild() returns the prebuild task for the variantgetSourceSets() returns the sorted sourcesets for the task, from lower to higher prioritycreateZipAlignTask(String taskName, File inputFile, File outputFile).This creates and return a new zipalign task. Useful if you have a custom plugin providing custom signing of APKs.&This also makes the assemble task depend on the new zipalign task, and wires variant.getOutputFile() to return the result of the zipalign task.project.android.registerJavaArtifact() now receives a Configuration object to pass the dependencies to the IDE. See artifactApi sample.New &lintVital& task, run automatically as part of assembling release variants, which checks only fatal-severity issuesReplace Java parser in lint with ECJ; must faster and fixes bug where lint could hang on certain source constructsLint HTML report now writes links to source files and images as URLs relative to the report location安装
如果你已经在运行 Android Studio,重启就可以了,或者是通过 帮助—&检查更新(OS X,在 Android Studio 菜单可以看到)。这种安装只会安装一部分分支,不会进行整个 IDE 镜像的安装。如果你想下载个完整安装版本,可以前往
Android Studio 的详细介绍:
Android Studio 的下载地址:
想通过手机客户端(支持 Android、iPhone 和 Windows Phone)访问开源中国:
旧一篇: 1年前
新一篇: 1年前
相关讨论话题
你也许会喜欢
比chrome更新还快
3楼:牛仔豆
好像比之前的流畅多了
4楼:打杂程序猿
这次居然有人比我还早知道!
5楼:rockjava
这货肿么个情况?天天发布吗?
6楼:阿信sxq
话说不是才发布0.4.2么
7楼:阿信sxq
都这么久了,1.0都还没有提上日程?,难道要出到0.?
8楼:abbish
9楼:wangxigui
用过1.0版本的,用不惯,还是换到了eclipse
10楼:kevinleng
现在android develop网站都打不开么, 一直提示403错误
11楼:理工小强
引用来自“rockjava”的评论这货肿么个情况?天天发布吗?更新的太快了点吧 话说这changelog也多了点吧 。。。
12楼:滔哥
这货更新真快
13楼:loyal
bug很多....相当多....
14楼:qiukeren 来自
这么快。。
15楼:jbas
很好,很强大,一直在用。
16楼:卖茄子
快出来看上帝~~~
17楼:guobosheng
之前更新了,还没打开过。。。这么快又来了!
18楼:FoxHu 来自
估计在2014 I/O开发者大会时退出1.0版
19楼:FoxHu
估计在2014 I/O开发者大会时推出1.0版
20楼:Broly
好难用啊这货
与内容无关的评论将被删除,严重者禁用帐号
本周热点资讯
本站最新资讯BuildConfig 无法得到正确创建 (Gradle Android)
我想转换我们向 gradle 生成的 Android 应用程序。我有项目,这是图书馆建设成功。我现在正在努力创建单独的 apks 为我们各种环境 (开发/测试/产品有不同的 url 供他们消费的 rest 风格的服务)。
在找来找去,我觉得这样做的最佳方式是以使不同 BuildConfig 为每个环境。这是我试过:
import java.util.regex.Pattern
buildscript {
repositories {
mavenCentral()
dependencies {
classpath 'com.android.tools.build:gradle:+'
apply plugin: 'android'
task('increaseVersionCode') && {
def manifestFile = file("AndroidManifest.xml")
def pattern = pile("versionCode=\"(\\d+)\"")
def manifestText = manifestFile.getText()
def matcher = pattern.matcher(manifestText)
matcher.find()
def versionCode = Integer.parseInt(matcher.group(1))
def manifestContent = matcher.replaceAll("versionCode=\"" + ++versionCode + "\"")
manifestFile.write(manifestContent)
tasks.whenTaskAdded { task -&
if (task.name == 'generateReleaseBuildConfig') {
task.dependsOn 'increaseVersionCode'
dependencies {
compile 'com.android.support:support-v4:19.0.0'
compile files('libs/commons-io-2.4.jar',
'libs/google-play-services.jar',
'libs/gson-2.2.4.jar',
'libs/universal-image-loader-1.8.6.jar',
'libs/wakeful-1.0.1.jar')
compile project(':pulltorefresh_lib')
compile project(':edgeeffect_lib')
compile project(':viewpagerindicator_lib')
buildToolsVersion "18.1.1"
compileSdkVersion "Google Inc.:Google APIs:18"
defaultConfig {
minSdkVersion 14
targetSdkVersion 18
buildTypes {
packageNameSuffix ".debug"
dev.initWith(buildTypes.debug)
buildConfigField "String", "URL_SEARCH", "\"https://dev-\";"
buildConfigField "String", "URL_CONNECT", "\"https://dev-\";"
buildConfigField "String", "URL_SVC_NEWSLIST", "\"https://dev-/newslist\";"
buildConfigField "String", "URL_SVC_NEWSDETAIL", "\"https://dev-/newsdetail\";"
buildConfigField "String", "URL_SVC_REGISTERENDPOINTS", "\"https://dev-/registerendpoints\";"
prod.initWith(buildTypes.release)
buildConfigField "String", "URL_SEARCH", "\"\";"
buildConfigField "String", "URL_CONNECT", "\"\";"
buildConfigField "String", "URL_SVC_NEWSLIST", "\"/newslist\";"
buildConfigField "String", "URL_SVC_NEWSDETAIL", "\"/newsdetail\";"
buildConfigField "String", "URL_SVC_REGISTERENDPOINTS", "\"https://mobilenews.pdc-np-/registerendpoints\";"
sourceSets {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
问题是我的 BuildConfig.java 似乎不能注入的静态变量,因此得到了一个错误类似于:
/Users/path/to/project/MainActivity.java:348: error: cannot find symbol
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(BuildConfig.URL_SEARCH)));
variable URL_SEARCH
location: class BuildConfig
/Users/path/to/project/MainActivity.java:359: error: cannot find symbol
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(BuildConfig.URL_CONNECT)));
variable URL_CONNECT
location: class BuildConfig
/Users/path/to/project/MainActivity.java:600: error: cannot find symbol
HttpPost httpPost = new HttpPost(BuildConfig.URL_SVC_REGISTERENDPOINTS);
variable URL_SVC_REGISTERENDPOINTS
location: class BuildConfig
/Users/path/to/project/service/AlarmNotificationService.java:145: error: cannot find symbol
String requestUrl = BuildConfig.URL_SVC_NEWSLIST + "?"
variable URL_SVC_NEWSLIST
location: class BuildConfig
/Users/path/to/project/service/NewsService.java:240: error: cannot find symbol
String requestUrl = BuildConfig.URL_SVC_NEWSLIST + "?"
variable URL_SVC_NEWSLIST
location: class BuildConfig
/Users/path/to/project/service/NewsService.java:530: error: cannot find symbol
HttpPost httpPost = new HttpPost(BuildConfig.URL_SVC_NEWSDETAIL);
variable URL_SVC_NEWSDETAIL
location: class BuildConfig
我的 build/source/buildConfig/debug/com/lmig/ets/mobile/libertynewsreader/BuildConfig.java 文件包含:
* Automatically generated file. DO NOT MODIFY
package com.lmig.ets.mobile.
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String PACKAGE_NAME = "com.lmig.ets.mobile.libertynewsreader.debug";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 5;
我究竟做错了?
解决方法 1:
请请务必您正在构建"dev"督促"变形。没有 BuildConfig 定义的默认"调试"和"释放"的变形。在 Android Studio 中,您可以选择左下角中的当前变量:
为了简化您的 build.gradle 文件,您可以定义:
buildTypes {
packageNameSuffix ".debug"
buildConfigField "String", "URL_SEARCH", "\"https://dev-\""
buildConfigField "String", "URL_SEARCH", "\"\""
然后只使用默认的"调试"和"释放"变形。
最后,删除分号 (标志:;) 从 buildConfigField 参数的值。Building Multiple Editions of an Android App with Gradle | robusta tech talk
A mobile application we’ve worked on recently had a special requirement. The app would be released multiple times, under different name, branding and minor feature differences. This can very easily turn into a mess quickly, if all the apps are not maintained in a single code base.
The way you would usually approach this is by building the whole app as an Android library project, and you would then build an Android application project for each edition. That can work, but you would need a lot of work to get the library/app separation to work, because your library is actually an application, and that could cause some confusions.
However, we were already migrating our Android development to Android Studio, and the new build system (Gradle) has a specific solution to this problem: meet Flavors.
Flavors are basically different editions of the application, that are built from a single code base. The library approach is no longer necessary, and the whole process is just streamlined. Through this post, we’re going to configure a build of an application with two flavors, take a look over the process quickly and see how to differentiate the two flavors with different graphics or features.
Note: Android Studio & Gradle Android plugin are still in preview mode and different versions aren’t necessarily compatible, so please take note that the following instructions apply to Gradle plugin 0.9.2 and Android Studio 5.5. If you use different versions than these, they may, or may not work.
Our base application
We’re going to use Android Studio for this app, it would still be relatively easy to apply this without Android Studio though. First, let’s create a new project MultiFlavorSampleApp, with the default empty Activity.
This will get you started with a default app/build.gradle, it should be similar to this:
apply plugin: 'android'
compileSdkVersion 19
buildToolsVersion &19.0.3&
defaultConfig {
minSdkVersion 8
targetSdkVersion 19
versionCode 1
versionName &1.0&
buildTypes {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
dependencies {
compile 'com.android.support:appcompat-v7:19.+'
compile fileTree(dir: 'libs', include: ['*.jar'])
Adding a Flavor
Now we want to add flavor that builds a different edition of the application. Since we don’t have any flavors, we’ll have to define 2 flavors, one for the default edition, and another for the flavor we want to add. Let’s call the default edition “Vanilla”, and the other flavor “Strawberry”.
We’ll need to add a productFlavors section inside the android section.
productFlavors {
strawberry {
After modifying your build.gradle, sync your Android Studio with the new changes.
Now if you open the “Build Variants” view, you can easily switch between build variants from within the IDE. A build variant is basically a combination of flavors and build types ( by default debug and release ). So, with 2 flavors, you get 4 build variants by default.
Now, first thing you would want to do is provide different package names per flavor, so you can distribute them separately.
Update: Check
regarding packageName.
productFlavors {
packageName &com.example.multiflavorapp&
strawberry {
packageName &com.example.multiflavorapp.strawberry&
From the build variants window you can now just change the variant and you’re good to go. So far though, we’re just building the same app with a different package name, now let’s start the fun.
Providing Alternate Resources
Now we’re going to start customizing the application per flavor, starting with resources. As we’ve created a new project in Android Studio, I’ll assume you now have the default project structure:
|--layout/
|--activity_main.xml
|--AndroidManifest.xml
In this structure, main is your default source directory (i.e. the “unflavored” source). So, where you would put your flavor customizations? in a flavored directory, that is. Let’s say we want to provide a different layout file for activity_main.xml in strawberry flavor. If you follow the same default structure, you won’t need to modify your Gradle script, you just need to provide an alternative source in the strawberry source directory, so basically you will have this structure:
|--strawberry/
|--layout/
|--activity_main.xml
|--layout/
|--activity_main.xml
|--AndroidManifest.xml
Note: You may face minor inconveniences creating files (code files or resources) under a flavor that’s not currently selected from Android’s Build Variants view. Selecting the right flavor before working on its source directory would be more convenient, but not necessary
Now if you build strawberry, you’re going to get the strawberry/res/layout/activity_main.xml layout. If you build vanilla, you’ll get the main/res/layout/activity_main.xml because it wasn’t overwritten.
Note: Be ware of the ids you’re using in the layouts. If you add new ids in strawberry‘s activity_main.xml that are not in main‘s activity_main.xml, these ids will not be visible when building vanilla, resulting build failure if you use these ids in code.
You should note that resources aren’t merged on file-level, but actually on resource-level. For string resources for example, if you have these two files:
src/main/res/values/strings.xml
&?xml version=&1.0& encoding=&utf-8&?&
&resources&
&string name=&app_name&&Vanilla App&/string&
&string name=&hello_world&&Hello world!&/string&
&/resources&
src/strawberry/res/values/strings.xml
&?xml version=&1.0& encoding=&utf-8&?&
&resources&
&string name=&app_name&&Strawberry App&/string&
&/resources&
when you build the strawberry flavor, you’ll get these resources (you won’t see this inside the IDE, your files will stay the same, but this just represents how the final resources would be.):
&?xml version=&1.0& encoding=&utf-8&?&
&resources&
&string name=&app_name&&Strawberry App&/string&
&string name=&hello_world&&Hello world!&/string&
&/resources&
If you build vanilla, you’ll get main‘s strings.xml as is.
Although this works, I’d recommend splitting customizable strings in a different file (e.g. flavor_strings.xml), to separate actual application strings, from strings that should be customized by each flavor. This way it’s more maintainable, and when adding a flavor, you would know exactly what to customize, without touching the application’s general strings and possibly their localized versions.
Note: When providing alternate resources in a flavor, make sure you provide alternates for all qualifiers that exist in main for the same resource.
For example, if you have logo.png in main provided in drawable-hdpi and drawable-xhdpi, and you only provide the hdpi version in strawberry flavor, the logo.png from main will be loaded on xhdpi devices.
Providing Alternate Code files
Code files are treated differently from resources. They don’t override each other, they’re just combined. So if you have com.example.MainActivity in your main source directory, and provide a different implementation of the same class in a different flavor, the build system will complain that you have duplicate class definitions when building that flavor.
However, this is still easily achievable. If you want to provide different implementations for a class in flavors, you have to omit them from the main source.
Let’s say you want to provide a different class called com.example.Flavor. First you would want to make sure you don’t have the class itself in main source. However, it’s likely that you want a default implementation. So, now we’re going to add it to all flavors separately, but not in main, this way, whenever you build a flavor, it will only see one com.example.Flavor class definition.
|--vanilla/
|--com/example/
|--Flavor.java
|--strawberry/
|--com/example/
|--Flavor.java
|--AndroidManifest.xml
Note: If you’re going to use both class versions from the main code files, make sure you maintain the same package, same class name, and same publicly used methods. If one version doesn’t have a method of another, and you attempt to use it, it will result a build error.
This works best if you structure the customizable classes correctly with interfaces or abstract classes. You may be interested to look at
if you want the code be more flexible.
Controlling Code Path per Flavor
If your flavors have different features enabled, you would want to control the code execution per flavor as well. Basically you want to say
if(IS_VANILLA) {
doSomething();
} else if(IS_STRAWBERRY) {
doSomethingElse();
You have many options to achieve this.
You can depend on BuildConfig.FLAVOR value, to check which flavor are we building. This method however can be hard to manage if you’re going to add more flavors in the future.
Put your flags in an XML resource file. This will force you to use a Context to get these values in runtime though.
Add a BuildConfig boolean flag, something like (BuildConfig.HAS_PAYMENT, BuildConfig.IS_PRO_VERSION), this could be done using buildConfigField:
productFlavors {
buildConfigField &boolean&, &HAS_PAYMENT&, &true&
strawberry {
buildConfigField &boolean&, &HAS_PAYMENT&, &false&
You can’t add it manually of course as BuildConfig is automatically generated. We’d recommend using this method if applicable.
Note: So far, I’ve been using the default project structure. You can always customize the locations of specific folders (for java files, resource directories…etc), but using the default structure will keep your build script short, and following the convention will help you find stuff easier instead of tracing around where files are coming from.
Signing Configuration
We’re almost done for publishing the applications. We need to add the signing configuration to build signed APKs. I will assume you have already generated the keystore files. You will need to add the signingConfigs section, anywhere before the productFlavors section:
signingConfigs {
storeFile file(&../../app.keystore&) //Path to the keystore file
keyAlias &app&
storePassword &&
keyPassword &&
You may prefer to sign each flavor with different certificate. To do that, you would just need to write a signingConfig section per flavor and assign it to each flavor:
signingConfigs {
storeFile file(&../../app.keystore&) //Path to the keystore file
keyAlias &vanilla&
storePassword &&
keyPassword &&
strawberry {
storeFile file(&../../app.keystore&) //Path to the keystore file
keyAlias &strawberry&
storePassword &&
keyPassword &&
productFlavors {
packageName &com.example.multiflavorapp&
strawberry {
packageName &com.example.multiflavorapp.strawberry&
buildTypes {
release { //Only use the release key on a release buildType
productFlavors.vanilla.signingConfig signingConfigs.vanilla
productFlavors.strawberry.signingConfig signingConfigs.strawberry
Note: For simplicity, I’ve put the keystore and alias password in the build file directly. Most probably, you want to move these out of the file so you can check it into version control, but that’s a bit beyond our scope here.
That’s all for this post. There’s a lot more you can do with flavors, and more configuration, like flavor-specific dependencies that were not covered here. You should not overuse flavors though, unless these flavors should really belong to the same code base. If you find yourself doing major work inside a specific flavor, you should probably reconsider using flavors at all. I think it’s better to think of a flavor as a thin layer, not an app in itself
References
Android is a trademark of Google Inc. The Android robot is reproduced or modified from work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License.
Senior Android Developer. Boilerplate code hater.

我要回帖

更多关于 android gradle 的文章

 

随机推荐