[06]——使用gradle打包多个变体(variant)

转载请标明原文地址:http://www.jianshu.com/p/843055bf6edd

重要更新

  1. 现在新建变体还需要在 defaultConfig 下加入 flavorDimensions "versionCode"
  2. 我写了一个脚本可以快速的创建变体的sourceSet,项目地址:junerver/flavor_cli

使用方法:将该脚本复制到项目根目录下(与app目录同级),然后运行指令:python3 flavor_variant.py,后续按照提示输入即可,因为是供自己开发快速使用的,所有必然有bug与一些严格匹配的要求,欢迎提PR!


Gradle

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

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

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

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

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


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

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

配置签名文件

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

配置变体Flavors

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

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


Paste_Image.png

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

2 新建不同变体的sourceSet

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


目录结构

我们正常编写项目都是写在main这个sourceSet下的,但是如果我们的项目的变体有不同的资源文件、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占位符

由于不同的项目有不同的名称、图标,这一点我们可以通过类似上一步的方法,在不同的sourceSet中配置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使用详解

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容