Gradle —— 使用 Gradle 打包多个变体(variant)

转载请标明原文地址:http://www.jianshu.com/p/843055bf6edd
刚开始使用 CSDN 博客,故将原来写在简书的文章迁移到 CSDN 的博客,并重新进行排版。

Gradle

背景:刚刚接手的项目中包含 3 个客户端 App(两个 Eclipse 工程、一个 AS 工程),同时这个项目根据不同用户的制定还有两个衍生版本。原来的开发人员将项目复制后修改,在我接手时一共存在着9个工程文件。

当我看到这个项目的时候近乎崩溃,因为这意味着每修改一个端的内容还要记着同步到其他的两个端中。查看后发现,衍生版本中大量的文件是重复的,只是部分比如资源文件、后台接口地址等是不同的。我便开始思考,如何通过一个 Android Studi o工程同时实现修改这三个版本。

于是便想到了曾看过 stormzhang 写过的 ANDROID STUDIO系列教程六–GRADLE多渠道打包,这篇文章中简单描述了如何使用 Gradle 进行多渠道打包(使用占位符替换 AndroidManifest 文件中友盟统计的 UMENG_CHANNEL 的值)。

这给了我一定的思路,通过查阅资料,确定了可以使用 Gradle 打包出不同变体(不同 applicationId、不同资源文件、不同 APP 名称与图标、不同 Java 文件)。

长篇讲解可以查看文章末尾的参考阅读,本文只介绍如何实现。


1 配置不同变体的属性(签名、applicationId)

由于项目中每个客户端都相当于存在三个版本,使用不同的签名文件,因此需要首先实现的就是对不同的变体配置不同的签名!

配置签名文件

如上图所示,选择 app module,选择 Signing 选项卡,首先配置好了这三个变体版本的签名文件。

配置变体 Flavors

扫描二维码关注公众号,回复: 889578 查看本文章

在 Flavors 选项卡中,新建我们的变体(variant),并对变体进行配置!所有的 Flavo r都会复写 defaultConfig 中的属性,所以可以看到我并没有填写其中的一些属性。在这里还可以对不同的变体设置不同的 applicationId(重要!这与极光推送等第三方 SDK 有关)。

创建完毕后同步项目,会发现 app moudle 下的 build.gradle 文件内容也发生了变化,如下图所示:
Paste_Image.png

如果你可以熟练的使用 Gradle 也可以选择不使用 AS 提供的 UI 界面,直接编写 gradle 文件。

2 新建不同变体的 sourceSet

在修改完变体的配置文件后,我们还需要再项目的 src 文件夹下新建以我们的 Flavor 名称命名的文件夹,并在这些文件夹下新建如 main 中相同的目录结构。
目录结构

我们正常编写项目都是写在 main 这个 sourceSe t下的,但是如果我们的项目的变体有不同的资源文件、Java 文件时,我们就需要使用不同的 sourceSet 来区别开。

需要注意的是,如果是资源文件,Flavor 下的资源文件会与 main 中的合并,如果存在重复,则 Flavor 中优先级高于 main 中。我们可以将不同变体中共用的资源存放在 main中,只将不同的内容存放在各自 Flavor 的 sourceSet 中。

如果不同变体有内容不同的Java文件则要注意,需要将这个 Java 文件放置到每个 Flavor 的 sourceSet 文件夹下,main 中不可以也存在这个 Java 文件,如果 main 中也存在此文件,编译时会提示文件重复。比如说有两个变体,有着不同的 MainActivity.java,那么 main 中就不能有这个文件了。需要把这个 Java 文件放到各个 Flavor 的 sourceSet 下,同时这个 Java 文件在 sourceSet 中要按照 main 中的包结构保存。

3 AndroidManifest 占位符

由于不同的项目有不同的名称、图标,这一点我们可以通过类似上一步的方法,在不同的 sourceSe t中配置 string.xml 中的 app_name 属性,与 drawable 文件夹中的 ic_launcher。但是这样有些麻烦,当我们的变体版本多了得手就需要不断的重复这一动作,所以我使用的是在 AndroidManifest 文件中使用占位符然后在 Flavor 中直接配置的方法。这样做的好处是,如果以后图标变更只需要到 main 中找到该文件然后替换即可,而不用去一个个找 sourceSet。

首先将所有图标文件放到 main 中,然后在 AndroidManifest 中使用¥{NAME}格式的占位符,最后在flavor中使用manifestPlaceholders =[NAME1:VALUE1,NAME2:VALUE2]替换占位符中的内容。

AndroidManifest占位符

在项目中,每个衍生版本都有自己的极光推送 APPKEY 属性,这也可以是用占位符这一方法来处理,最终的 Flavors 如下图所示:

gradle文件

4 调试不同版本

现在我们拥有了三个不同的变体,但是我们调试的时候如何选择对应的程序来调试呢?

方式一:
方式一

方式二:
方式二

在选择好要调试的变体后,会发现对应的 sourceSet 文件夹变成了我们工程文件夹的央视:

选择需要调试的变体

可以看到我们一共有 6 个可选变体,这是怎么回事呢?我们明明只设置了 3 个 flavor。

这时就需要介绍 buildTypes 了,再次回到项目配置页面如下图所示:

buildTypes

可以看到有两个 build type,这其中可以配置构建的一些选项,这里就不做过多介绍了。

我们的总变体数量等于(build type数量)*(flavor数量),这就是为什么一共有六个可选的variant。

最后献上一个 release 的 buildType 配置

release {
    minifyEnabled true
    shrinkResources true       //移除无用资源
    debuggable false
    zipAlignEnabled true        //Zipalign优化
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    signingConfig signingConfigs.uerbT
    // 自定义输出配置
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def outputFile = output.outputFile
            if (outputFile != null && outputFile.name.endsWith('.apk')) {
                // 输出apk名称为UerbT_v1.0_2016-12-01_uerbt.apk
                def fileName = "UerbT_v${variant.versionName}_${releaseTime()}_${variant.flavorName}.apk"
                output.outputFile = new File(outputFile.parent, fileName)
            }
        }
        //过滤掉unaligned的包
        variant.assemble.doLast {
            variant.outputs.each { output ->
                println "-----------------------------------------"
                println "aligned " + output.outputFile
                println "unaligned " + output.packageApplication.outputFile
                File unaligned = output.packageApplication.outputFile;
                File aligned = output.outputFile
                if (!unaligned.getName().equalsIgnoreCase(aligned.getName())) {
                    println "deleting " + unaligned.getName()
                    unaligned.delete()
                }
            }
        }
    }
}

releaseTime() 函数如下:

def releaseTime() {
    return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
}

参考阅读:

重要-Gradle for Android 第四篇( 构建变体 )
重要 - 使用gradle构建不同特性的app
gradle配置详解
知乎问答-如何使用gradle构建不同的app
android studio gradle 多版本多apk打包
使用Gradle自动化构建多类型apk包
外包采用Gradle生成多套app打包
ANDROID STUDIO系列教程六–GRADLE多渠道打包
Android Studio中Gradle使用详解

猜你喜欢

转载自blog.csdn.net/u011133887/article/details/64919136