目錄
一、Python打包及優(yōu)化(美團(tuán)多渠道打包)
二、Gradle打包
三、其他打包方案:修改Zip文件的comment
參考閱讀
早幾個(gè)月前在有心課堂看過(guò)Android多渠道打包的視頻,覺(jué)得蠻有用的,時(shí)至今日卻發(fā)現(xiàn)不少具體的細(xì)節(jié)已經(jīng)忘得差不多,于是重新整理了一篇筆記,順道分享給大家。
一、Python打包及優(yōu)化(美團(tuán)多渠道打包)
既然是Python打包,那么python環(huán)境是必須的,否則無(wú)法運(yùn)行python腳本文件,mac系統(tǒng)下默認(rèn)安裝了Python環(huán)境,而Windows系統(tǒng)下則需要自己安裝了,這個(gè)安裝過(guò)程相對(duì)可以簡(jiǎn)單,大家可以自行谷歌下,記得配好環(huán)境變量。驗(yàn)證是否安裝成功的方式是,打開(kāi)命令行,輸入python,如果安裝成功的話,會(huì)打印python的版本信息。
下面我們以友盟應(yīng)用統(tǒng)計(jì)為例,進(jìn)行相關(guān)的操作。
需要準(zhǔn)備的東西:
- 簽名好的Apk文件
- channel.py (python腳本文件
- channel列表文件 (注:必須命名為android_channels.txt,如果不想這樣命名,可自行更改python腳本代碼
- ChannelUtil.java工具類
其中channel列表文件(android_channels.txt)的格式為每一個(gè)渠道號(hào)換一行,示例:
xiaomi
360mobile
wandoujia
baidu
另外python腳本文件、ChannelUtil.java這里就不貼代碼了,有點(diǎn)長(zhǎng),但還是比較簡(jiǎn)單容易理解的,大家可以自己下載下來(lái)看看,附上 :傳送門(mén)
使用姿勢(shì):
首先,在簽名打包一個(gè)Apk之前,需要在程序的入口處添加如下代碼:
String channel= ChannelUtil.getChannel(mAppContext); //獲取渠道號(hào),內(nèi)存>SharedPreferences>apk的/META-INF/目錄
MobclickAgent.startWithConfigure(new MobclickAgent.UMAnalyticsConfig(getApplicationContext(),umengAppkey,channel)); //友盟:通過(guò)代碼的方式設(shè)置渠道號(hào)
生成好以后,將該apk文件和上面所準(zhǔn)備的東西放在同一個(gè)文件夾,打開(kāi)終端命令行,進(jìn)入該文件夾。執(zhí)行命令:
python channel.py apk包名
很快就在當(dāng)前目錄下生成一個(gè)release文件夾,里面生成了各個(gè)渠道所需要的渠道包。
這一條簡(jiǎn)單的命令背后,到底隱藏著什么不為人知的流程呢?請(qǐng)看下圖:

整理思路來(lái)看,就是通過(guò)python腳本去讀取渠道列表,然后一個(gè)for循環(huán)將簽名好的apk寫(xiě)入渠道號(hào),并在當(dāng)前目錄下,生成一個(gè)release文件夾,將寫(xiě)入好的渠道包放進(jìn)去,那么這個(gè)for循環(huán)內(nèi)部究竟是怎樣的一個(gè)操作呢?它分為以下幾步:
- 復(fù)制簽名好的signatured.apk到./release文件夾下
- 重命名signatured.spk 為 signatured_channel_xxx.apk
- 找到apk/META-INF/目錄
- 新建一個(gè)文件名為 channel_xxx的空文件
這種通過(guò)python打包的方式有什么優(yōu)點(diǎn)和缺點(diǎn)呢?
優(yōu)點(diǎn):
- 只需要一個(gè)簽名好的apk
- 速度快(在渠道少的情況下,基本秒開(kāi),如果渠道更多,有100多個(gè)的話應(yīng)該也不會(huì)超過(guò)一分鐘)
缺點(diǎn):
- 依賴Java的簽名方式(現(xiàn)有的打包方式,在apk的META-INF目錄下添加文件,是不需要重新簽名的,但如果谷歌更改了這套簽名方式,那么這種方法就不適用了)
- 必須支持只用Java代碼寫(xiě)入渠道號(hào)
zipalign優(yōu)化:
是否上述的這種打包方式就一定完美了呢?也許你會(huì)遇到這樣的問(wèn)題:
- 在Google Play上提交會(huì)失敗(如果你的應(yīng)用要上傳到該市場(chǎng)的話
- Lollipop系統(tǒng)(Android 5.0.1)安裝可能會(huì)提示解析安裝包錯(cuò)誤
所以介紹來(lái)要介紹另外一款工具——zipalign,官方的定義是這樣子的:
zipalign is an archive alignment tool that provides important optimization to Android application (APK) files
簡(jiǎn)單提煉為關(guān)鍵詞就是:優(yōu)化工具、4字節(jié)邊界對(duì)齊、減少內(nèi)存使用、提高效率
何時(shí)需要使用這個(gè)工具?
- apk簽名之后(在開(kāi)發(fā)過(guò)程中,更多的時(shí)候是eclipse、as自動(dòng)幫我們使用了這個(gè)工具,不需要我們手動(dòng)去使用它的
- 對(duì)apk進(jìn)行添加或更改的時(shí)候
常用的命令:
- zipalign -c -v <alignment> existing.apk
- zipalign [-f] [-v] <alignment> infile.apk outfile.apk
-c :驗(yàn)證apk是否按照某種對(duì)齊方式對(duì)齊
-f :覆蓋已經(jīng)存在的文件
-v :輸出verbose級(jí)別的信息
<alignment> :對(duì)齊方式,這里我們以4字節(jié)的方式對(duì)齊
existing.apk :需要驗(yàn)證的apk文件
infile.apk :要打包的apk文件
outfile.apk :要輸出的apk文件
第一條命令是用來(lái)驗(yàn)證apk是否有進(jìn)行過(guò)zipalign優(yōu)化;第二條命令是用來(lái)進(jìn)行zipalign優(yōu)化
那么zipalign這個(gè)工具在哪里呢?
我們可以打開(kāi)android sdk的安裝目錄下,在build-tools/版本號(hào)文件夾/找到一個(gè)zipalign.exe,其實(shí)zipalign是在android 1.6之后提供的一個(gè)工具,在使用之前我們最好可以把這個(gè)路徑配置到環(huán)境變量里。
在使用的時(shí)候,我們通常先用第一條命令判斷我們的apk文件是否已經(jīng)進(jìn)行過(guò)zipalign優(yōu)化,接著再使用第二條命令是優(yōu)化我們的apk文件,快捷命令:
首先是驗(yàn)證apk:
zipalign -c -v 4 demo_channel.apk
進(jìn)行zipalign優(yōu)化:
zipalign -f -v 4 demo_channel.apk demo_align.apk
有些同學(xué)可能會(huì)問(wèn),你這一個(gè)apk優(yōu)化還好,那如果有很多個(gè)渠道包,我們應(yīng)該怎么去優(yōu)化呢?這里已經(jīng)在剛剛的傳送門(mén)里,給大家準(zhǔn)備好了兩個(gè)腳本文件,分別是mac系統(tǒng)下的zipalign_batch.sh和windows系統(tǒng)下的zipalign_batch.bat文件,并且已經(jīng)集成到channel.py的python腳本當(dāng)中,我們?cè)谑褂玫臅r(shí)候,可以根據(jù)自己的需要自行開(kāi)啟相關(guān)的代碼即可:
#mac
#os.system('chmod u+x zipalign_batch.sh')
#os.system('./zipalign_batch.sh')
#windows
#os.system('zipalign_batch.bat')
再次提醒下大家,在開(kāi)啟使用這段代碼的前,要把zipalign工具配置到你系統(tǒng)的環(huán)境變量里,否則在運(yùn)行python腳本過(guò)程中會(huì)提示相關(guān)的文件找不到哈。
二、Gradle打包
相信大部分開(kāi)發(fā)者都已經(jīng)遷移到AS下進(jìn)行開(kāi)發(fā),那么利用gradle進(jìn)行多渠道打包也是我們必須掌握的一個(gè)知識(shí)點(diǎn),下面分別講解下gradle的多渠道打包和多Apk打包。
多渠道打包
多渠道打包,大家應(yīng)該都知道,這里不解釋,同樣以友盟統(tǒng)計(jì)為例,
第一步:
在AndroidManifest.xml文件中配置渠道ID,${UMENG_CHANNEL_VALUE} 為占位符,其中的UMENG_CHANNEL_VALUE可以自己任意定義
<meta-data android:name="UMENG_CHANNEL" android:value="${UMENG_CHANNEL_VALUE}"/>
第二步:
在項(xiàng)目的build.gradle文件中設(shè)置打包簽名信息 signingConfigs:
android {
debug {
// No debug config
}
release {
storeFile file("../yourapp.jks")
storePassword "your password"
keyAlias "your alias"
keyPassword "your password"
}
}
接著,設(shè)置productFlavors,這里包含你了所需要的渠道號(hào):
android {
productFlavors {
xiaomi {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"]
}
360 mobile {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "360mobile"]
}
wandoujia {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
}
baidu {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
}
}
}
也有另外一種簡(jiǎn)便的寫(xiě)法,其實(shí)就是用Groovy語(yǔ)法執(zhí)行一個(gè)for循環(huán):
productFlavors {
xiaomi {}
360 mobile {}
wandoujia {}
baidu {}
}
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
最后:
在AS的內(nèi)置終端Terminal工具中執(zhí)行命令:
./gradlew assembleRelease
(所有生成的apk在項(xiàng)目的build\outputs\apk下)
好了,接下來(lái)可以靜靜等待打包完成。
如果不想使用命令行的方式進(jìn)行打包,AS也為我們提供了圖形界面的方式,點(diǎn)擊菜單欄->Build->Generate Signed APK,輸入相關(guān)的簽名證書(shū)路徑和密碼即可:


這種打包方式的其中一個(gè)好處是可以指定打包后的apk所存放的路徑。
多Apk打包
什么叫多Apk打包?可能很多人不知道,也沒(méi)有碰到這樣的需求,多Apk打包其實(shí)就是根據(jù)特定的需求,生成不同類型的apk,譬如說(shuō)每個(gè)apk的有不同的應(yīng)用名稱、應(yīng)用icon或cpu類型等等。
下面以生成不同的cup類型的apk為例,cup的類型大致可以分為分別是arm、mips、X86這三種:
同樣地,我們?cè)赽uild.gradle設(shè)置這ProductFlavors即可:
productFlavors {
arm {
ndk{
abiFilters("armeabi","armeabi-v7a")
}
}
mips {
ndk{
abiFilters("mips","mips86")
}
}
x86 {
ndk{
abiFilters("x86","x86_64")
}
}
}
這里要插句補(bǔ)充下defaultConfig 跟 productFlavors的關(guān)系,defaultConfig相當(dāng)于一個(gè)默認(rèn)的flavor,如果我們沒(méi)有定義productFlavors,gradle在構(gòu)建過(guò)程中就會(huì)只讀取defaultConfig的配置信息;如果自定義了productFlavors,那么defaultConfig相當(dāng)于每一個(gè)flavor的基礎(chǔ)配置信息。如果flavor和defaultConfig的某些配置項(xiàng)相同,flavor的配置將會(huì)覆蓋defaultConfig。
補(bǔ)充知識(shí)點(diǎn)
Gradle常用命令
- ./gradlew -v :版本號(hào)
- ./gradlew clean :清除項(xiàng)目/app目錄下的build文件夾
- ./gradlew build 檢查依賴并編譯打包
需要注意的是 ./gradlew build 命令會(huì)debug、release環(huán)境的包都打出來(lái),如果正式發(fā)布只需要打Release的包,可以使用assemble命令
- ./gradlew assembleDebug :編譯并打Debug包
- ./gradlew assembleRelease :編譯并打Release的包
- ./gradlew installRelease :Release模式打包并安裝
- ./gradlew uninstallRelease :卸載Release模式包
我們執(zhí)行命令前,都會(huì)加上
./gradlew,./代表當(dāng)前目錄,gradlew代表gradle wrapper,意思是gradle的一層包裝,可以理解為在這個(gè)項(xiàng)目本地就封裝了gradle,即gradle wrapper。在項(xiàng)目名/gradle/wrapper/gralde-wrapper.properties文件中聲明了它指向的目錄和版本.
關(guān)于assemble
在上面的assemble命令中,會(huì)結(jié)合Build Type來(lái)創(chuàng)建自己的task,譬如:
- ./gradlew assembleDebug
- ./gradlew assembleRelease
除此之外,assemble還能和ProductFlavor 結(jié)合創(chuàng)建新的任務(wù),其實(shí)assemble是和Build >Variants 一起結(jié)合使用的,大家可以這么來(lái)理解:
Build Variants = Build Type + Product Flavor
舉個(gè)栗子:
如果我們想打wandoujia渠道的Release版本,可以執(zhí)行如下命令
./gradlew assembleWandoujiaRelease
如果我們只打wandoujia渠道版本,則:
./gradlew assembleWandoujia
(此命令會(huì)生成wandoujia渠道的Release和Debug版本)同理,如果想打全部Release版本:
./gradlew assembleRelease
(這條命令會(huì)把Product Flavor下的所有渠道的Release版本都打出來(lái))
基于以上,總結(jié)一下assemble創(chuàng)建task有如下用法:
- 允許直接構(gòu)建一個(gè)Variant版本,例如 assembleFlavor1Debug
- 允許構(gòu)建指定Build Type的所有APK,例如assembleDebug將會(huì)構(gòu)建Flavor1Debug和Flavor2Debug兩個(gè)Variant版本
- 允許構(gòu)建指定flavor的所有APK,例如assembleFlavor1將會(huì)構(gòu)建Flavor1Debug和Flavor1Release兩個(gè)Variant版本
關(guān)于BuildVariants
在AS中有個(gè)BuildVariants的概念,Build Variants = Build Type + Product Flavor,譬如如下代碼:
android {
productFlavors {
xiaomi {}
_360mobile {}
wandoujia {}
baidu {}
}
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
}
會(huì)生成以下的BuildVariants:

我們就可以看到,productFlavors有多個(gè)維度,并且每個(gè)Flavor都有debug和release,所以總共生成Build Type*ProductFlavor個(gè)不同的apk,也即2*4=8種不同的APK。
最后附上送一個(gè)完整的gradle腳本文件:傳送門(mén)
三、其他打包方案:修改Zip文件的comment
核心原理:
Android應(yīng)用使用的APK文件就是一個(gè)帶簽名信息的ZIP文件,根據(jù) ZIP文件格式規(guī)范 ,每個(gè)ZIP文件的最后都必須有一個(gè)叫 Central Directory Record 的部分,這個(gè)CDR的最后部分叫"end of central directory record",這一部分包含一些元數(shù)據(jù),它的末尾是ZIP文件的注釋。注釋包含Comment Length和File Comment兩個(gè)字段,前者表示注釋內(nèi)容的長(zhǎng)度,后者是注釋的內(nèi)容,正確修改這一部分不會(huì)對(duì)ZIP文件造成破壞,利用這個(gè)字段,我們可以添加一些自定義的數(shù)據(jù)。
所以原理很簡(jiǎn)單,就是將渠道信息存放在APK文件的注釋字段中
優(yōu)點(diǎn):
- 沒(méi)有解壓縮、壓縮、重簽名過(guò)程,打包速度極快,單個(gè)包只需要5毫秒左右,甚至可用于網(wǎng)站后臺(tái)動(dòng)態(tài)生成渠道包
缺點(diǎn):
- 沒(méi)有使用Android的productFlavors,無(wú)法利用flavor條件編譯的功能
相關(guān)工具: