手游SDK — 第七篇(游戲打包篇(下)- 自動(dòng)化打包踩坑記錄)

Hi镰烧,各位老鐵,歡迎走進(jìn)自動(dòng)化打包系列的最后一篇楞陷,上文已整體分析并構(gòu)建了自動(dòng)化打包項(xiàng)目怔鳖,下面跟大家伙嘮嘮打包的實(shí)戰(zhàn),打包過程遇到的各位問題及處理方式固蛾。

在寫之前结执,大家伙先來看看之前的打包過程圖解:

image.png

通過這張圖可以看到度陆,整個(gè)打包的過程準(zhǔn)確地來講就是資源合并的過程,自動(dòng)化打包踩坑記錄篇也就是資源合并的坑點(diǎn)献幔。

合并Assets目錄及apktool.yml實(shí)戰(zhàn)踩坑記

通常在合并游戲和渠道的assets目錄的時(shí)候懂傀,先處理渠道的特殊配置,然后將渠道assets目錄資源拷貝覆蓋到游戲資源目錄就可以了蜡感。但是這里會(huì)遇到兩個(gè)坑點(diǎn):

坑點(diǎn)一:assets目錄的資源怎么缺失了蹬蚁。

以打YSDK渠道包為例,當(dāng)你美滋滋的打出來的包體運(yùn)行的時(shí)候郑兴。缚忧。。bangbangbangbang 杈笔,哈哈闪水,點(diǎn)擊YSDK渠道登錄沒反應(yīng)。問題在哪里呢蒙具?不著急哈球榆,首先你找一個(gè)可以正常運(yùn)行的包體,反編譯后跟你打出來的包體禁筏,你會(huì)發(fā)現(xiàn)assets目錄缺少了一堆文件持钉。

image.png

那這些文件都是哪里來的?最后你會(huì)發(fā)現(xiàn)在YSDK的.jar包里面篱昔,當(dāng)打包將.jar轉(zhuǎn)化為smail的時(shí)候只是將源碼進(jìn)行了轉(zhuǎn)化每强,沒有處理資源文件,導(dǎo)致資源的丟失州刽。

image.png

所以在合并libs資源的時(shí)候需要將jar里面的非class資源抽出來處理空执,后面代碼有說明

坑點(diǎn)二:unknown目錄的生成

細(xì)心的朋友可能通過上面的截圖就可以看到,jar文件里面除了assets目錄下的資源以外還多了BeaconVersion.txt文件穗椅,而且這個(gè)文件在最開始的時(shí)候也沒有打到游戲里面去辨绊,這個(gè)文件又要怎么處理呢?

其實(shí)匹表,在回編譯生成apk文件的時(shí)候门坷,apktool工具會(huì)將非.apk文件打包放到unknown的目錄下。這里可以參考下apktool源碼分析袍镀。
Apktool源碼解析——第一篇
Apktool源碼解析——第二篇

public void decodeUnknownFiles(ExtFile apkFile, File outDir, ResTable resTable) throws AndrolibException {
  LOGGER.info("Copying unknown files...");
  File unknownOut = new File(outDir, UNK_DIRNAME);
  ZipEntry invZipFile;

  // have to use container of ZipFile to help identify compression type
  // with regular looping of apkFile for easy copy
  try {
      Directory unk = apkFile.getDirectory();
      ZipExtFile apkZipFile = new ZipExtFile(apkFile.getAbsolutePath());

      // loop all items in container recursively, ignoring any that are pre-defined by aapt
      Set<String> files = unk.getFiles(true);
      for (String file : files) {//取出apk內(nèi)所有文件名
          if (!isAPKFileNames(file) && !file.endsWith(".dex")) {//不是常規(guī)文件也不是.dex文件

              // copy file out of archive into special "unknown" folder
              unk.copyToDir(unknownOut, file);//拷貝至unknown目錄
              try {
                  // ignore encryption
                  apkZipFile.getEntry(file).getGeneralPurposeBit().useEncryption(false);
                  invZipFile = apkZipFile.getEntry(file);

                  // lets record the name of the file, and its compression type
                  // so that we may re-include it the same way
                  if (invZipFile != null) {//這里把他們收集起來默蚌,如果需要回編譯還可以原封不動(dòng)的塞回去
                      mResUnknownFiles.addUnknownFileInfo(invZipFile.getName(), String.valueOf(invZipFile.getMethod()));
                  }
               } catch (NullPointerException ignored) { }
            }
        }
        apkZipFile.close();
   } catch (DirectoryException | IOException ex) {
        throw new AndrolibException(ex);
   }
}

當(dāng)你處理了前面兩個(gè)坑點(diǎn),將資源文件都拷貝到對應(yīng)的目錄的時(shí)候,你以為美滋滋的打包了苇羡, 你會(huì)發(fā)現(xiàn)你處理的unknown目錄的資源在回編譯的時(shí)候沒有打到Apk里面绸吸。為什么?

大家請看這句:

// lets record the name of the file, and its compression type
// so that we may re-include it the same way
if (invZipFile != null) {//這里把他們收集起來,如果需要回編譯還可以原封不動(dòng)的塞回去
    mResUnknownFiles.addUnknownFileInfo(invZipFile.getName(), String.valueOf(invZipFile.getMethod()));
}

apktool工具在反編譯apk時(shí)惯裕,會(huì)把編譯過程的資源信息寫到apktool.yml文件中温数,然后在回編譯的時(shí)候讀取apktool.yml的配置信息找對應(yīng)的資源文件

public void writeMetaFile(File mOutDir, Map<String, Object> meta)//鍵值對信息
            throws AndrolibException {
        DumperOptions options = new DumperOptions();
        options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
        Yaml yaml = new Yaml(options);

        try (
                Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(
                        new File(mOutDir, "apktool.yml")), "UTF-8"));//輸出目錄
        ) {
            yaml.dump(meta, writer);
        } catch (IOException ex) {
            throw new AndrolibException(ex);
        }
    }

因此,咱們在合并資源到unknown目錄的時(shí)候蜻势,需要修改下apktool.yml信息

坑點(diǎn)三:!!brut.androlib.meta.MetaInfo

這個(gè)坑點(diǎn)撑刺,比較隱秘,是不同版本apktool工具發(fā)現(xiàn)的握玛,是我在排查問題時(shí)遇到的够傍,打包工具用的是2.3.3版本的,但是電腦配置環(huán)境變量apktool版本是2.0.1的版本挠铲,然后手動(dòng)回編譯時(shí)冕屯,老是報(bào)錯(cuò):“could not determine a constructor for the tag 'tag:yaml.org,2002:brut.androlib.meta.MetaInfo'”。才發(fā)現(xiàn)高版本的的apktool工具在生成apktool.yml文件時(shí)拂苹,自動(dòng)在第一行上添加了這個(gè)字段安聘,再用版本回編譯的時(shí)候報(bào)錯(cuò)。如果反編譯和回編譯用的版本都是一樣的就沒有這個(gè)問題瓢棒。

坑點(diǎn)四:brut.androlib.AndrolibException: brut.common.BrutException: could not exec

這個(gè)問題排查了好久浴韭,最終發(fā)現(xiàn)是游戲包體資源放到assets目錄太多,在回編譯成apk包體時(shí)脯宿,無法編譯念颈。在apktool.yml處理下doNotCompress 字段下的字符串?dāng)?shù)字限制導(dǎo)致的(windows 命令行支持的字符串長度有限制,不超過8191個(gè)字符)连霉。

針對這個(gè)問題處理榴芳,還需要兼容apktool這個(gè)工具的版本。
apktool 2.0.2下以下版本跺撼,沒有做這個(gè)不壓縮機(jī)制處理窟感,可以正常回編譯财边。
2.0.2到2.3.2版本新增不壓縮的過濾規(guī)則
“jpg|jpeg|png|gif|wav|mp2|mp3|ogg|aac|mpg|mpeg|mid|midi|smf|jet|rtttl|imy|xmf|mp4|m4a|m4v|3gp|3gpp|3g2|3gpp2|amr|awb|wma|wmv|webm|mkv”
但是在2.3.3以上版本版本又將不過濾規(guī)則去掉了肌括。

為兼容apktool版本,在回編譯時(shí)修改設(shè)置過濾規(guī)則修改apktool.yml文件下的doNotCompress字段酣难。

針對上述的坑點(diǎn)問題,可查看PackageApkTool/MergeLibUtils.py中的modify_jars具體實(shí)現(xiàn)

合并libs目錄實(shí)戰(zhàn)踩坑記

通常在合并游戲和渠道的libs目錄的時(shí)候黑滴,這里需要處理.jar和.so兩個(gè)類型的文件處理憨募。
1、提取.jar文件里面非class資源袁辈,拷貝到對應(yīng)的目錄下
2菜谣、保證渠道提供的.so資源文件在游戲包體對應(yīng)的armeabi/armeabi-v7a/x86等目錄下都保持一致。不然會(huì)導(dǎo)致部分機(jī)型crash
3、需要額外處理微信相關(guān)功能的.java文件轉(zhuǎn)化為對應(yīng)的jar文件尾膊,方便在后續(xù)jar自動(dòng)轉(zhuǎn)化為smali代碼統(tǒng)一處理

針對上述的坑點(diǎn)問題媳危,可查看PackageApkTool/MergeResource.py中的merge_libs_resource具體實(shí)現(xiàn)

合并res目錄實(shí)戰(zhàn)踩坑記

通常在合并游戲和渠道的libs目錄的時(shí)候,會(huì)直接將渠道的資源拷貝覆蓋到游戲目錄里面冈敛。
一般渠道的res目錄資源都是有前綴來區(qū)分的待笑,但是需要考慮的是,游戲資源和渠道資源同名文件的覆蓋問題抓谴。

坑點(diǎn)一:res目錄下-V4目錄問題

渠道提供的資源目錄結(jié)構(gòu)與游戲反編譯后的目錄結(jié)構(gòu)不一致問題暮蹂。通常在新建安卓工程的時(shí)候,res目錄的資源包大多是drawable癌压、drawable-hdpi仰泻、drawable-xhdpi、values滩届、values-hdpi等形式集侯。但是反編譯之后你就發(fā)現(xiàn)游戲的目錄格式不一樣:

image.png

如果游戲資源已經(jīng)存在了資源文件,當(dāng)拷貝渠道的資源后帜消,回編譯時(shí)浅悉,會(huì)提示資源重復(fù),為了處理這個(gè)問題券犁,在合并資源文件的時(shí)候术健,就需提前判斷反編譯后的目錄結(jié)構(gòu)≌吵模拷貝到對應(yīng)的資源文件中荞估。

坑點(diǎn)二:res目錄下values目錄下arrays.xml/colors.xml/demens.xml/strings.xml資源丟失問題:

拷貝完渠道res資源之后,渠道的資源同名資源會(huì)覆蓋掉游戲反編譯后原有的資源來保證資源是渠道的最新版本稚新,但是需要注意的是values目錄下arrays.xml/colors.xml/demens.xml/strings.xml的資源丟失問題勘伺,因?yàn)橛螒騛pk包反編譯后的資源信息都打包到這幾個(gè)文件里面了,覆蓋后褂删,找不到對應(yīng)的資源會(huì)導(dǎo)致各種問題飞醉,所以需要針對這幾個(gè)資源文件做合并處理玄括。

坑點(diǎn)三:res目錄下values/values-hdpi等目錄下values.xml摹芙、values-hdpi.xml等資源沖突問題:

個(gè)別渠道的res/values目錄下提供的是values.xml判没、values-hdpi.xml的復(fù)合資源文件旧巾,將資源屬性都定義到里面利虫,values.xml準(zhǔn)確來說就是arrays.xml/colors.xml/demens.xml/strings.xml等的結(jié)合體:

image.png

其實(shí)在處理arrays.xml/colors.xml/demens.xml/strings.xml資源的時(shí)候笆怠,并沒有處理掉values.xml資源极祸,后面在生成R文件的時(shí)候就會(huì)提示資源沖突了祠汇。需要先將values.xml轉(zhuǎn)化為arrays.xml/colors.xml/demens.xml/strings.xml等文件盖袭。

坑點(diǎn)四:Error parsing XML: duplicate attribute 資源屬性名稱重復(fù)定義問題:

res目錄下values/values-hdpi等目錄下失暂,渠道的資源屬性和游戲的資源屬性重復(fù)定義彼宠,比如,游戲已定義了app_name這個(gè)字段弟塞,但是渠道資源里面也定義了這個(gè)字段凭峡。這類的處理是將渠道定義的屬性去掉。

針對上述的坑點(diǎn)問題决记,可查看PackageApkTool/MergeResUtils.py中的handle_res_dirs具體實(shí)現(xiàn)

合并Manifest文件實(shí)戰(zhàn)踩坑記

通常在合并游戲和渠道的Manifest文件的時(shí)候摧冀,先修改渠道的差異化參數(shù)配置后,直接將對應(yīng)的節(jié)點(diǎn)屬性拷貝到游戲的Manifest文件上面就可以了霉涨。
1按价、這里需要額外處理游戲的啟動(dòng)入口和SDK的閃屏邏輯處理
2、個(gè)別渠道需要特殊處理游戲的主Activity問題

坑點(diǎn)一:apktool無法識別compileSdkVersion 笙瑟、compileSdkVersionCodename

在實(shí)際操作過程中發(fā)現(xiàn)個(gè)別游戲包體反編譯后楼镐,Manifest文件中有compileSdkVersion 、compileSdkVersionCodename這兩個(gè)字段往枷,即使下載了最新版本的apktool工具也無法識別框产。這個(gè)是因?yàn)橛螒蚓幾g生成apk包時(shí)設(shè)置編譯版本為compileSdkVersion = 28 才會(huì)生成的。這里需要額外處理下將compileSdkVersion 错洁、compileSdkVersionCodename字段去掉秉宿。
但是在個(gè)別包體發(fā)現(xiàn),單單去掉還不行屯碴,需將targetSdkVersion設(shè)置為23以上才不會(huì)異常描睦。

針對上述的坑點(diǎn)問題,可查看PackageApkTool/MergeManifesUtils.py中的merger_manifest_config具體實(shí)現(xiàn)

生成R文件實(shí)戰(zhàn)踩坑記

坑點(diǎn)一:aapt停止運(yùn)行

其實(shí)在生成R文件時(shí)導(dǎo)致aapt停止運(yùn)行的原因有很多导而,但是基本上一般是資源文件或是xml文件中有錯(cuò)誤造成的忱叭。具體錯(cuò)誤的原因需要慢慢找。

這個(gè)問題發(fā)現(xiàn)在反編譯包體后今艺,生成的資源文件有問題韵丑,發(fā)現(xiàn)在布局xml中都自動(dòng)生成了n1這個(gè)字段。


image.png

最終定位的原因是模擬游戲母包的apk包是Android Studio3.0 Build Apks 生成包體虚缎,classpath 'com.android.tools.build:gradle:3.0.0' 生成的包體反編譯后都會(huì)這樣撵彻,可以通過將gradle版本設(shè)置:classpath 'com.android.tools.build:gradle:2.3.3' 就沒有該問題出現(xiàn)

坑點(diǎn)二:第三方庫通過R.xxx引用資源導(dǎo)致資源找不到問題。

這個(gè)問題很典型的案例就是個(gè)別第三方渠道引用了v7庫实牡,v7庫里面的res資源是通過R.xxx引用的陌僵。在最終打出來的包體資源只會(huì)跟當(dāng)前包名有關(guān),為解決類似這種需要指定包名的問題铲掐,可以生成多個(gè)R文件的思路解決拾弃。

PS:但是這里有個(gè)雷點(diǎn):生成的R文件除了包名不一致外,資源的ID都是一樣的摆霉。不知道會(huì)不會(huì)有問題。

針對上述的坑點(diǎn)問題,可查看PackageApkTool/MergeRFileUtils.py中的create_r_files具體實(shí)現(xiàn)

渠道差異化處理實(shí)戰(zhàn)踩坑記

坑點(diǎn)一:YSDK渠道ysdkconf.ini文件解析

文件不是標(biāo)準(zhǔn)的.ini的標(biāo)準(zhǔn)格式携栋,需要額外處理搭盾,同時(shí)文件的字符集是utf-8-sig,讀取后第一行老是多一個(gè)空格婉支,用.ini格式讀寫時(shí)鸯隅,老報(bào)錯(cuò),需先處理下字符集向挖。

針對上述的坑點(diǎn)問題蝌以,可查看PackageApkTool/YsdkChannel.py中的modify_assets_resource具體實(shí)現(xiàn)

坑點(diǎn)二:xml.etree import ElementTree as ET 解析xml文件出現(xiàn) ns0:xxx錯(cuò)誤

這個(gè)問題很好解決,在解析文件之前需將在parse前一定要設(shè)置namespace何之,類似Manifest需添加下面代碼跟畅。

ET.register_namespace('android', "http://schemas.android.com/apk/res/android")

結(jié)語:

坑點(diǎn)記錄的詳細(xì)代碼,可到開源項(xiàng)目打包工具下載:PackageApkTool

該工具后續(xù)持續(xù)完善溶推,歡迎大家star

如果覺得我的文章對你有幫助徊件,請隨意贊賞。您的支持將鼓勵(lì)我繼續(xù)創(chuàng)作蒜危!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載虱痕,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。
  • 序言:七十年代末辐赞,一起剝皮案震驚了整個(gè)濱河市部翘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌响委,老刑警劉巖新思,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異晃酒,居然都是意外死亡表牢,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門贝次,熙熙樓的掌柜王于貴愁眉苦臉地迎上來崔兴,“玉大人,你說我怎么就攤上這事蛔翅∏们眩” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵山析,是天一觀的道長堰燎。 經(jīng)常有香客問我,道長笋轨,這世上最難降的妖魔是什么秆剪? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任赊淑,我火速辦了婚禮,結(jié)果婚禮上仅讽,老公的妹妹穿的比我還像新娘陶缺。我一直安慰自己,他們只是感情好洁灵,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布饱岸。 她就那樣靜靜地躺著,像睡著了一般徽千。 火紅的嫁衣襯著肌膚如雪苫费。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天双抽,我揣著相機(jī)與錄音百框,去河邊找鬼。 笑死荠诬,一個(gè)胖子當(dāng)著我的面吹牛琅翻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播柑贞,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼方椎,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了钧嘶?” 一聲冷哼從身側(cè)響起棠众,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎有决,沒想到半個(gè)月后闸拿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡书幕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年新荤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片台汇。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡苛骨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出苟呐,到底是詐尸還是另有隱情痒芝,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布牵素,位于F島的核電站严衬,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏笆呆。R本人自食惡果不足惜请琳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一粱挡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧单起,春花似錦抱怔、人聲如沸劣坊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽局冰。三九已至测蘑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間康二,已是汗流浹背碳胳。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留沫勿,地道東北人挨约。 一個(gè)月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像产雹,于是被迫代替她去往敵國和親诫惭。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

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