前言
其實(shí)本文大部分資料都來自github和google,如何有興趣的讀者,可以直接閱讀官方文檔~
什么是Gradle
Android 構(gòu)建系統(tǒng)編譯應(yīng)用資源和源代碼,然后將它們打包成可供您測試、部署、簽署和分發(fā)的 APK。 Android Studio 使用?Gradle?這一高級(jí)構(gòu)建工具包來自動(dòng)執(zhí)行和管理構(gòu)建流程,同時(shí)也允許您定義靈活的自定義構(gòu)建配置。
每個(gè)構(gòu)建配置均可自行定義一組代碼和資源,同時(shí)對(duì)所有應(yīng)用版本共有的部分加以重復(fù)利用。 Android Plugin for Gradle 與這個(gè)構(gòu)建工具包協(xié)作,共同提供專用于構(gòu)建和測試 Android 應(yīng)用的流程和可配置設(shè)置。
Gradle 和 Android 插件獨(dú)立于 Android Studio 運(yùn)行。 這意味著,您可以在 Android Studio 內(nèi)、計(jì)算機(jī)上的命令行或未安裝 Android Studio 的計(jì)算機(jī)(例如持續(xù)性集成服務(wù)器)上構(gòu)建 Android 應(yīng)用。
如果您不使用 Android Studio,可以學(xué)習(xí)如何從命令行構(gòu)建和運(yùn)行您的應(yīng)用。 無論您是從命令行、在遠(yuǎn)程計(jì)算機(jī)上還是使用 Android Studio 構(gòu)建項(xiàng)目,構(gòu)建的輸出都相同。
注:由于 Gradle 和 Android 插件獨(dú)立于 Android Studio 運(yùn)行,您需要單獨(dú)更新構(gòu)建工具。
請(qǐng)閱讀版本說明,了解如何更新 Gradle 和 Android 插件。Android 構(gòu)建系統(tǒng)非常靈活,讓您能夠在不修改應(yīng)用核心源文件的情況下執(zhí)行自定義構(gòu)建配置。
什么是VasDolly?(github 傳送門)
VasDolly是騰訊開源的一個(gè)高效的打包工具。騰訊作為國內(nèi)的技術(shù)大廠,在技術(shù)層面上還是很牛逼and可靠的。而且開發(fā)團(tuán)隊(duì)在github上也是相對(duì)的活躍,對(duì)issue也解決也是很積極的。
VasDolly是一種快速多渠道打包工具,同時(shí)支持基于V1簽名和V2簽名進(jìn)行多渠道打包。插件本身會(huì)自動(dòng)檢測Apk使用的簽名類別,并選擇合適的多渠道打包方式,對(duì)使用者來說完全透明。
VasDolly 是騰訊推出的新一代打包工具,相對(duì)于傳統(tǒng)的打包工具,即AS自帶的打包工具,速度有了非一般的提升。
Gradle Plugin本身提供了多渠道的打包策略: 首先,在AndroidManifest.xml中添加渠道信息占位符:
<meta-data android:name="InstallChannel" android:value="${InstallChannel}" />
然后,通過Gradle Plugin提供的productFlavors標(biāo)簽,添加渠道信息:
productFlavors{
"YingYongBao"{ manifestPlaceholders = [InstallChannel : "YingYongBao"] }
"360"{ manifestPlaceholders = [InstallChannel : "360"] }
}
這樣,Gradle編譯生成多渠道包時(shí),會(huì)用不同的渠道信息替換AndroidManifest.xml中的占位符。我們?cè)诖a中,也就可以直接讀取AndroidManifest.xml中的渠道信息了。
但是,這種方式存在一些缺點(diǎn):
每生成一個(gè)渠道包,都要重新執(zhí)行一遍構(gòu)建流程,效率太低,只適用于渠道較少的場景。
Gradle會(huì)為每個(gè)渠道包生成一個(gè)不同的BuildConfig.java類,記錄渠道信息,導(dǎo)致每個(gè)渠道包的DEX的CRC值都不同。一般情況下,這是沒有影響的。但是如果你使用了微信的Tinker熱補(bǔ)丁方案,那么就需要為不同的渠道包打不同的補(bǔ)丁,這完全是不可以接受的。(因?yàn)門inker是通過對(duì)比基礎(chǔ)包APK和新包APK生成差分補(bǔ)丁,然后再把補(bǔ)丁和基礎(chǔ)包APK一起合成新包APK。這就要求用于生成差分補(bǔ)丁的基礎(chǔ)包DEX和用于合成新包的基礎(chǔ)包DEX是完全一致的,即:每一個(gè)基礎(chǔ)渠道包的DEX文件是完全一致的,不然就會(huì)合成失敗)
那有沒有一種方案:可以在添加渠道信息后,不需要重新簽名?
答案就是:VasDolly 。
背景
Android在國內(nèi)的市場極度的碎片化,各大應(yīng)用市場樂此不疲,OEM廠商也都自立山頭。而作為一個(gè)成熟的、商業(yè)化的App,必然是要在各個(gè)應(yīng)用市場占坑霸榜的。所以運(yùn)營的同事一般都會(huì)要求Android小哥哥提供幾個(gè)甚至十幾個(gè)不同渠道的渠道包。而傳統(tǒng)的打包工具的打包速度大家都心知肚明的,盡管Google不斷的優(yōu)化,但還是差強(qiáng)人意。因此一個(gè)快速,高效的打包工具就很必要了,可以節(jié)省開發(fā)小哥哥大量的工作時(shí)間。
使用VasDolly
在根工程的build.gradle中,添加對(duì)打包Plugin的依賴:
dependencies {? ? ?
? classpath'com.android.tools.build:gradle:3.0.0'classpath'com.leon.channel:plugin:2.0.3'
}
在主App工程的build.gradle中,添加對(duì)VasDolly Plugin的引用:
applyplugin:'channel'
添加對(duì)VasDolly helper類庫的依賴
在主App工程的build.gradle中,添加讀取渠道信息的helper類庫依賴:
dependencies { ? ?api'com.leon.channel:helper:2.0.3'}
配置渠道列表
目前有兩種方式配置渠道列表,最終的渠道列表是兩者的累加之和:
在gradle.properties文件指定渠道文件名稱,該渠道文件必須位于根工程目錄下,一行一個(gè)渠道信息。
channel_file=channelFile.txt
在channel或者rebuildChannel屬性中通過channelFile屬性指定渠道文件,一行一個(gè)渠道信息。
channel{
//指定渠道文件
channelFile = file("../channelFile.txt")
}
rebuildChannel{
//指定渠道文件
channelFile = file("../channelFile.txt")
}
channelFile.txt 為了方便經(jīng)常git版本管理,我放在了項(xiàng)目的根目錄下

channelFile.txt 中的內(nèi)容是每一個(gè)渠道都單獨(dú)成行

直接編譯生成多渠道包
若是直接編譯生成多渠道包,首先要配置渠道文件、渠道包的輸出目錄和渠道包的命名規(guī)則:
channel{
//指定渠道文件
channelFile=file("../channelFile.txt")
//多渠道包的輸出目錄,默認(rèn)為new File(project.buildDir,"channel")
baseOutputDir = new File("${project.buildDir}/channelRoot/test")
//多渠道包的命名規(guī)則,默認(rèn)為${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}
apkNameFormat='${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}'
//快速模式:生成渠道包時(shí)不進(jìn)行校驗(yàn)(速度可以提升10倍以上,默認(rèn)為false)
isFastMode=true
//buildTime的時(shí)間格式,默認(rèn)格式:yyyyMMdd-HHmmss
buildTimeDateFormat='yyyyMMdd-HH:mm:ss'
//低內(nèi)存模式(僅針對(duì)V2簽名,默認(rèn)為false):只把簽名塊、中央目錄和EOCD讀取到內(nèi)存,不把最大頭的內(nèi)容塊讀取到內(nèi)存,在手機(jī)上合成APK時(shí),可以使用該模式
lowMemory=false
}
其中,多渠道包的命名規(guī)則中,可使用以下字段:
appName : 當(dāng)前project的name
versionName : 當(dāng)前Variant的versionName
versionCode : 當(dāng)前Variant的versionCode
buildType : 當(dāng)前Variant的buildType,即debug or release
flavorName : 當(dāng)前的渠道名稱
appId : 當(dāng)前Variant的applicationId
buildTime : 當(dāng)前編譯構(gòu)建日期時(shí)間,時(shí)間格式可以自定義,默認(rèn)格式:yyyyMMdd-HHmmss
然后,通過gradle channelDebug、gradle channelRelease命令分別生成Debug和Release的多渠道包。
為了方便臨時(shí)生成渠道包進(jìn)行測試,我們從v2.0.0開始支持添加渠道參數(shù):gradle channelDebug(channelRelease) -Pchannels=yingyongbao,gamecenter,這里通過屬性channels指定的渠道列表擁有更高的優(yōu)先級(jí),且和原始的文件方式是互斥的。
選擇使用V1 還是V2簽名
目前Gradle Plugin 2.2以上默認(rèn)開啟V2簽名,所以如果想關(guān)閉V2簽名,可將下面的v2SigningEnabled設(shè)置為false。
signingConfigs {?
? ? ? release {
? ? ?? ? ?...? ? ? ? ? ?
? ? ?? ? ?v1SigningEnabledtruev2SigningEnabledfalse
? ? ?}? ? ? ?
debug {
? ? ?...? ? ? ? ? ?
? ? ?v1SigningEnabledtruev2SigningEnabledfalse
? ? ?}?
}
如圖

讀取渠道信息
通過helper類庫中的ChannelReaderUtil類讀取渠道信息。
Stringchannel=ChannelReaderUtil.getChannel(getApplicationContext());
如果沒有渠道信息,那么這里返回null,開發(fā)者需要自己判斷。
調(diào)用Gradle Task 一鍵生成多個(gè)release版本渠道包,或者debug渠道包
在集成成功之后,重新rebuild項(xiàng)目,VasDolly就會(huì)自動(dòng)在項(xiàng)目的Gradle Task中生成對(duì)應(yīng)的Task ,在需要發(fā)布正式版的時(shí)候只要選擇對(duì)應(yīng)的task即可

完成打包之后,就可以在直接配置的輸出目錄中看到生成的應(yīng)用安裝包了

使用命令行生成渠道包
為了方便臨時(shí)生成渠道包進(jìn)行測試,VasDolly從v2.0.0開始支持添加渠道參數(shù):gradle channelDebug(channelRelease) -Pchannels=yingyongbao,gamecenter,這里通過屬性channels指定的渠道列表擁有更高的優(yōu)先級(jí),且和原始的文件方式是互斥的。
效果等同于上一種使用方式

Demo參考
詳細(xì)的接入范式,可參考Demo
或者參考我自己寫的Demo