如何使用Gradle构建不同版本的app?

某软件,一套源代码中绝大多数代码是相同的,仅仅是某些类不同; 或者说,在某版本的app上开发新的beta版本。 笨笨的方法是有几个版本使用拷贝几个源代码的包进行开发。 初略知道gradle好像可以进行这方面的管理,如何在配置文件中根据版本使用不同的源代码进行编译呢?
关注者
74
被浏览
7919

见我的blog: 使用Gradle自动化构建多类型apk包


对于多种类型的apk包构建,通常有以下需求:

  • 各版本有不同的代码、资源
  • 上述代码中各版本有不同的依赖
  • 各版本有不同的Manifest中元素需求
  • 各版本有不同的proGuard

Android Studio中使用Gradle编译多种apk包需要靠productFlavors或者buildTypes实现,如果有两种product flavor和两种build type,则他们可以生成2*2=4种不同类型的apk包。下文主要使用productFlavors自定义apk内容,而buildTypes使用默认配置用于处理debug版本和release版本。

以下依次来看这4点怎样实现



一、不同的代码和资源

要实现build时使用不同的代码和资源:

  1. 在build文件中定义productFlavors
  2. 为每个Flavor创建对应的文件夹
  3. 将每个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文件,按照下面的步骤:

  1. 展开app目录
  2. 右击src目录,选择New>Directory
  3. 输入Flavor的名字,也就是demo,新建
  4. 在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,下面是按照优先权排序:

  1. productFlavors和buildTypes中所指定的manifest文件
  2. 应用主manifest文件
  3. 库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