美團多渠道打包方案詳解,速度快到白駒過隙

loonggg發表於2016-06-06

Andorid渠道市場有多分散呢?分散到比Android碎片化還嚴重,你還在為多渠道打包而頭疼嗎?美團提供了速度快到白駒過隙的多渠道打包方案。說的有點誇張,對,雖然誇張,但是確實很快,不誇張不足以形容其快。廢話不多說,先講原理,再講實踐方法。

新舊打包方法原理對比講解

傳統方式

在AndroidManifest定義渠道的年代,多渠道打包無非以下兩種方案:

  • 方案一:完全的重新編譯,即在程式碼重新編譯打包之前,在AndroidManifest中修改渠道標示;

  • 方案二:通過ApkTool進行解包,然後修改AndroidManifest中修改渠道標示,最後再通過ApkTool進行打包、簽名。

這兩種打包方式,不管是哪種,效率都很低,方案一毫無效率可言,而且打包的渠道規模非常小,第二種方案效率稍微高些,打包的渠道規模也還可以,但是這兩種方案速度慢的驚人,如果你打個上百的渠道包試試,估計你的電腦能卡一下午。慢,當然也有好處,你可以不用工作了,喝著咖啡,玩著手機慢慢等也很愜意是不?哈哈……

美團高效的多渠道打包方案

美團高效的多渠道打包方案是把一個Android應用程式包當作一個zip檔案包進行解壓,然後發現在簽名生成的目錄下新增一個空檔案,空檔案用渠道名來命名,而且不需要重新簽名。這種方式不需要重新簽名,編譯等步驟,使得這種方法非常高效。

第一步:解壓apk檔案

我們直接解壓apk,解壓後的根目錄會有一個META-INF目錄,如下圖所示:

如果在META-INF目錄內新增空檔案,可以不用重新簽名應用。因此,通過為不同渠道的應用新增不同的空檔案,可以唯一標識一個渠道。

第二步:用python指令碼向apk檔案中新增空渠道檔案

我們用python程式碼來給apk新增空的渠道檔案,渠道名的字首為mtchannel_:

import zipfile
zipped = zipfile.ZipFile(your_apk, `a`, zipfile.ZIP_DEFLATED) 
empty_channel_file = "META-INF/mtchannel_{channel}".format(channel=your_channel)
zipped.write(your_empty_file, empty_channel_file)

新增完空渠道檔案後的目錄,META-INFO目錄多了一個名為mtchannel_meituan的空檔案:

第三步:用java程式碼讀取渠道名,並動態設定渠道名

我們用指令碼生成了檔案之後,檔案的名字是用渠道名來命名的,所以我們在啟動程式的時候,可以用java程式碼動態讀取渠道名,並動態的去設定。
java程式碼讀取渠道名的方法:

public static String getChannel(Context context) {
        ApplicationInfo appinfo = context.getApplicationInfo();
        String sourceDir = appinfo.sourceDir;
        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("mtchannel")) {
                    ret = entryName;
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (zipfile != null) {
                try {
                    zipfile.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        String[] split = ret.split("_");
        if (split != null && split.length >= 2) {
            return ret.substring(split[0].length() + 1);

        } else {
            return "";
        }
    }

讀取到了渠道名,我們就可以動態的設定了,比如友盟渠道的動態設定方法是:AnalyticsConfig.setChannel(getChannel(Context context) );這樣就好了。這種方式每打一個渠道包只需複製一個apk,在META-INF中新增一個使用渠道號命名的空檔案即可。這種打包方式速度非常快,據說900多個渠道不到一分鐘就能打完。我親測的是我用了10秒鐘打了32個渠道包,是不是很快。

實踐使用

你可能會說,我看不懂上面的python程式碼,那個指令碼里的內容看不明白,這個沒關係。你仔細明白了原理即可,因為有人給你造輪子,我們直接騎就可以了。

實踐方法使用

第一步:配置python環境

我們既然需要使用指令碼打包,那麼相應的電腦上必須有可以執行python指令碼的執行環境。所以我們第一步是要配置python執行環境。
自己去官網下載安裝即可,非常簡單。官網地址:https://www.python.org/

第二步:設定python指令碼並把封裝好的類放到工程裡

好心人已經把執行的打包指令碼寫好了,並且也封裝了讀取渠道號的實體工具類。大家只需要去github上下載即可。
地址:https://github.com/GavinCT/AndroidMultiChannelBuildTool
當然在github上也有相關的使用介紹,非常簡單,一看就懂。這裡簡單說下,下載下來有個ChannelUtil.java類,裡面封裝好了獲取渠道號的方法,你只需要在啟動應用程式的地方呼叫友盟的設定程式碼即可,比如:AnalyticsConfig.setChannel(ChannelUtil.getChannel(this))。

第三步:配置渠道列表

我們在github上把輪子下載下來之後,你解壓檔案,在PythonTool/Info/channel.txt中編輯渠道列表,沒寫一個渠道名,換行即可。

第四步:複製簽好名的包,執行指令碼

你把你已經簽名打包好的apk檔案,複製到PythonTool目錄下和MultiChannelBuildTool.py這個指令碼同級,直接雙擊點選MultiChannelBuildTool.py即可完成打包。

ok,到這裡基本就講完了,講了講原理,又講了講實踐方式,鑑於別人都給你造好輪子了,所以使用起來非常簡單,趕緊去試一試吧。如果不明白的可以留言,歡迎一起交流。

參考文章:
http://tech.meituan.com/mt-apk-packaging.html

移動開發者的聚集地,公眾號“非著名程式設計師”,每天一篇原創技術分享和移動網際網路知識分享,微信公眾號:smart_android,頭條號和百度百家賬號都是“非著名程式設計師”。

相關文章