手游SDK — 第六篇(游戲打包篇(中)- 自動化打包)

hi鞠呈,各位看官,前一篇大概介紹了如何生成打包需要的原料山析,下面這篇來分析下打包工具是如何做的奶是。歡迎來到打包系統(tǒng)核心部分:自動化打包

PS:該自動化打包工具是Python代碼編寫,需要大伙有點(diǎn)python的功底聚磺。(不過沒事坯台,我也是邊學(xué)邊擼出來的。)瘫寝。打包系統(tǒng)的的交互會涉及到網(wǎng)頁和桌面兩種方式蜒蕾,因網(wǎng)頁打包涉及到與前端交互就不細(xì)講,該系列只會講桌面部分供大家參考焕阿。

自動化打包過程分析及實現(xiàn)

自動化打包思路

前面已經(jīng)說過咪啡,搞事情就得反編譯apk,整體的自動化打包也是基于包體的反編譯和回編譯設(shè)計的暮屡。利用apktool工具先反編譯游戲母包撤摸,之后合并游戲母包和渠道資源,利用dx.jar和baksmail.jar工具將渠道資源包內(nèi)封裝好的源碼合并到游戲反編譯后的smali代碼中褒纲,再回編譯生成新的包體准夷,最后給包體簽名優(yōu)化輸出最終的游戲_渠道包≥郝樱可以參考下圖

自動化打包過程圖解
image.png
自動化打包過程示例:

手游SDK框架Demo的工程及樂享渠道SDK為例子衫嵌,下面講解下打包的實現(xiàn)過程:

原料準(zhǔn)備
  • 1、游戲母包:手游SDK框架Demo接入模擬測試渠道生成GameSDKFrame.apk彻秆。(模擬游戲母包)
  • 2渐扮、渠道資源包:手游SDK框架Demo接入樂享渠道并生成對應(yīng)的混淆jar:sdk_lexiang_v1.0.0.jar论悴,整合資源目錄:


    image.png

相關(guān)說明可以在打包示例資源下載。

命令打包過程
  • 1墓律、將GameSDKFrame.apk反編譯成資源文件(GameSDKFrame.apk模擬游戲母包)膀估,進(jìn)入cmd,執(zhí)行命令:

apktool d -f [待編譯apk路徑] -o [輸出資源路徑]

image.png
  • 2耻讽、將反編譯生成的資源文件和渠道的資源文件合并察纯,合并assets、libs针肥、res及AndroidManifest.xml等資源文件(目前是手動合并)
image.png
  • 3饼记、根據(jù)資源文件合成R.java文件,進(jìn)入cmd慰枕,執(zhí)行命令:

aapt package -f -m -J [R.java輸出路徑] -S [res路徑] -I [android.jar路徑]-M [AndroidManifest.xml路徑]

image.png
  • 4具则、編譯生成的R.class文件,進(jìn)入cmd 具帮,執(zhí)行命令:

javac -source 1.7 -target 1.7 -encoding UTF-8 [R.java路徑]

image.png
  • 5博肋、合成R.jar文件,進(jìn)入cmd蜂厅,執(zhí)行命令:

jar cvf [輸入目錄及名稱] *

image.png
  • 6匪凡、將.jar 轉(zhuǎn)化為.dex文件(注意只能單個轉(zhuǎn)換,批量轉(zhuǎn)換需要循環(huán))掘猿,進(jìn)入cmd病游,執(zhí)行命令:

java -jar [dx.jar路徑] --dex --output=[輸出路徑] [待轉(zhuǎn)化jar路徑]

image.png
  • 7、將.dex轉(zhuǎn)化為smail代碼(注意只能單個轉(zhuǎn)換稠通,批量轉(zhuǎn)換需要循環(huán))衬衬,進(jìn)入cmd,執(zhí)行命令:

java -jar [baksmali.jar路徑] -o [輸入文件夾] [待轉(zhuǎn)化dex文件]

image.png
  • 8改橘、回編譯生成apk包進(jìn)入cmd滋尉,執(zhí)行命令:

apktool b [待編譯資源路徑] -o [生成apk路徑]

image.png
  • 9、生成apk包體簽名

jarsigner -verbose -keystore [keystore文件路徑] -signedjar [簽名后生成的apk路徑] [待簽名的apk路徑] [別名]

image.png

至此完整的打包流程就完畢了唧龄,至此就可以把渠道對應(yīng)的資源打到游戲包體里面去了可以運(yùn)行下前后的包體看下效果:

打包前的登錄界面


image.png

打包后的登錄界面


image.png

關(guān)于游戲的整體打包流程的實現(xiàn)就大體介紹到這里。其中涉及到的腳本命名不太清楚的奸远,可自行查閱資料既棺。

自動化打包項目架構(gòu)設(shè)計

上面跟大家分析了及實現(xiàn)了生成一個游戲_渠道包的整體過程,但是都是命令行一步一步講解實現(xiàn)懒叛,過程很麻煩丸冕,效率也很低。根本達(dá)不到日常的開發(fā)及應(yīng)用效果薛窥,下面咱們來聊聊整體搭建自動化打包項目胖烛,并開發(fā)一個打包工具出來眼姐。

PS:這里的項目架構(gòu)設(shè)計會大概說明下前端的交互設(shè)計,但是涉及到前端知識就不涉及具體實現(xiàn)(可以看看效果圖)佩番。

架構(gòu)設(shè)計的產(chǎn)品輸出

產(chǎn)品定位:任何一款接入聚合SDK的任意版本游戲都能通過自動化打包系統(tǒng)快速的生成任意渠道任意版本的游戲包體众旗。

注意這里的任意含義:
任意版本游戲:同一款游戲會有多個地區(qū)版本
任意渠道:同一款同版本的游戲可以快速接入任意一家已合作的渠道SDK
任意渠道任意版本:同一款同版本的游戲可以快速接入同一家已合作的渠道的任意版本SDK。

架構(gòu)設(shè)計的功能模塊設(shè)計

根據(jù)產(chǎn)品的定位趟畏,可以快速確認(rèn)產(chǎn)品的功能設(shè)計大概會幾個模塊內(nèi)容:游戲管理贡歧、渠道管理、打包任務(wù)管理赋秀、自動化打包工具利朵。可以細(xì)分為兩部分:后臺管理系統(tǒng)部分和前端打包部分

后臺管理系統(tǒng)
  • 1猎莲、游戲管理:
    主要是管理游戲參數(shù)配置绍弟,登錄、支付開關(guān)著洼、計費(fèi)點(diǎn)等信息


    image.png
  • 2樟遣、渠道管理:
    主要是渠道信息管理、版本管理郭脂、參數(shù)管理年碘、渠道資源配置管理。


    image.png
前端打包系統(tǒng)
  • 1展鸡、打包任務(wù)界面管理:
    會給打包工具提供輸出當(dāng)前的打包任務(wù)的信息:包含游戲版本屿衅、渠道參數(shù)信息、渠道參數(shù)配置信息莹弊,打包過程的編譯參數(shù)等涤久。
網(wǎng)頁版打包系統(tǒng)
image.png
桌面版打包系統(tǒng)
image.png

ps:自己開發(fā)的有點(diǎn)丑,這個可以參考易接的界面會更好一些

  • 2忍弛、自動化打包工具:
    自動化打包的核心响迂,接收打包任務(wù),接收打包資源(游戲資源细疚、渠道資源蔗彤、配置資源等),自動化處理生成apk疯兼。

自動化打包工具(自動化打包項目核心)

好了然遏,來到該系列的核心內(nèi)容了。自動化打包工具吧彪,又要敲代碼了待侵,好開心。姨裸。秧倾。

項目結(jié)構(gòu)搭建

廢話不多說了怨酝,代碼經(jīng)過三次重構(gòu)優(yōu)化,簡單附上一張項目結(jié)構(gòu)圖

image.png

項目代碼模塊實現(xiàn)

打包任務(wù)接口設(shè)計
    """
    # taskId                       任務(wù)ID
    # gameName                     游戲名稱
    # gameId                       游戲ID
    # gameVersion                  游戲版本
    # gameApkName                  游戲母包名稱
    # channelName                  渠道名稱
    # channelId                    渠道ID
    # channelVersion               渠道版本
    # isLocal                      是否是本地打包(區(qū)分服務(wù)器打包,主要處理差異化配置)
    # signId                       簽名文件ID那先,默認(rèn)為0, 本地桌面打包默認(rèn)設(shè)置為1
    # keystore                     簽名文件名稱,為默認(rèn)
    # alias                        簽名文件別名农猬,為默認(rèn)
    # storepass                    簽名文件密碼,為默認(rèn)
    # keypass                      簽名文件別名密碼胃榕,為默認(rèn)

    """

    # 基準(zhǔn)包任務(wù)
    task = BuildApkTask('180', 'TESTGame', '1', '1.0.0', 'GameSDKFrame.apk', 'lexiang' '1', '1.0.0')
    # 開始打包任務(wù)
    task.buildApk()

資源合并模塊處理

這里資源合并處理跟渠道資源包一一對應(yīng):assets/libs/res/manifest/icon/r文件等盛险。

    # 開始打包的核心邏輯,第一步:合并資源文件,包括assets/libs/res等目錄資源
    self.logger.info(u'開始合并資源....')
    status, result = merge_resources(self.taskId, self.Tools, self.TempPath, self.BaseChannelPath, self.ChannelId,
                                     self.ChannelVersion, self.compile_config)
    if status == 0:
        self.logger.info(u'合并資源成功\n')
    else:
        self.logger.info(result)
        self.logger.info(u'合并資源失敗\n')
        return status, result

    # 第二步: 配置渠道的閃屏圖片及特殊配置文件等
    self.logger.info(u'合并配置文件....')
    status, result = merge_config(self.TempPath, self.BaseChannelPath)
    if status == 0:
        self.logger.info(u'合并配置文件成功\n')
    else:
        self.logger.info(result)
        self.logger.info(u'合并配置文件失敗\n')
        return status, result

    # 第三步:合并游戲的Icon和角標(biāo)資源
    self.logger.info(u'開始合并角標(biāo)....')
    status, result = merge_icon(self.taskId, self.TempPath, self.BaseChannelPath)
    if status == 0:
        self.logger.info(u'合并角標(biāo)成功\n')
    else:
        self.logger.info(result)
        self.logger.info(u'合并角標(biāo)失敗\n')
        return status, result

    # 第四步:合并Manifest.xml
    self.logger.info(u'開始合并Manifest.xml文件....')
    status, result, package_name = merge_manifest(self.taskId, self.TempPath, self.BaseChannelPath, self.ChannelId,
                                                  self.ChannelVersion, self.compile_config)
    if status == 0:
        self.logger.info(u'合并Manifest.xml文件成功\n')
    else:
        self.logger.info(result)
        self.logger.info(u'合并Manifest.xml文件失敗\n')
        return status, result

    # 第五步:根據(jù)資源生成對應(yīng)的R文件
    self.logger.info(u'開始生成R文件....')
    status, result = create_r_files(self.taskId, self.Tools, self.TempPath, self.BaseChannelPath,
                                    self.ChannelId, self.ChannelVersion, self.compile_config, package_name)
    if status == 0:
        self.logger.info(u'生成R文件成功\n')
    else:
        self.logger.info(result)
        self.logger.info(u'生成R文件失敗\n')
        return status, result

渠道資源差異化處理

主要特處理特殊渠道的參數(shù)配置勋又,閃屏邏輯苦掘,是否有微信登錄支付類文件等。

# 定義特殊渠道父類
class SpecialChannel(object):

    def __init__(self, channel_name):
        self.channel_name = channel_name

    # 修改assets_resource
    def modify_assets_resource(self, channel_path, channel_version, config):
        print "%s modify_assets_resource" % self.channel_name
        return 0, "%s modify_assets_resource" % self.channel_name

    # 修改res_resource
    def modify_res_resource(self, channel_path, channel_version, config):
        print "%s modify_res_resource" % self.channel_name
        return 0, "%s modify_res_resource" % self.channel_name

    # 修改manifest_resource
    def modify_manifest_resource(self, channel_path, channel_version, config):
        print "%s modify_manifest_resource" % self.channel_name
        return 0, "%s modify_manifest_resource" % self.channel_name

    # 修改微信回調(diào)包名.wxapi.xxx.java問題
    def modify_wx_callback_resource(self, tools_path, temp_path, channel_path, channel_version, config):
        print "%s modify_wx_callback_resource" % self.channel_name
        return 0, "%s modify_wx_callback_resource" % self.channel_name
#
#  修改渠道assets目錄資源統(tǒng)一入口, 根據(jù)渠道的id來分發(fā), version來做版本版本控制
#
def modify_channel_assets_resource(channel_path, channel_id, channel_version, config):

    # 默認(rèn)特殊渠道
    special_channel = special.SpecialChannel('special_channel')

    if channel_id == '28':  # 應(yīng)用寶渠道YSDK
        special_channel = ysdk.YsdkChannel('ysdk')

    status, result = special_channel.modify_assets_resource(channel_path, channel_version, config)
    return status, result


#
#  修改渠道res目錄資源統(tǒng)一入口, 根據(jù)渠道的id來分發(fā), version來做版本版本控制
#
def modify_channel_res_resource(channel_path, channel_id, channel_version, config):

    # 默認(rèn)特殊渠道
    special_channel = special.SpecialChannel('special_channel')

    if channel_id == '26':  # 360渠道SDK
        special_channel = qihoo.QihooChannel('360')

    status, result = special_channel.modify_res_resource(channel_path, channel_version, config)
    return status, result


#
#  修改渠道AndroidManifest.xml資源統(tǒng)一入口, 根據(jù)渠道的id來分發(fā), version來做版本版本控制
#
def modify_channel_manifest(channel_path, channel_id, channel_version, config):

    # 默認(rèn)修改包名
    try:
        modify_manifest_package_name(channel_path, config)
    except Exception as e:
        return 1, u'modify manifest package_name fail' + str(e)

    # 默認(rèn)特殊渠道
    special_channel = special.SpecialChannel('special_channel')

    if channel_id == '17':  # OPPO渠道SDK
        special_channel = oppo.OppoChannel('oppo')

    elif channel_id == '28':  # 應(yīng)用寶渠道SDK
        special_channel = ysdk.YsdkChannel('ysdk')

    status, result = special_channel.modify_manifest_resource(channel_path, channel_version, config)
    return status, result


#
#  處理下,渠道微信登錄楔壤、支付等相關(guān)功能需在包名下配置: 包名.wxapi.xxx.java問題
#
def modify_channel_wx_callback(tools_path, temp_path, channel_path, channel_id, channel_version, config):

    # 默認(rèn)特殊渠道
    special_channel = special.SpecialChannel('special_channel')

    if channel_id == '28':  # 應(yīng)用寶渠道SDK
        special_channel = ysdk.YsdkChannel('ysdk')

    status, result = special_channel.modify_wx_callback_resource(tools_path, temp_path, channel_path, channel_version, config)
    return status, result


#
#  處理下,渠道閃屏問題 和 修改游戲主入口問題
#
def modify_channel_splash_and_main(game_path, channel_id, channel_version, config):

    status, result = modify_splash_and_gameMain(game_path, channel_id, channel_version, config)
    return status, result

界面打包示例:

打包.gif
結(jié)語:

關(guān)于自動化打包就到這里鹤啡,下一篇會詳細(xì)自動化打包遇到的坑點(diǎn)及代碼優(yōu)化過程。手游SDK — 第七篇(游戲打包篇(下)- 自動化打包踩坑記錄)蹲嚣。

完整的自動化打包工具項目递瑰,本人已開源∠缎螅可到可到開源項目打包工具下載:PackageApkTool

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

如果覺得我的文章對你有幫助,請隨意贊賞议惰。您的支持將鼓勵我繼續(xù)創(chuàng)作慎颗!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者言询。
  • 序言:七十年代末俯萎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子运杭,更是在濱河造成了極大的恐慌夫啊,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辆憔,死亡現(xiàn)場離奇詭異撇眯,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)虱咧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門熊榛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人彤钟,你說我怎么就攤上這事来候□尾妫” “怎么了逸雹?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵营搅,是天一觀的道長。 經(jīng)常有香客問我梆砸,道長转质,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任帖世,我火速辦了婚禮休蟹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘日矫。我一直安慰自己赂弓,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布哪轿。 她就那樣靜靜地躺著盈魁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪窃诉。 梳的紋絲不亂的頭發(fā)上杨耙,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機(jī)與錄音飘痛,去河邊找鬼珊膜。 笑死,一個胖子當(dāng)著我的面吹牛宣脉,可吹牛的內(nèi)容都是我干的车柠。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼脖旱,長吁一口氣:“原來是場噩夢啊……” “哼堪遂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起萌庆,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤溶褪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后践险,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體猿妈,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年巍虫,在試婚紗的時候發(fā)現(xiàn)自己被綠了彭则。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡占遥,死狀恐怖俯抖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瓦胎,我是刑警寧澤芬萍,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布尤揣,位于F島的核電站,受9級特大地震影響柬祠,放射性物質(zhì)發(fā)生泄漏北戏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一漫蛔、第九天 我趴在偏房一處隱蔽的房頂上張望嗜愈。 院中可真熱鬧,春花似錦莽龟、人聲如沸蠕嫁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拌阴。三九已至,卻和暖如春奶镶,著一層夾襖步出監(jiān)牢的瞬間迟赃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工厂镇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纤壁,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓捺信,卻偏偏與公主長得像酌媒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子迄靠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

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