使用Ant或者Gradle來給程序進行多渠道批量打包,一般都是在manifest文件中寫入一個meta標籤:git
<meta-data android:name="CHANNEL" android:value="xxx" />
meta的key值固定,經過循環改變meta中的value值來實現市場渠道的寫入。程序員
Ant批量打包實現相對麻煩,之前寫的時候多虧了謙虛的天下-《App自動化之使用Ant編譯項目多渠道打包》 。若是沒有這篇帖子,真不知道當時Ant要折騰多少回才能寫好。github
Gradle做爲新的安卓官方構建工具,有Google老大撐腰,它的批量打包實現會相對簡單些。能夠參考《遷移到Android Studio》。固然這裏面有些指令過期了,例如:runProguard已經被minifyEnabled替代了。android-studio
以上兩種都是傳統的批量打包方式,他們最大的缺點就是打包時間長。
在前期渠道不多時這種方法還能夠接受,但只要渠道稍微增多該方法就再也不適用了,緣由是每打一個包都要執行一遍構建過程,效率過低。(電腦比較爛,之前通常打包都要花費個30-40分鐘。)app
前幾天看到美團的技術分享文檔:《美團Android自動化之旅—生成渠道包》,其中第三種方式提到:工具
若是能直接修改apk的渠道號,而不須要再從新簽名能節省很多打包的時間。幸運的是咱們找到了這種方法。直接解壓apk,解壓後的根目錄會有一個META-INF目錄,以下圖所示:
若是在META-INF目錄內添加空文件,能夠不用從新簽名應用。所以,經過爲不一樣渠道的應用添加不一樣的空文件,能夠惟一標識一個渠道。
採用這種方式,每打一個渠道包只需複製一個apk,在META-INF中添加一個使用渠道號命名的空文件便可。
這種打包方式速度很是快,900多個渠道不到一分鐘就能打完。
OK,到這裏,思路就有了。
因爲文檔中的代碼實現較少,這裏我來說述一下個人實現。
基於以上總結的美團思路,實現了一套本身的代碼,方便引入到工程後實現這種打包方式。
代碼在Github:GavinCT/AndroidMultiChannelBuildTool
首先建立一個空文件,等待寫入META-INF目錄做爲channel_xxx文件
# 空文件 便於寫入此空文件到apk包中做爲channel文件 src_empty_file = 'info/czt.txt' # 建立一個空文件(不存在則建立) f = open(src_empty_file, 'w') f.close()
獲取渠道列表。
考慮到渠道的更新不該該是程序員來作,所以在info文件夾下放置一個channel文件,便於不懂程序的人更新渠道。(每一個渠道以換行結束)
# 獲取渠道列表 channel_file = 'info/channel.txt' f = open(channel_file) lines = f.readlines() f.close()
找到初始apk
考慮到現實中爲了防止安裝包過大,咱們一般分爲arm和x86兩個版本,因此python中支持當前目錄下放多個apk來進行打包。
固然有人會說共用了一個channel文件,多個apk會生成相同市場的對應包。
你也能夠修改一下python,使不一樣的apk去找不一樣的channel文件進行打包。
這裏因爲個人業務場景這樣更方便,我就不修改了。
# 獲取當前目錄中全部的apk源包 src_apks = [] # python3 : os.listdir()便可,這裏使用兼容Python2的os.listdir('.') for file in os.listdir('.'): if os.path.isfile(file): extension = os.path.splitext(file)[1][1:] if extension in 'apk': src_apks.append(file)
遍歷渠道號並寫入apk。
多個apk只是for循環問題,咱們來看單個apk生成多市場包的代碼
# file name (with extension) src_apk_file_name = os.path.basename(src_apk) # 分割文件名與後綴 temp_list = os.path.splitext(src_apk_file_name) # name without extension src_apk_name = temp_list[0] # 後綴名,包含. 例如: ".apk " src_apk_extension = temp_list[1] # 建立生成目錄,與文件名相關 output_dir = 'output_' + src_apk_name + '/' # 目錄不存在則建立 if not os.path.exists(output_dir): os.mkdir(output_dir) # 遍歷渠道號並建立對應渠道號的apk文件 for line in lines: # 獲取當前渠道號,由於從渠道文件中得到帶有\n,全部strip一下 target_channel = line.strip() # 拼接對應渠道號的apk target_apk = output_dir + src_apk_name + "-" + target_channel + src_apk_extension # 拷貝創建新apk shutil.copy(src_apk, target_apk) # zip獲取新創建的apk文件 zipped = zipfile.ZipFile(target_apk, 'a', zipfile.ZIP_DEFLATED) # 初始化渠道信息 empty_channel_file = "META-INF/cztchannel_{channel}".format(channel = target_channel) # 寫入渠道信息 zipped.write(src_empty_file, empty_channel_file) # 關閉zip流 zipped.close()
以上Python是屬於現學現寫,有什麼能夠優化的地方還請告知。
Python幫咱們向apk包中寫入了channel信息,Java端固然也須要對應更改才能使用。
因爲解析channel須要去apk也就是zip中去找文件,因此相對耗時一些。
所以在ChannelUtil.java中,會將找到的channel和對應versionCode存儲在靜態變量和SharedPreference中,保證本次甚至本版本中channel只從zip中獲取一次。
從apk中獲取channel,美團留下的代碼if (entryName.startsWith("mtchannel"))
是有問題的,應該採用if (entryName.startsWith("META-INF/mtchannel"))
。
個人代碼以下:
/** * 從apk中獲取版本信息 * @param context * @param channelKey * @return */ private static String getChannelFromApk(Context context, String channelKey) { //從apk包中獲取 ApplicationInfo appinfo = context.getApplicationInfo(); String sourceDir = appinfo.sourceDir; //注意這裏:默認放在meta-inf/裏, 因此須要再拼接一下 String key = "META-INF/" + channelKey; String ret = ""; ZipFile zipfile = null; try { zipfile = new ZipFile(sourceDir); Enumeration<?> entries = zipfile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = ((ZipEntry) entries.nextElement()); String entryName = entry.getName(); if (entryName.startsWith(key)) { ret = entryName; break; } } } catch (IOException e) { e.printStackTrace(); } finally { if (zipfile != null) { try { zipfile.close(); } catch (IOException e) { e.printStackTrace(); } } } String[] split = ret.split("_"); String channel = ""; if (split != null && split.length >= 2) { channel = ret.substring(split[0].length() + 1); } return channel; }
使用這種方式打包,打包工做再也不須要非得是安卓程序員。須要打包時,只要下載安裝Python環境,點擊MultiChannelBuildTool.py執行便可。
固然不是,Google老大爲他作了這麼多,怎麼能說不用就不用呢?
他的用處在於實現訂製,好比打包出x86和arm的包,或者打出手機包和適應平板的hd包,而後藉助上面的工具生成多個市場,即完成了多種適配包多個市場的任務。
Gradle渠道訂製的具體內容能夠參見:《美團Android自動化之旅—適配渠道包》 。
仍是美團的文檔,仍是熟悉的味道。在此感謝美團的分享。
這部分問題是由美團大神丁志虎在微博上答覆的,摘錄以下: