对于多种类型的apk包构建,通常有以下需求:
- 各版本有不同的代码、资源
- 上述代码中各版本有不同的依赖
- 各版本有不同的Manifest中元素需求
- 各版本有不同的proGuard
Android Studio中使用Gradle编译多种apk包需要靠productFlavors或者buildTypes实现,如果有两种product flavor和两种build type,则他们可以生成2*2=4种不同类型的apk包。下文主要使用productFlavors自定义apk内容,而buildTypes使用默认配置用于处理debug版本和release版本。
以下依次来看这4点怎样实现
一、不同的代码和资源要实现build时使用不同的代码和资源:
- 在build文件中定义productFlavors
- 为每个Flavor创建对应的文件夹
- 将每个Flavor特有的文件放入文件夹
1.在build文件中定义productFlavors
...android { ... defaultConfig { ... } signingConfigs { ... } buildTypes { ... } productFlavors { demo { applicationId "com.buildsystemexample.app.demo" versionName "1.0-demo" } full { applicationId "com.buildsystemexample.app.full" versionName "1.0-full" } }}...
其中defaultConfig{}中为默认值,productFlavors{}会复写所有可以复写的值。
2.为每个Flavor创建对应的文件夹
在上面两个Flavor的基础上,假设你想在每个Flavor使用不同的SecondActivity文件,按照下面的步骤:
- 展开app目录
- 右击src目录,选择New>Directory
- 输入Flavor的名字,也就是demo,新建
- 在demo中创建以下文件夹 app/src/demo/java app/src/demo/res app/src/demo/res/layout app/src/demo/res/values 如下图:
PS:上述过程就是将默认的main下的目录结构复制过来,想添加其他资源也是同样的操作
3. 将每个Flavor特有的文件放入文件夹
向上一步新建的目录中,先在java目录下建立对应的package,向其中放入SecondActivity.java和其layout文件,并在res目录下添加本Flavor的AndroidManifest.xml文件。Manifest的merge规则见下文。
另外一种方法是右击app目录,选择添加Activity,在引导界面中最后一项Target Source Set选择你想添加到的Flavor,Android Studio就会自动为你生成对应的AndroidManifest,不过需要稍加修改。
在添加demo所需文件后,为了添加full所需文件和包,需要在Android Studio中将build variants切换为fullDebug,否则Android Studio不会将full下的java目录识别为源文件目录,导致不能添加package。
对于demo和full中对应的相同的文件,注意要保证包名的相同,否则main中代码对于不同部分的引用,会因为有不同包名而失败。
二、不同的依赖在build.gradle中,使用Flavor名+Compile来规定特定Flavor所需依赖:
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:22.2.0' demoCompile 'com.android.support:design:22.2.0' fullCompile 'com.jakewharton:butterknife:6.1.0'}
三、不同的Manifest需求Manifest可以通过Merge的方式合并多个Manifest源。通常来说,有三种类型manifest文件需要被merge到最终的结果apk,下面是按照优先权排序:
- productFlavors和buildTypes中所指定的manifest文件
- 应用主manifest文件
- 库manifest文件
简单来说,manifest的merge会将每个元素及其子元素的节点和属性进行合并。
例如:
<activity android:name=”com.foo.bar.ActivityOne” android:theme=”@theme1”/>
和
<activity android:name=”com.foo.bar.ActivityOne” android:screenOrientation=”landscape/>
合并会成为
<activity android:name=”com.foo.bar.ActivityOne” android:theme=”@theme1” android:screenOrientation=”landscape/>
不过
<activity android:name=”com.foo.bar.ActivityOne” android:theme=”@theme1”/>
和
<activity android:name=”com.foo.bar.ActivityOne” android:theme=”@theme2” android:screenOrientation=”landscape/>
合并会产生一个冲突,因为都有theme,而theme的属性不同。
要了解manifest合并的更高级应用,查看Manifest Merger
四、不同ProGuard需求android { buildTypes { release { minifyEnabled true proguardFile getDefaultProguardFile('proguard-android.txt') } } productFlavors { flavor1 { } flavor2 { proguardFile 'some-other-rules.txt' } }}
Android Studio将使用所有的定义在相应buildTypes和相应productFlavors中的规则文件。
有两个默认的规则文件:
- proguard-android.txt
- proguard-android-optimize.txt 存放在SDK中。可以使用getDefaultProguardFile()来获得文件的完整路径,他们除了优化的开启是否不同之外都相同。
参考资料:
Manifest Merger
Gradle Plugin User Guide
New Build System
Using Build Flavors - Structuring source folders and build.gradle correctly
Build System Concepts
找了半天也不晓得原因。。。
这样的确方便了开发,不过好像好像apk的大小也会增加