目錄
一、Python打包及優化(美團多渠道打包)
二、Gradle打包
三、其他打包方案:修改Zip文件的comment
參考閱讀
早幾個月前在有心課堂看過Android多渠道打包的視頻,覺得蠻有用的,時至今日卻發現不少具體的細節已經忘得差不多,于是重新整理了一篇筆記,順道分享給大家。
一、Python打包及優化(美團多渠道打包)
既然是Python打包,那么python環境是必須的,否則無法運行python腳本文件,mac系統下默認安裝了Python環境,而Windows系統下則需要自己安裝了,這個安裝過程相對可以簡單,大家可以自行谷歌下,記得配好環境變量。驗證是否安裝成功的方式是,打開命令行,輸入python,如果安裝成功的話,會打印python的版本信息。
下面我們以友盟應用統計為例,進行相關的操作。
需要準備的東西:
- 簽名好的Apk文件
- channel.py (python腳本文件
- channel列表文件 (注:必須命名為android_channels.txt,如果不想這樣命名,可自行更改python腳本代碼
- ChannelUtil.java工具類
其中channel列表文件(android_channels.txt)的格式為每一個渠道號換一行,示例:
xiaomi
360mobile
wandoujia
baidu
另外python腳本文件、ChannelUtil.java這里就不貼代碼了,有點長,但還是比較簡單容易理解的,大家可以自己下載下來看看,附上 :傳送門
使用姿勢:
首先,在簽名打包一個Apk之前,需要在程序的入口處添加如下代碼:
String channel= ChannelUtil.getChannel(mAppContext); //獲取渠道號,內存>SharedPreferences>apk的/META-INF/目錄
MobclickAgent.startWithConfigure(new MobclickAgent.UMAnalyticsConfig(getApplicationContext(),umengAppkey,channel)); //友盟:通過代碼的方式設置渠道號
生成好以后,將該apk文件和上面所準備的東西放在同一個文件夾,打開終端命令行,進入該文件夾。執行命令:
python channel.py apk包名
很快就在當前目錄下生成一個release文件夾,里面生成了各個渠道所需要的渠道包。
這一條簡單的命令背后,到底隱藏著什么不為人知的流程呢?請看下圖:
整理思路來看,就是通過python腳本去讀取渠道列表,然后一個for循環將簽名好的apk寫入渠道號,并在當前目錄下,生成一個release文件夾,將寫入好的渠道包放進去,那么這個for循環內部究竟是怎樣的一個操作呢?它分為以下幾步:
- 復制簽名好的signatured.apk到./release文件夾下
- 重命名signatured.spk 為 signatured_channel_xxx.apk
- 找到apk/META-INF/目錄
- 新建一個文件名為 channel_xxx的空文件
這種通過python打包的方式有什么優點和缺點呢?
優點:
- 只需要一個簽名好的apk
- 速度快(在渠道少的情況下,基本秒開,如果渠道更多,有100多個的話應該也不會超過一分鐘)
缺點:
- 依賴Java的簽名方式(現有的打包方式,在apk的META-INF目錄下添加文件,是不需要重新簽名的,但如果谷歌更改了這套簽名方式,那么這種方法就不適用了)
- 必須支持只用Java代碼寫入渠道號
zipalign優化:
是否上述的這種打包方式就一定完美了呢?也許你會遇到這樣的問題:
- 在Google Play上提交會失敗(如果你的應用要上傳到該市場的話
- Lollipop系統(Android 5.0.1)安裝可能會提示解析安裝包錯誤
所以介紹來要介紹另外一款工具——zipalign,官方的定義是這樣子的:
zipalign is an archive alignment tool that provides important optimization to Android application (APK) files
簡單提煉為關鍵詞就是:優化工具、4字節邊界對齊、減少內存使用、提高效率
何時需要使用這個工具?
- apk簽名之后(在開發過程中,更多的時候是eclipse、as自動幫我們使用了這個工具,不需要我們手動去使用它的
- 對apk進行添加或更改的時候
常用的命令:
- zipalign -c -v <alignment> existing.apk
- zipalign [-f] [-v] <alignment> infile.apk outfile.apk
-c :驗證apk是否按照某種對齊方式對齊
-f :覆蓋已經存在的文件
-v :輸出verbose級別的信息
<alignment> :對齊方式,這里我們以4字節的方式對齊
existing.apk :需要驗證的apk文件
infile.apk :要打包的apk文件
outfile.apk :要輸出的apk文件
第一條命令是用來驗證apk是否有進行過zipalign優化;第二條命令是用來進行zipalign優化
那么zipalign這個工具在哪里呢?
我們可以打開android sdk的安裝目錄下,在build-tools/版本號文件夾/找到一個zipalign.exe,其實zipalign是在android 1.6之后提供的一個工具,在使用之前我們最好可以把這個路徑配置到環境變量里。
在使用的時候,我們通常先用第一條命令判斷我們的apk文件是否已經進行過zipalign優化,接著再使用第二條命令是優化我們的apk文件,快捷命令:
首先是驗證apk:
zipalign -c -v 4 demo_channel.apk
進行zipalign優化:
zipalign -f -v 4 demo_channel.apk demo_align.apk
有些同學可能會問,你這一個apk優化還好,那如果有很多個渠道包,我們應該怎么去優化呢?這里已經在剛剛的傳送門里,給大家準備好了兩個腳本文件,分別是mac系統下的zipalign_batch.sh和windows系統下的zipalign_batch.bat文件,并且已經集成到channel.py的python腳本當中,我們在使用的時候,可以根據自己的需要自行開啟相關的代碼即可:
#mac
#os.system('chmod u+x zipalign_batch.sh')
#os.system('./zipalign_batch.sh')
#windows
#os.system('zipalign_batch.bat')
再次提醒下大家,在開啟使用這段代碼的前,要把zipalign工具配置到你系統的環境變量里,否則在運行python腳本過程中會提示相關的文件找不到哈。
二、Gradle打包
相信大部分開發者都已經遷移到AS下進行開發,那么利用gradle進行多渠道打包也是我們必須掌握的一個知識點,下面分別講解下gradle的多渠道打包和多Apk打包。
多渠道打包
多渠道打包,大家應該都知道,這里不解釋,同樣以友盟統計為例,
第一步:
在AndroidManifest.xml文件中配置渠道ID,${UMENG_CHANNEL_VALUE}
為占位符,其中的UMENG_CHANNEL_VALUE
可以自己任意定義
<meta-data android:name="UMENG_CHANNEL" android:value="${UMENG_CHANNEL_VALUE}"/>
第二步:
在項目的build.gradle文件中設置打包簽名信息 signingConfigs:
android {
debug {
// No debug config
}
release {
storeFile file("../yourapp.jks")
storePassword "your password"
keyAlias "your alias"
keyPassword "your password"
}
}
接著,設置productFlavors,這里包含你了所需要的渠道號:
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"]
}
}
}
也有另外一種簡便的寫法,其實就是用Groovy語法執行一個for循環:
productFlavors {
xiaomi {}
360 mobile {}
wandoujia {}
baidu {}
}
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
最后:
在AS的內置終端Terminal工具中執行命令:
./gradlew assembleRelease
(所有生成的apk在項目的build\outputs\apk下)
好了,接下來可以靜靜等待打包完成。
如果不想使用命令行的方式進行打包,AS也為我們提供了圖形界面的方式,點擊菜單欄->Build->Generate Signed APK,輸入相關的簽名證書路徑和密碼即可:
這種打包方式的其中一個好處是可以指定打包后的apk所存放的路徑。
多Apk打包
什么叫多Apk打包?可能很多人不知道,也沒有碰到這樣的需求,多Apk打包其實就是根據特定的需求,生成不同類型的apk,譬如說每個apk的有不同的應用名稱、應用icon或cpu類型等等。
下面以生成不同的cup類型的apk為例,cup的類型大致可以分為分別是arm、mips、X86這三種:
同樣地,我們在build.gradle設置這ProductFlavors即可:
productFlavors {
arm {
ndk{
abiFilters("armeabi","armeabi-v7a")
}
}
mips {
ndk{
abiFilters("mips","mips86")
}
}
x86 {
ndk{
abiFilters("x86","x86_64")
}
}
}
這里要插句補充下defaultConfig 跟 productFlavors的關系,defaultConfig相當于一個默認的flavor,如果我們沒有定義productFlavors,gradle在構建過程中就會只讀取defaultConfig的配置信息;如果自定義了productFlavors,那么defaultConfig相當于每一個flavor的基礎配置信息。如果flavor和defaultConfig的某些配置項相同,flavor的配置將會覆蓋defaultConfig。
補充知識點
Gradle常用命令
- ./gradlew -v :版本號
- ./gradlew clean :清除項目/app目錄下的build文件夾
- ./gradlew build 檢查依賴并編譯打包
需要注意的是 ./gradlew build 命令會debug、release環境的包都打出來,如果正式發布只需要打Release的包,可以使用assemble命令
- ./gradlew assembleDebug :編譯并打Debug包
- ./gradlew assembleRelease :編譯并打Release的包
- ./gradlew installRelease :Release模式打包并安裝
- ./gradlew uninstallRelease :卸載Release模式包
我們執行命令前,都會加上
./gradlew
,./
代表當前目錄,gradlew
代表gradle wrapper,意思是gradle的一層包裝,可以理解為在這個項目本地就封裝了gradle,即gradle wrapper。在項目名/gradle/wrapper/gralde-wrapper.properties
文件中聲明了它指向的目錄和版本.
關于assemble
在上面的assemble命令中,會結合Build Type來創建自己的task,譬如:
- ./gradlew assembleDebug
- ./gradlew assembleRelease
除此之外,assemble還能和ProductFlavor 結合創建新的任務,其實assemble是和Build >Variants 一起結合使用的,大家可以這么來理解:
Build Variants = Build Type + Product Flavor
舉個栗子:
如果我們想打wandoujia渠道的Release版本,可以執行如下命令
./gradlew assembleWandoujiaRelease
如果我們只打wandoujia渠道版本,則:
./gradlew assembleWandoujia
(此命令會生成wandoujia渠道的Release和Debug版本)同理,如果想打全部Release版本:
./gradlew assembleRelease
(這條命令會把Product Flavor下的所有渠道的Release版本都打出來)
基于以上,總結一下assemble創建task有如下用法:
- 允許直接構建一個Variant版本,例如 assembleFlavor1Debug
- 允許構建指定Build Type的所有APK,例如assembleDebug將會構建Flavor1Debug和Flavor2Debug兩個Variant版本
- 允許構建指定flavor的所有APK,例如assembleFlavor1將會構建Flavor1Debug和Flavor1Release兩個Variant版本
關于BuildVariants
在AS中有個BuildVariants的概念,Build Variants = Build Type + Product Flavor,譬如如下代碼:
android {
productFlavors {
xiaomi {}
_360mobile {}
wandoujia {}
baidu {}
}
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
}
會生成以下的BuildVariants:
我們就可以看到,productFlavors有多個維度,并且每個Flavor都有debug和release,所以總共生成Build Type*ProductFlavor個不同的apk,也即2*4=8種不同的APK。
最后附上送一個完整的gradle腳本文件:傳送門
三、其他打包方案:修改Zip文件的comment
核心原理:
Android應用使用的APK文件就是一個帶簽名信息的ZIP文件,根據 ZIP文件格式規范 ,每個ZIP文件的最后都必須有一個叫 Central Directory Record 的部分,這個CDR的最后部分叫"end of central directory record",這一部分包含一些元數據,它的末尾是ZIP文件的注釋。注釋包含Comment Length和File Comment兩個字段,前者表示注釋內容的長度,后者是注釋的內容,正確修改這一部分不會對ZIP文件造成破壞,利用這個字段,我們可以添加一些自定義的數據。
所以原理很簡單,就是將渠道信息存放在APK文件的注釋字段中
優點:
- 沒有解壓縮、壓縮、重簽名過程,打包速度極快,單個包只需要5毫秒左右,甚至可用于網站后臺動態生成渠道包
缺點:
- 沒有使用Android的productFlavors,無法利用flavor條件編譯的功能
相關工具: