Android多渠道打包方案

Android多渠道打包,由于傳統(tǒng)打包速度比較慢单芜,本篇主要 介紹一種新的打包方案细疚,速度可提升百倍。

背景:

android studio支持多渠道打包方式俩莽,是通過gradle 的變種方式來進行的:

//build.gradle
manifestPlaceholders = [FFCHANNEL_ID_VALUE: channel]
//AndroidManifest.xml
<meta-data            
    android:name="FFCHANNEL_ID"           
    android:value="${FFCHANNEL_ID_VALUE}" />

這種方式是google推薦的方式旺坠,但這種方式對于幾個渠道包是可以支持的, 當我們需要打上百個渠道包時扮超,這種方案耗時很長取刃,是項目開發(fā)不能忍受的。而目前我們項目需要進行加固后保障安全出刷,發(fā)布市場的app需要進行加固蝉衣。當發(fā)布app時候,我們需要在集成打包機器上進行打包巷蚪,目前項目為11個渠道包病毡,耗時一個多小時,時間已經(jīng)屬于不可容忍的,況且還未進行加固屁柏,目前加固11個包啦膜,需要半小時有送,廣州銀行80個渠道包,2G多僧家,全部加固完成需要半天時間雀摘。這種情況下,我們需要考慮采用新的方案來解決打渠道包耗時費力的問題八拱。

新方案

新方案是通過zip包注釋的方案進行多渠道打包的阵赠,由開發(fā)提供一個生成包即可,使用該包進行加固肌稻,作為母包清蚀。通過開發(fā)提供的腳本,批量生成多渠道包爹谭,基本屬于拷貝復(fù)制的節(jié)奏枷邪,由于目前apk為27M多,偏大诺凡,所以基本一個渠道包為1s东揣,生成80個渠道包耗時80秒,親測腹泌。
可以考慮以后由開發(fā)只提供母包嘶卧,由運營發(fā)布市場的同事根據(jù)運營需求來自己執(zhí)行腳本發(fā)布各市場渠道包,簡單凉袱,方便芥吟,快捷,不受限制绑蔫。

原理

使用APK注釋字段保存渠道信息和MAGIC字節(jié)运沦,通過腳本將取渠道信息寫入apk注釋字段中。 android使用的apk包的壓縮方式是zip配深,與zip有相同的文件結(jié)構(gòu)携添,在zip的Central directory file header中包含一個File comment區(qū)域,可以存放一些數(shù)據(jù)篓叶。File comment是zip文件如果可以正確的修改這個部分烈掠,就可以在不破壞壓縮包、不用重新打包的的前提下快速的給apk文件寫入自己想要的數(shù)據(jù)缸托。 comment是在Central directory file header末尾儲存的左敌,可以將數(shù)據(jù)直接寫在這里,下表是header末尾的結(jié)構(gòu)
image
由于數(shù)據(jù)是不確定的俐镐,我們無法知道comment的長度矫限,從表中可以看到zip定義comment的長度的位置在comment之前,所以無法從zip中直接獲取comment的長度。這里我們需要自定義comment的長度叼风,在自定義comment內(nèi)容的后面添加一個區(qū)域儲存comment的長度取董,結(jié)構(gòu)如下圖。 image

目前也已經(jīng)和愛加密加固的同事進行了確認无宿,愛加密的加固方式不會占用該zip注釋茵汰,不會和該多渠道包方案沖突,也已經(jīng)在項目中測試驗證通過孽鸡。

實現(xiàn)

寫入 :寫入可以使用java蹂午,也可以使用python,目前考慮到可以對外提供彬碱,使用python豆胸。
讀取 :讀取需要在Android代碼中用java實現(xiàn)。
//定義魔法串作為結(jié)束符
MAGIC = '!ZXK!'
//寫入

def write_market(path, market, output):
    '''
    write market info to apk file
    write_market(apk-file-path, market-name, output-path)
    '''
    path = os.path.abspath(path)
    output = unicode(output)
    if not os.path.exists(path):
        print('apk file',path,'not exists')
        return
    if read_market(path):
        print('apk file',path,'had market already')
        return
    if not output:
        output = os.path.dirname(path)
    if not os.path.exists(output):
        os.makedirs(output)
    name,ext = os.path.splitext(os.path.basename(path))
    # name,package,vname,vcode
    app = parse_apk(path)
    apk_name = '%s-%s-%s-%s%s' % (app['app_package'],
        market.decode('utf8'), app['version_name'], app['version_code'], ext)
    # apk_name = name + "-" + market + ext
    apk_file = os.path.join(output,apk_name)
    shutil.copy(path,apk_file)
    # print('apk file:',apk_file)
    index = os.stat(apk_file).st_size
    index -= ZIP_SHORT
    with open(apk_file,"r+b") as f:
        f.seek(index)
        # write comment length 
        f.write(struct.pack('<H',len(market) + ZIP_SHORT + len(MAGIC)))
        # write comment content
        # content = [market_string + market_length + magic_string]
        f.write(market)
        f.write(struct.pack('<H',len(market)))
        f.write(MAGIC)
    return apk_file

//讀取

public static String readZipComment(File file) throws IOException {
            RandomAccessFile raf = null;
            try {
                raf = new RandomAccessFile(file, "r");
                long index = raf.length();
                byte[] buffer = new byte[MAGIC.length];
                index -= MAGIC.length;
                // read magic bytes
                raf.seek(index);
                raf.readFully(buffer);
                // if magic bytes matched
                if (isMagicMatched(buffer)) {
                    index -= SHORT_LENGTH;
                    raf.seek(index);
                    // read content length field
                    int length = readShort(raf);
                    if (length > 0) {
                        index -= length;
                        raf.seek(index);
                        // read content bytes
                        byte[] bytesComment = new byte[length];
                        raf.readFully(bytesComment);
                        return new String(bytesComment, UTF_8);
                    } else {
                        throw new IOException("zip comment content not found");
                    }
                } else {
                    throw new IOException("zip comment magic bytes not found");
                }
            } finally {
                if (raf != null) {
                    raf.close();
                }
            }
        }

使用

目前提供寫入腳本到項目中堡妒,讀取渠道號代碼已經(jīng)集成到j(luò)ava代碼中配乱。
使用如下:
格式是:python ngpacker.py [file] [market] [output]
eg:

python ngpacker.py app-release_signed.apk markets.txt apks

渠道配置文件如下:

1001#bdsj  
1002#azsc  
1003#91zs  
1004#wdj  
1005#txyyb
1006#xmyy
1007#360sj
1008#hwyy
1009#anzhisc
1010#ppzs
1011#lsd
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末溉卓,一起剝皮案震驚了整個濱河市皮迟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌桑寨,老刑警劉巖伏尼,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異尉尾,居然都是意外死亡爆阶,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門沙咏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辨图,“玉大人,你說我怎么就攤上這事肢藐」屎樱” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵吆豹,是天一觀的道長鱼的。 經(jīng)常有香客問我,道長痘煤,這世上最難降的妖魔是什么凑阶? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮衷快,結(jié)果婚禮上宙橱,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好师郑,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布哼勇。 她就那樣靜靜地躺著,像睡著了一般呕乎。 火紅的嫁衣襯著肌膚如雪积担。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天猬仁,我揣著相機與錄音帝璧,去河邊找鬼。 笑死湿刽,一個胖子當著我的面吹牛的烁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播诈闺,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼渴庆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了雅镊?” 一聲冷哼從身側(cè)響起襟雷,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎仁烹,沒想到半個月后耸弄,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡卓缰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年计呈,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片征唬。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡捌显,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出总寒,到底是詐尸還是另有隱情扶歪,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布偿乖,位于F島的核電站击罪,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏贪薪。R本人自食惡果不足惜媳禁,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望画切。 院中可真熱鬧竣稽,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至岛宦,卻和暖如春台丛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背砾肺。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工挽霉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人变汪。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓侠坎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親裙盾。 傳聞我的和親對象是個殘疾皇子实胸,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容