12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910 |
- # 安卓游戏打包脚本
- # 1.用apktool解包
- # 2.复制res资源、assets资源、jniLib资源
- # 3.修改包名、app名、渠道文件
- # 4.添加app icon、合并AndroidManifest文件
- # 5.添加app启动图,修改AndroidManifest文件
- # 6.生成新的R文件
- # 7.将新的R文件编译,生成dex,再用baksmali生成smali,替换旧的R文件
- # 8.将jar资源打包成dex,再用baksmali生成smali,拷贝到smali目录下
- # 9.统计方法量,并分割dex(将smali文件拷贝到目录smali_classes2)
- # 10.用apktool回包
- # 11.重新签名
- import datetime
- import importlib
- import json
- import os
- import os.path
- import re
- import sys
- import uuid
- import zipfile
- import common_utils
- import config_utils
- import file_utils
- import game_utils
- import smali_utils
- import xml_utils
- ignoreLauncher = ['jm_ysdk', 'jm_yijie', 'jm_quick',
- 'jm_beiyu', 'jm_xq_jrtt', 'jm_zy_ysdk']
- adaptApp = ['yjzx']
- startTime = ''
- def pack(game, sdk, config):
- config['cache'] = uuid.uuid1()
- sub_channel = config['subChannel']
- print('game = %s, sdk = %s, subChannel = %s, ...' % (game, sdk, sub_channel))
- # 解包
- print('解包')
- ret = decomplie(game, sdk, sub_channel, config)
- if ret:
- return ret
- if is_refactor_sdk(config):
- return pack_v2(game, sdk, sub_channel, config)
- else:
- return pack_v1(game, sdk, sub_channel, config)
- def pack_v1(game, sdk, sub_channel, config):
- # 删除旧代码
- print('删除旧代码')
- ret = handle_jm_old_code(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 删除一些不支持的属性
- print('删除一些不支持的属性')
- ret = remove_no_support_attr(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 删除一些不支持的配置
- print('删除一些不支持的配置')
- ret = fix_un_support_config(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 合并Drawable-v4目录
- ret = merge_drawable_res(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 移除相同的资源
- ret = remove_same_values_res(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 复制res资源
- ret = copy_res(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 合并主文件
- ret = merge_manifest_res(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 替换占位符
- ret = change_placeholders(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 添加meta-data
- ret = add_meta_data(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 增加配置文件
- ret = add_v1_config(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 复制app res资源
- ret = copy_app_res(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 更改包名
- if 'packageName' in config and config['packageName'] != '':
- ret = change_package_name(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 更改app名
- if 'name' in config and config['name'] != '':
- ret = change_app_name(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 更改app icon
- if config['changeIcon']:
- ret = change_app_icon(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 添加启动图操作
- if config['addLauncher']:
- ret = add_launcher(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 添加多图标
- # ret = addMoreIcon(game, sdk, subChannel, config)
- # 复制icon图标到res
- copy_icon(game, sdk, sub_channel, config)
- # 打包lib依赖
- ret = pack_jar(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 修改继承Application
- print('修改继承Application')
- common_utils.change_application(game, sdk, sub_channel, config, 'com.jmhy.sdk.common.JMApplication')
- # sdk脚本处理
- ret = do_sdk_post_script(game, sdk, config)
- if ret:
- return ret
- # 乐变sdk的特殊处理
- ret = game_utils.handle_lebian_sdk_manifest(game, sdk, config)
- if ret:
- return ret
- # 游戏脚本处理
- ret = do_game_post_script(game, sdk, config)
- if ret:
- return ret
- # 游戏独立处理
- ret = do_game_script(game, sdk, config)
- if ret:
- return ret
- # log sdk
- if 'logSdk' in config:
- for log in config['logSdk']:
- ret = add_log_sdk(game, sdk, sub_channel, config, log)
- if ret:
- return ret
- # oaid sdk
- ret = addOaidSdk(game, sdk, sub_channel, config, "1.0.10")
- if ret:
- return ret
- # 生成R文件
- '''ret = generateNewRFile(game, sdk, subChannel, config)
- if ret:
- return ret'''
- # 添加MultiDex支持
- if config['splitDex']:
- ret = split_dex(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 更改版本号
- ret = changeVersion(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 更改HardwareAccelerated属性
- replace_hardware_accelerated(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 回编译
- ret = recomplie(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 对齐apk
- ret = alignApk(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 签名
- ret = apk_signer_apk(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 添加渠道信息
- ret = add_channel(game, sdk, sub_channel, config)
- if ret:
- return ret
- copy_v1_apk_2_out_dir(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 清理产生的中间文件
- if config['clearCache']:
- clearTemp(game, sdk, sub_channel, config)
- endTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- d1 = datetime.datetime.strptime(endTime, '%Y-%m-%d %H:%M:%S')
- d2 = datetime.datetime.strptime(startTime, '%Y-%m-%d %H:%M:%S')
- d = d1 - d2
- print('开始时间:' + startTime)
- print('结束时间:' + endTime)
- print('用时:{}'.format(config_utils.getTime(d.seconds)))
- return 0
- def pack_v2(game, sdk, sub_channel, config):
- # 删除旧代码
- ret = handle_qingshi_old_code(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 删除一些不支持的属性
- ret = remove_no_support_attr(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 删除一些不支持的配置
- ret = fix_un_support_config(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 合并Drawable-v4目录
- ret = merge_drawable_res(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 移除旧sdk资源
- remove_v2_old_res(game, sdk, sub_channel, config)
- # 移除旧abi文件
- remove_v2_old_abi(game, sdk, sub_channel, config)
- # 移除相同的资源
- ret = remove_same_values_res(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 复制res资源
- ret = copy_res(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 合并主文件
- ret = merge_manifest_res(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 替换占位符
- ret = change_placeholders(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 添加meta-data
- ret = add_meta_data(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 增加配置文件
- ret = add_v2_config(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 复制app res资源
- ret = copy_app_res(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 更改包名
- if 'packageName' in config and config['packageName'] != '':
- ret = change_package_name(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 更改app名
- if 'name' in config and config['name'] != '':
- ret = change_app_name(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 更改app icon
- if config['changeIcon']:
- ret = change_app_icon(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 添加启动图操作
- if config['addLauncher']:
- ret = add_launcher(game, sdk, sub_channel, config)
- if ret:
- return ret
- copy_icon(game, sdk, sub_channel, config)
- # 打包lib依赖
- ret = pack_jar(game, sdk, sub_channel, config)
- if ret:
- return ret
- # sdk脚本处理
- ret = do_sdk_post_script(game, sdk, config)
- if ret:
- return ret
- # 乐变sdk的特殊处理
- ret = game_utils.handle_lebian_sdk_manifest(game, sdk, config)
- if ret:
- return ret
- # 游戏脚本处理
- ret = do_game_post_script(game, sdk, config)
- if ret:
- return ret
- # 游戏独立处理
- ret = do_game_script(game, sdk, config)
- if ret:
- return ret
- # log sdk
- if 'logSdk' in config:
- for log in config['logSdk']:
- ret = add_log_sdk(game, sdk, sub_channel, config, log)
- if ret:
- return ret
- # 生成R文件
- '''ret = generateNewRFile(game, sdk, subChannel, config)
- if ret:
- return ret'''
- # 添加MultiDex支持
- if config['splitDex']:
- print('重构sdk split smali')
- decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- manifest = os.path.join(decompile_path, 'AndroidManifest.xml')
- application = xml_utils.get_application_attr(manifest, 'name')
- ret = split_smali(game, sdk, sub_channel, config, application)
- if ret:
- return ret
- # 更改版本号
- ret = changeVersion(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 更改HardwareAccelerated属性
- replace_hardware_accelerated(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 回编译
- ret = recomplie(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 对齐apk
- ret = alignApk(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 签名
- ret = apk_signer_apk(game, sdk, sub_channel, config)
- if ret:
- return ret
- copy_v2_apk_2_out_dir(game, sdk, sub_channel, config)
- if ret:
- return ret
- # 清理产生的中间文件
- if config['clearCache']:
- clearTemp(game, sdk, sub_channel, config)
- endTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- d1 = datetime.datetime.strptime(endTime, '%Y-%m-%d %H:%M:%S')
- d2 = datetime.datetime.strptime(startTime, '%Y-%m-%d %H:%M:%S')
- d = d1 - d2
- print('开始时间:' + startTime)
- print('结束时间:' + endTime)
- print('用时:{}'.format(config_utils.getTime(d.seconds)))
- return 0
- def decomplie(game, sdk, sub_channel, config):
- """
- 解包
- """
- apktoolPath = file_utils.get_apktool_path()
- cacheGameApk = file_utils.get_cache_game_apk(game, config['random'], sdk)
- decompliePath = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- if os.path.exists(decompliePath):
- print('delete decomplie folder...')
- file_utils.delete_folder(decompliePath)
- print('decomplie apk...')
- return file_utils.exec_jar_cmd(apktoolPath, 'd -f "%s" -o "%s"' % (cacheGameApk, decompliePath))
- def remove_old_code(game, sdk, sub_channel, config):
- """
- 删除旧代码
- """
- print(config)
- if config['refactorSdk']:
- return handle_qingshi_old_code(game, sdk, sub_channel, config)
- else:
- return handle_jm_old_code(game, sdk, sub_channel, config)
- def handle_jm_old_code(game, sdk, sub_channel, config):
- decompliePath = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- codePath = os.path.join(decompliePath, 'smali', 'com', 'jmhy', 'sdk')
- # file_utils.deleteFolder(codePath)
- allFiles = []
- allFiles = file_utils.list_files(codePath, allFiles)
- for f in allFiles:
- fpath, fname = os.path.split(f) # 分离文件名和路径
- if fname == 'R.smali' or fname.startswith('R$'):
- continue
- os.remove(f)
- return 0
- def handle_qingshi_old_code(game, sdk, sub_channel, config):
- print('handle_qingshi_old_code')
- decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- qingshi_path = os.path.join(decompile_path, 'smali', 'cn', 'qingshi')
- support_path = os.path.join(decompile_path, 'smali', 'cn', 'yyxx')
- xi_path = os.path.join(decompile_path, 'smali', 'XI')
- ali_path = os.path.join(decompile_path, 'smali', 'com', 'alibaba')
- asus_path = os.path.join(decompile_path, 'smali', 'com', 'asus')
- bun_path = os.path.join(decompile_path, 'smali', 'com', 'bun')
- cmic_path = os.path.join(decompile_path, 'smali', 'com', 'cmic')
- dolin_path = os.path.join(decompile_path, 'smali', 'com', 'dolin')
- huawei_path = os.path.join(decompile_path, 'smali', 'com', 'huawei')
- mobile_path = os.path.join(decompile_path, 'smali', 'com', 'mobile')
- netease_path = os.path.join(decompile_path, 'smali', 'com', 'netease')
- nirvana_path = os.path.join(decompile_path, 'smali', 'com', 'nirvana')
- samsung_path = os.path.join(decompile_path, 'smali', 'com', 'samsung')
- mmkv_path = os.path.join(decompile_path, 'smali', 'com', 'tencent', 'mmkv')
- zui_path = os.path.join(decompile_path, 'smali', 'com', 'zui')
- annotation_path = os.path.join(decompile_path, 'smali', 'android', 'support', 'annotation')
- v4_path = os.path.join(decompile_path, 'smali', 'android', 'support', 'v4')
- file_utils.delete_folder(qingshi_path)
- file_utils.delete_folder(support_path)
- file_utils.delete_folder(xi_path)
- file_utils.delete_folder(ali_path)
- file_utils.delete_folder(asus_path)
- file_utils.delete_folder(bun_path)
- file_utils.delete_folder(cmic_path)
- file_utils.delete_folder(dolin_path)
- file_utils.delete_folder(huawei_path)
- file_utils.delete_folder(mobile_path)
- file_utils.delete_folder(netease_path)
- file_utils.delete_folder(nirvana_path)
- file_utils.delete_folder(samsung_path)
- file_utils.delete_folder(mmkv_path)
- file_utils.delete_folder(zui_path)
- file_utils.delete_folder(qingshi_path)
- file_utils.delete_folder(annotation_path)
- file_utils.delete_folder(v4_path)
- return 0
- def copy_res(game, sdk, sub_channel, config):
- """
- 复制res资源
- """
- # 拷贝sdk资源
- print('copy res...')
- decompliePath = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- sdkPath = file_utils.get_full_sdk_path(sdk)
- resPath = os.path.join(sdkPath, 'res')
- decomplieResPath = file_utils.get_full_path(decompliePath, 'res')
- for d in os.listdir(resPath):
- copy_res_with_type(resPath, decomplieResPath, d)
- # 拷贝assets
- print('copy assets...')
- assetsPath = file_utils.get_full_path(sdkPath, 'assets')
- decomplieAssetsPath = file_utils.get_full_path(decompliePath, 'assets')
- if os.path.exists(assetsPath):
- ret = file_utils.copy_file_all_dir(assetsPath, decomplieAssetsPath)
- if ret:
- return ret
- # 拷贝jniLib
- print('copy jniLibs...')
- jniPath = file_utils.get_full_path(sdkPath, 'jniLibs')
- decomplieJniPath = file_utils.get_full_path(decompliePath, 'lib')
- abiFilters = []
- if os.path.exists(decomplieJniPath):
- for abi in os.listdir(decomplieJniPath):
- # if abi == 'armeabi-v7a' or abi == 'armeabi' or abi == 'arm64-v8a':
- print('append : ' + abi)
- abiFilters.append(abi)
- else:
- abiFilters = ['armeabi-v7a']
- if os.path.exists(jniPath):
- ret = file_utils.copy_file_all_dir(
- jniPath, decomplieJniPath, False, abiFilters)
- if ret:
- return ret
- return 0
- def merge_drawable_res(game, sdk, sub_channel, config):
- """
- 合并Drawable-v4目录
- """
- print('merge drawable path...')
- decompliePath = file_utils.get_decompile_path(
- game, sdk, sub_channel, config['cache'])
- resPath = os.path.join(decompliePath, 'res')
- for path in os.listdir(resPath):
- # print('res path %s' % path)
- if (path.startswith('drawable') or path.startswith('mipmap')) and path.endswith('-v4'):
- # print('merge path %s' % path)
- v4DrawablePath = os.path.join(resPath, path)
- drawablePath = os.path.join(resPath, path[:-3])
- if os.path.exists(drawablePath):
- ret = file_utils.copy_file_all_dir(
- v4DrawablePath, drawablePath, True)
- if ret:
- return ret
- else:
- os.rename(v4DrawablePath, drawablePath)
- return 0
- def remove_v2_old_res(game, sdk, sub_channel, config):
- print('remove v2 sdk old res...')
- decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- res_path = os.path.join(decompile_path, 'res')
- public_xml = os.path.join(res_path, 'values', 'public.xml')
- # 移除public.xml
- if os.path.exists(public_xml):
- print('remove public.xml')
- os.remove(public_xml)
- sub_folders = os.listdir(res_path)
- for folder in sub_folders:
- sub_folder_path = os.path.join(res_path, folder)
- qs_xml_docs = os.listdir(sub_folder_path)
- for xml in qs_xml_docs:
- if xml.startswith('qs_') or xml.startswith('authsdk_'):
- xml_path = os.path.join(sub_folder_path, xml)
- print(xml_path)
- os.remove(xml_path)
- if xml == 'widget_pns_action_bar.xml' or xml == 'widget_pns_optional_viewgroup.xml' or xml == 'widget_pns_protocol.xml':
- xml_path = os.path.join(sub_folder_path, xml)
- print(xml_path)
- os.remove(xml_path)
- def remove_same_values_res(game, sdk, sub_channel, config):
- """
- 移除相同的资源
- """
- # 读取sdk的资源
- print('remove same res...')
- decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- sdk_path = file_utils.get_full_sdk_path(sdk)
- sdk_res_path = os.path.join(sdk_path, 'res')
- print('sdk res path: %s' % sdk_res_path)
- res_list = []
- for path in os.listdir(sdk_res_path):
- print('path: %s' % path)
- if not path.startswith('values'):
- continue
- abs_path = os.path.join(sdk_res_path, path)
- print('abs path: %s' % abs_path)
- for res_file in os.listdir(abs_path):
- if res_file.endswith('.DS_Store'):
- continue
- res_list = xml_utils.read_all_res(os.path.join(abs_path, res_file), res_list)
- if len(res_list) == 0:
- print('no same res found')
- return 0
- # 移除相同的资源
- resPath = os.path.join(decompile_path, 'res')
- for path in os.listdir(resPath):
- if not path.startswith('values'):
- continue
- abs_path = os.path.join(resPath, path)
- for res_file in os.listdir(abs_path):
- xml_utils.remove_same_values_res(os.path.join(abs_path, res_file), res_list)
- return 0
- def merge_manifest_res(game, sdk, sub_channel, config):
- """
- 合并主文件
- """
- print('merge AndroidManifest...')
- decompliePath = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
- sdkPath = file_utils.get_full_sdk_path(sdk)
- libManifest = file_utils.get_full_path(sdkPath, 'manifest.xml')
- return xml_utils.merge_manifest_res(manifest, libManifest)
- def copy_app_res(game, sdk, sub_channel, config):
- """
- 拷贝app的资源,比如app icon、启动图等
- """
- random = config['random']
- channelPath = file_utils.getSubChannelPath(game, sdk, random, sub_channel)
- decompliePath = file_utils.get_decompile_path(
- game, sdk, sub_channel, config['cache'])
- # assets
- print('copy assets...')
- # 适配一剑斩仙
- if game in adaptApp:
- print('适配一剑斩仙...')
- decomplieAssetsPath = file_utils.get_full_path(decompliePath, 'assets')
- skinZipPath = os.path.join(decomplieAssetsPath, 'skin.zip')
- skinPath = os.path.join(decomplieAssetsPath, 'skin')
- if os.path.exists(skinZipPath):
- with zipfile.ZipFile(skinZipPath) as zf:
- zf.extractall(decomplieAssetsPath)
- print('create unzip skin')
- assetsPath = file_utils.get_full_path(channelPath, 'assets')
- decomplieAssetsPath = file_utils.get_full_path(
- decompliePath, 'assets')
- if os.path.exists(assetsPath):
- ret = file_utils.copy_file_all_dir(
- assetsPath, decomplieAssetsPath)
- with zipfile.ZipFile(skinZipPath, 'w') as z:
- for root, dirs, files in os.walk(skinPath):
- for single_file in files:
- filepath = os.path.join(root, single_file)
- print('create zip ---> ' + filepath)
- temPath = 'skin/' + single_file
- z.write(filepath, temPath)
- z.close()
- else:
- print('normal copy assets...')
- assetsPath = file_utils.get_full_path(channelPath, 'assets')
- decomplieAssetsPath = file_utils.get_full_path(
- decompliePath, 'assets')
- if os.path.exists(assetsPath):
- ret = file_utils.copy_file_all_dir(
- assetsPath, decomplieAssetsPath)
- if ret:
- return ret
- else:
- print('normal copy assets...')
- assetsPath = file_utils.get_full_path(channelPath, 'assets')
- decomplieAssetsPath = file_utils.get_full_path(decompliePath, 'assets')
- if os.path.exists(assetsPath):
- ret = file_utils.copy_file_all_dir(assetsPath, decomplieAssetsPath)
- if ret:
- return ret
- # icon
- print('copy icon...')
- ret = copy_app_res_with_type(decompliePath, channelPath, 'icon')
- if ret:
- return ret
- # 启动图
- print('copy splash...')
- ret = copy_app_res_with_type(decompliePath, channelPath, 'splash')
- if ret:
- return ret
- # 其他图片
- print('copy image...')
- ret = copy_app_res_with_type(decompliePath, channelPath, 'image')
- if ret:
- return ret
- return 0
- def copy_app_res_with_type(decompile_path, channel_path, type_name):
- decomplieResPath = os.path.join(decompile_path, 'res')
- iconPath = os.path.join(channel_path, type_name)
- if not os.path.exists(iconPath):
- print('dir "%s" not exists' % iconPath)
- return 0
- for d in os.listdir(iconPath):
- ret = copy_res_with_type(iconPath, decomplieResPath, d)
- if ret:
- return ret
- return 0
- def copy_res_with_type(res_path, decompile_res_path, type_name):
- # aapt的打包目录会带-v4后缀
- resDir = os.path.join(res_path, type_name)
- target = os.path.join(decompile_res_path, type_name)
- targetV4 = os.path.join(decompile_res_path, type_name + '-v4')
- if not os.path.exists(target) and not os.path.exists(targetV4):
- os.makedirs(target)
- return file_utils.copy_file_all_dir(resDir, target, False)
- elif not os.path.exists(target):
- return file_utils.copy_file_all_dir(resDir, targetV4, False)
- else:
- return file_utils.copy_file_all_dir(resDir, target, False)
- def remove_no_support_attr(game, sdk, sub_channel, config):
- """
- 删除一些不支持的属性
- """
- decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- manifest = os.path.join(decompile_path, 'AndroidManifest.xml')
- xml_utils.remove_root_attr(manifest, 'compileSdkVersion')
- xml_utils.remove_root_attr(manifest, 'compileSdkVersionCodename')
- return 0
- def fix_un_support_config(game, sdk, sub_channel, config):
- """
- 删除一些不支持的配置
- """
- # 检查minSdkVersion
- decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- yml = os.path.join(decompile_path, 'apktool.yml')
- min_sdk_version = 21
- file_utils.change_min_sdk_version(yml, min_sdk_version)
- res_path = os.path.join(decompile_path, 'res')
- tag = '-v'
- for res in os.listdir(res_path):
- # print('res = ' + res)
- if res.startswith('values') and tag in res:
- start = res.index(tag)
- version = res[start + len(tag):]
- if not version.isdigit():
- continue
- version = int(version)
- print('version = %d' % version)
- if version < min_sdk_version:
- un_support_path = os.path.join(res_path, res)
- print('un_support_path = ' + un_support_path)
- file_utils.delete_folder(un_support_path)
- print('deleteFolder = ' + un_support_path)
- return 0
- def change_package_name(game, sdk, sub_channel, config):
- """
- 更改包名
- """
- # 全局替换AndroidManifest里面的包名
- newPackageName = config['packageName']
- decompliePath = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
- packageName = xml_utils.get_package_name(manifest)
- config['oldPackageName'] = packageName
- xml_utils.change_package_name(manifest, newPackageName)
- print('change package name %s --> %s' % (packageName, newPackageName))
- return 0
- def change_app_name(game, sdk, sub_channel, config):
- """
- 更改app名
- """
- # 生成string.xml文件
- name = config['name']
- resName = 'common_sdk_name'
- if 'outName' in config:
- resName = resName + '_' + config['outName']
- decompliePath = file_utils.get_decompile_path(
- game, sdk, sub_channel, config['cache'])
- stringFile = os.path.join(decompliePath, 'res',
- 'values', 'sdk_strings_temp.xml')
- content = '<?xml version="1.0" encoding="utf-8"?><resources><string name="%s">%s</string></resources>' % (
- resName, name)
- file_utils.create_file(stringFile, content)
- # 修改主文件的app名的值
- manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
- xml_utils.change_app_name(manifest, '@string/%s' % resName)
- print('change app name %s' % name)
- return 0
- def change_app_icon(game, sdk, subChannel, config):
- '''
- 更改app icon
- '''
- print('change app icon...')
- resName = 'common_sdk_icon'
- decompliePath = file_utils.get_decompile_path(
- game, sdk, subChannel, config['cache'])
- manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
- xml_utils.change_app_icon(manifest, '@mipmap/%s' % resName)
- return 0
- def add_meta_data(game, sdk, subChannel, config):
- '''
- 添加meta-data
- '''
- if 'metaData' not in config:
- return 0
- print('add meta-data...')
- decompliePath = file_utils.get_decompile_path(
- game, sdk, subChannel, config['cache'])
- manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
- xml_utils.addMetaData(manifest, config['metaData'])
- return 0
- def add_v1_config(game, sdk, sub_channel, config):
- """
- 添加config.json
- """
- if 'configData' not in config:
- return 0
- print('add config.json...')
- decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- configJson = os.path.join(decompile_path, 'assets', 'jmhy_config.json')
- jsonText = json.dumps(config['configData'], ensure_ascii=False)
- file_utils.create_file(configJson, jsonText)
- return 0
- def add_v2_config(game, sdk, sub_channel, config):
- """
- 添加config.json
- """
- if 'configData' not in config:
- return 0
- print('add config.json...')
- decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- config_json = os.path.join(decompile_path, 'assets', 'qs_game', 'qs_analytics.json')
- if os.path.exists(config_json):
- os.remove(config_json)
- json_text = json.dumps(config['configData']['channel_sdk_list'], ensure_ascii=False)
- file_utils.create_file(config_json, json_text)
- return 0
- def change_placeholders(game, sdk, sub_channel, config):
- """
- 处理掉占位符
- """
- if 'placeholders' not in config:
- return 0
- decompliePath = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
- placeholders = config['placeholders']
- for placeholder in placeholders:
- oldText = '${%s}' % placeholder
- newText = placeholders[placeholder]
- print('change placeholder %s -> %s' % (oldText, newText))
- file_utils.replace_content(manifest, oldText, newText)
- return 0
- def add_launcher(game, sdk, subChannel, config):
- '''
- 添加启动图
- '''
- # ysdk的特殊处理
- if sdk in ignoreLauncher:
- return 0
- random = config['random']
- channelPath = file_utils.getSubChannelPath(game, sdk, random, subChannel)
- splashPath = os.path.join(channelPath, 'splash')
- if len(os.listdir(splashPath)) == 0:
- print('dir splash is empty')
- return 0
- print('add launcher...')
- decompliePath = file_utils.get_decompile_path(
- game, sdk, subChannel, config['cache'])
- manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
- activity = xml_utils.get_launcher_activity_name(manifest)
- if activity == 'com.jmhy.sdk.template.LauncherActivity':
- print('add launcher already exist...')
- return 1
- # 添加关联资源
- internalPath = file_utils.getFullInternalPath()
- ret = copy_app_res_with_type(decompliePath, internalPath, 'launcher_res')
- if ret:
- return ret
- # 拷贝代码
- print('copy launcher code...')
- codePath = os.path.join(internalPath, 'launcher_code', 'smali')
- smaliPath = file_utils.get_full_path(decompliePath, 'smali')
- ret = file_utils.copy_file_all_dir(codePath, smaliPath)
- if ret:
- return ret
- # 修改主文件信息
- print('change launcher config...')
- orientation = xml_utils.get_screen_orientation(manifest)
- activity = xml_utils.remove_launcher_activity(manifest)
- xml_utils.add_launcher_activity(
- manifest, orientation, 'com.jmhy.sdk.template.LauncherActivity')
- # 修改跳转的
- launcherActivity = os.path.join(
- decompliePath, 'smali', 'com', 'jmhy', 'sdk', 'template', 'LauncherActivity.smali')
- file_utils.replace_content(launcherActivity, '{class}', activity)
- print('change launcher %s to %s' %
- (activity, 'com.jmhy.sdk.template.LauncherActivity'))
- # config['oldLauncher'] = activity
- if 'launcherTime' in config:
- timeHex = formatHex(config['launcherTime'])
- file_utils.replace_content(launcherActivity, '0x0BB8', timeHex)
- return 0
- def addMoreIcon(game, sdk, subChannel, config):
- '''
- 添加多个图标
- '''
- print('add more icon support...')
- decompliePath = file_utils.get_decompile_path(
- game, sdk, subChannel, config['cache'])
- icon = '@mipmap/common_sdk_icon'
- if not config['changeIcon']:
- manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
- icon = xml_utils.get_application_attr(manifest, 'icon')
- switchIcon = icon
- if config['switchIcon']:
- switchIcon = '@mipmap/common_sdk_icon2'
- manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
- return xml_utils.add_more_icon(manifest, icon, switchIcon)
- def copy_icon(game, sdk, subChannel, config):
- '''
- 复制icon到res ,一键登录使用
- '''
- if config['changeIcon']:
- decompliePath = file_utils.get_decompile_path(game, sdk, subChannel, config['cache'])
- decomplieResPath = file_utils.get_full_path(decompliePath, 'res')
- iconPath = os.path.join(decomplieResPath, 'mipmap-xhdpi', 'common_sdk_icon.png')
- desPath = os.path.join(
- decomplieResPath, 'drawable-hdpi', 'jm_cmcc_icon.png')
- file_utils.copy_file(iconPath, desPath)
- else:
- decompliePath = file_utils.get_decompile_path(game, sdk, subChannel, config['cache'])
- decomplieResPath = file_utils.get_full_path(decompliePath, 'res')
- desPath = os.path.join(decomplieResPath, 'drawable-hdpi', 'jm_cmcc_icon.png')
- manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
- icon = xml_utils.get_application_attr(manifest, 'icon')
- tag = icon[1:].split("/")
- if len(tag) < 1:
- return
- hdpi = ['-xhdpi', '-xxhdpi', '-xxxhdpi']
- for h in hdpi:
- p1 = '%s%s' % (tag[0], h)
- png = tag[1] + ".png"
- iconPath = os.path.join(decomplieResPath, p1, png)
- if os.path.exists(iconPath):
- print('iconPath = ' + iconPath)
- file_utils.copy_file(iconPath, desPath)
- break
- def formatHex(millisecond):
- '''
- 将毫秒转为16进制,4位格式
- '''
- timeHex = str(hex(millisecond)).upper()
- timeHex = timeHex[2:]
- formatHex = ''
- if len(timeHex) == 3:
- formatHex = '0x0' + timeHexaddLauncher
- elif len(timeHex) == 4:
- formatHex = '0x' + timeHex
- else:
- formatHex = '0x0BB8'
- return formatHex
- def do_sdk_post_script(game, sdk, config):
- """
- 执行sdk相关特殊处理脚本
- """
- sdkPath = file_utils.get_full_sdk_path(sdk)
- scriptPath = os.path.join(sdkPath, 'script')
- targetScript = os.path.join(scriptPath, 'sdk_script.py')
- if not os.path.exists(targetScript):
- print('sdk_script no exists')
- return 0
- print('do sdk post script...')
- sys.path.append(scriptPath)
- module = importlib.import_module('sdk_script')
- ret = module.execute(game, sdk, config)
- sys.path.remove(scriptPath)
- return ret
- def do_game_post_script(game, sdk, config):
- """
- 执行游戏相关特殊处理脚本
- """
- channelPath = file_utils.get_full_game_path(game)
- scriptPath = os.path.join(channelPath, 'script')
- targetScript = os.path.join(scriptPath, 'game_script.py')
- if not os.path.exists(targetScript):
- print('game_script no exists')
- return 0
- print('doGamePostScript...')
- sys.path.append(scriptPath)
- module = importlib.import_module('game_script')
- ret = module.execute(game, sdk, config)
- sys.path.remove(scriptPath)
- return ret
- def do_game_script(game, sdk, config):
- """
- 执行游戏相关特殊处理脚本
- """
- channelPath = file_utils.get_full_path('game_script', game)
- targetScript = os.path.join(channelPath, 'game_script.py')
- print(targetScript + "--------")
- if not os.path.exists(targetScript):
- print('game_script no exists')
- return 0
- print('doGameScript...')
- sys.path.append(channelPath)
- module = importlib.import_module('game_script')
- ret = module.execute(game, sdk, config)
- sys.path.remove(channelPath)
- return ret
- def add_log_sdk(game, sdk, sub_channel, config, logSdk):
- # 拷贝jniLibs
- decompliePath = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- print('add log sdk, sdk:' + sdk)
- if sdk == 'jm_beta_sdk' or sdk == 'beta_sdk':
- sdk_path = file_utils.get_full_log_sdk_path(logSdk, True)
- elif sdk == 'qingshi':
- sdk_path = file_utils.get_full_log_sdk_v2_path(logSdk)
- else:
- sdk_path = file_utils.get_full_log_sdk_path(logSdk)
- print('copy log jniLibs...')
- jni_path = file_utils.get_full_path(sdk_path, 'jniLibs')
- decomplie_jni_path = file_utils.get_full_path(decompliePath, 'lib')
- abiFilters = []
- if os.path.exists(decomplie_jni_path):
- for abi in os.listdir(decomplie_jni_path):
- if abi == 'armeabi-v7a' or abi == 'x86' or abi == 'x86_64' or abi == 'arm64-v8a':
- abiFilters.append(abi)
- else:
- abiFilters = ['armeabi-v7a']
- if os.path.exists(jni_path):
- ret = file_utils.copy_file_all_dir(jni_path, decomplie_jni_path, False, abiFilters)
- if ret:
- return ret
- print('merge log AndroidManifest...')
- libManifest = file_utils.get_full_path(sdk_path, 'manifest.xml')
- if os.path.exists(libManifest):
- manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
- ret = xml_utils.merge_manifest_res(manifest, libManifest)
- if ret:
- return ret
- change_placeholders(game, sdk, sub_channel, config)
- return pack_log_jar(game, sdk, sub_channel, config, logSdk)
- def addOaidSdk(game, sdk, subChannel, config, oaidVersion):
- sdkPath = file_utils.getFullOaidSDKPath(oaidVersion)
- decompliePath = file_utils.get_decompile_path(
- game, sdk, subChannel, config['cache'])
- # 拷贝assets
- print('copy oaid assets...')
- assetsPath = file_utils.get_full_path(sdkPath, 'assets')
- decomplieAssetsPath = file_utils.get_full_path(decompliePath, 'assets')
- if os.path.exists(assetsPath):
- ret = file_utils.copy_file_all_dir(assetsPath, decomplieAssetsPath)
- if ret:
- return ret
- # 拷贝jniLibs
- print('copy oaid jniLibs...')
- jniPath = file_utils.get_full_path(sdkPath, 'jniLibs')
- decomplieJniPath = file_utils.get_full_path(decompliePath, 'lib')
- abiFilters = []
- if os.path.exists(decomplieJniPath):
- for abi in os.listdir(decomplieJniPath):
- if abi == 'armeabi-v7a' or abi == 'armeabi':
- abiFilters.append(abi)
- else:
- abiFilters = ['armeabi-v7a']
- if os.path.exists(jniPath):
- ret = file_utils.copy_file_all_dir(
- jniPath, decomplieJniPath, False, abiFilters)
- if ret:
- return ret
- print('merge oaid AndroidManifest...')
- libManifest = file_utils.get_full_path(sdkPath, 'manifest.xml')
- if os.path.exists(libManifest):
- manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
- ret = xml_utils.merge_manifest_res(manifest, libManifest)
- if ret:
- return ret
- return packOaidJar(game, sdk, subChannel, config, oaidVersion)
- def generateNewRFile(game, sdk, subChannel, config):
- """
- 生成新的R文件
- """
- decompliePath = file_utils.get_decompile_path(
- game, sdk, subChannel, config['cache'])
- androidPlatforms = file_utils.get_android_compile_tool_path()
- manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
- decomplieResPath = file_utils.get_full_path(decompliePath, 'res')
- compliePath = file_utils.get_full_path(decompliePath, 'gen')
- if not os.path.exists(compliePath):
- os.makedirs(compliePath)
- # 生成R文件
- print('生成R文件 ...')
- if config['aapt2disable']:
- aapt = file_utils.get_aapt_path()
- ret = file_utils.get_exec_permission(aapt)
- if ret:
- return ret
- createRCmd = '"%s" p -f -m -J "%s" -S "%s" -I "%s" -M "%s"' % (
- aapt, compliePath, decomplieResPath, androidPlatforms, manifest)
- ret = file_utils.exec_format_cmd(createRCmd)
- if ret:
- return ret
- else:
- # compile
- aapt = file_utils.get_aapt2_path()
- ret = file_utils.get_exec_permission(aapt)
- if ret:
- return ret
- print('compiled res ...')
- complieResPath = os.path.join(compliePath, 'compiled')
- complieResCmd = '"%s" compile --dir "%s" -o "%s"' % (
- aapt, decomplieResPath, complieResPath)
- file_utils.exec_format_cmd(complieResCmd)
- # unzip
- print('unzip compiled res ...')
- unzipResPath = os.path.join(compliePath, 'aapt2_res')
- with zipfile.ZipFile(complieResPath) as zf:
- zf.extractall(unzipResPath)
- print('create unzip %s' % unzipResPath)
- # link
- print('link res ...')
- outApk = os.path.join(compliePath, 'res.apk')
- linkResCmd = '"%s" link -o "%s" -I "%s" --manifest "%s" --java "%s" --auto-add-overlay' % (
- aapt, outApk, androidPlatforms, manifest, compliePath)
- for filename in os.listdir(unzipResPath):
- linkResCmd += ' %s' % filename
- print('link cmd len is %s' % len(linkResCmd))
- ret = file_utils.exec_format_cmd(linkResCmd, unzipResPath)
- if ret:
- return ret
- # 编译R文件
- print('complie R.java ...')
- packageName = xml_utils.get_package_name(manifest)
- packagePath = file_utils.get_package_path(compliePath, packageName)
- RSourceFile = os.path.join(packagePath, 'R.java')
- complieRCmd = 'javac -source 1.8 -target 1.8 -encoding UTF-8 "%s"' % RSourceFile
- ret = file_utils.exec_format_cmd(complieRCmd)
- if ret:
- return ret
- # 生成dex
- print('dex R.class ...')
- outDex = os.path.join(compliePath, 'classes.dex')
- if config['aapt2disable']:
- dx = file_utils.get_dx_path()
- dexCmd = '--dex --no-warning --output="%s" "%s"' % (
- outDex, compliePath)
- else:
- dx = file_utils.get_d8_path()
- clazz = os.path.join(packagePath, '*.class')
- dexCmd = '--lib "%s" --output "%s" %s' % (
- androidPlatforms, compliePath, clazz)
- ret = file_utils.exec_jar_cmd(dx, dexCmd)
- if ret:
- return ret
- # 反向dex生成smali
- # 存放在out目录
- print('baksmali classes.dex ...')
- baksmaliPath = file_utils.get_baksmali_path()
- outPath = file_utils.get_full_path(decompliePath, 'out')
- ret = file_utils.exec_jar_cmd(
- baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
- if ret:
- return ret
- # 将生成的文件拷贝到目标目录
- print('copy R.smali ...')
- smaliPath = file_utils.get_full_path(decompliePath, 'smali')
- file_utils.copy_file_all_dir(outPath, smaliPath)
- return 0
- def pack_jar(game, sdk, sub_channel, config):
- """
- 打包所有的jar
- """
- split_dex = config['splitDex']
- decompile_path = file_utils.get_decompile_path(
- game, sdk, sub_channel, config['cache'])
- outPath = file_utils.get_full_path(decompile_path, 'gen')
- if not os.path.exists(outPath):
- os.makedirs(outPath)
- if config['aapt2disable']:
- dx = file_utils.get_dx_path()
- dex_cmd = '--dex --no-warning --output="%s"' % outPath
- else:
- dx = file_utils.get_d8_path()
- androidPlatforms = file_utils.get_android_compile_tool_path()
- dex_cmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
- # 找到所有lib依赖
- sdk_path = file_utils.get_full_sdk_path(sdk)
- libs = os.path.join(sdk_path, 'libs')
- libConfig = os.path.join(libs, 'config.json')
- # 存在配置文件
- if os.path.exists(libConfig):
- jsonText = file_utils.read_file(libConfig)
- libConf = json.loads(jsonText)
- if 'libConfig' in config and config['libConfig'] in libConf:
- conf = config['libConfig']
- libList = libConf[conf]
- for jar in libList:
- dex_cmd += ' ' + os.path.join(libs, jar)
- elif 'default' in libConf:
- libList = libConf['default']
- for jar in libList:
- dex_cmd += ' ' + os.path.join(libs, jar)
- else:
- for jar in os.listdir(libs):
- if not jar.endswith('.jar'):
- continue
- dex_cmd += ' ' + os.path.join(libs, jar)
- else:
- for jar in os.listdir(libs):
- if not jar.endswith('.jar'):
- continue
- dex_cmd += ' ' + os.path.join(libs, jar)
- if 'refactorSdk' in config and config['refactorSdk']:
- pass
- else:
- # multidex.jar
- if split_dex:
- print('getMultiDexPath ...')
- dex_cmd += ' ' + file_utils.get_multidex_path()
- # sdk实现类
- dex_cmd += ' ' + os.path.join(sdk_path, '%s.jar' % sdk)
- print('packaging all jar ...')
- ret = file_utils.exec_jar_cmd(dx, dex_cmd)
- if ret:
- return ret
- # 反向dex生成smali
- # 存放在out目录
- print('baksmali classes.dex ...')
- outDex = os.path.join(outPath, 'classes.dex')
- baksmaliPath = file_utils.get_baksmali_path()
- outPath = file_utils.get_full_path(decompile_path, 'out')
- ret = file_utils.exec_jar_cmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
- if ret:
- return ret
- # 将生成的文件拷贝到目标目录
- print('copy all smali ...')
- smaliPath = file_utils.get_full_path(decompile_path, 'smali')
- ret = file_utils.copy_file_all_dir(outPath, smaliPath, True)
- if ret:
- return ret
- return 0
- def pack_log_jar(game, sdk, sub_channel, config, log_sdk):
- """
- 打包Log jar
- """
- decompliePath = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- outPath = file_utils.get_full_path(decompliePath, 'gen')
- if not os.path.exists(outPath):
- os.makedirs(outPath)
- if config['aapt2disable']:
- dx = file_utils.get_dx_path()
- dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
- else:
- dx = file_utils.get_d8_path()
- androidPlatforms = file_utils.get_android_compile_tool_path()
- dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
- # 找到所有lib依赖
- if sdk == 'jm_beta_sdk' or sdk == 'beta_sdk':
- sdk_path = file_utils.get_full_log_sdk_path(log_sdk, True)
- elif sdk == 'qingshi':
- sdk_path = file_utils.get_full_log_sdk_v2_path(log_sdk)
- else:
- sdk_path = file_utils.get_full_log_sdk_path(log_sdk)
- libs = os.path.join(sdk_path, 'libs')
- lib_config = os.path.join(libs, 'config.json')
- # 存在配置文件
- if os.path.exists(lib_config):
- json_text = file_utils.read_file(lib_config)
- lib_list = json.loads(json_text)
- for jar in lib_list:
- if not jar.endswith('.jar'):
- continue
- dexCmd += ' ' + os.path.join(libs, jar)
- else:
- for jar in os.listdir(libs):
- if not jar.endswith('.jar'):
- continue
- dexCmd += ' ' + os.path.join(libs, jar)
- # sdk实现类
- print('packaging all log jar ...')
- if sdk != 'qingshi':
- dexCmd += ' ' + os.path.join(sdk_path, '%s.jar' % log_sdk)
- ret = file_utils.exec_jar_cmd(dx, dexCmd)
- if ret:
- return ret
- # 反向dex生成smali
- # 存放在out目录
- print('baksmali classes.dex ...')
- outDex = os.path.join(outPath, 'classes.dex')
- baksmaliPath = file_utils.get_baksmali_path()
- outPath = file_utils.get_full_path(decompliePath, 'out')
- ret = file_utils.exec_jar_cmd(
- baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
- if ret:
- return ret
- # 将生成的文件拷贝到目标目录
- print('copy all log smali ...')
- smaliPath = file_utils.get_full_path(decompliePath, 'smali')
- ret = file_utils.copy_file_all_dir(outPath, smaliPath, True)
- if ret:
- return ret
- return 0
- def packOaidJar(game, sdk, subChannel, config, oaidVerion):
- '''
- 打包oaid jar
- '''
- decompliePath = file_utils.get_decompile_path(
- game, sdk, subChannel, config['cache'])
- outPath = file_utils.get_full_path(decompliePath, 'gen')
- if not os.path.exists(outPath):
- os.makedirs(outPath)
- if config['aapt2disable']:
- dx = file_utils.get_dx_path()
- dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
- else:
- dx = file_utils.get_d8_path()
- androidPlatforms = file_utils.get_android_compile_tool_path()
- dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
- # 找到所有lib依赖
- sdkPath = file_utils.getFullOaidSDKPath(oaidVerion)
- libs = os.path.join(sdkPath, 'libs')
- libConfig = os.path.join(libs, 'config.json')
- # 存在配置文件
- # if os.path.exists(libConfig):
- # jsonText = file_utils.readFile(libConfig)
- # libList = json.loads(jsonText)
- # for jar in libList:
- # if not jar.endswith('.jar'):
- # continue
- # dexCmd += ' ' + os.path.join(libs, jar)
- # else:
- # for jar in os.listdir(libs):
- # if not jar.endswith('.jar'):
- # continue
- # dexCmd += ' ' + os.path.join(libs, jar)
- # sdk实现类
- print('packageing oaid jar ...')
- dexCmd += ' ' + os.path.join(libs, 'miit_mdid_%s.jar' % oaidVerion)
- ret = file_utils.exec_jar_cmd(dx, dexCmd)
- if ret:
- return ret
- # 反向dex生成smali
- # 存放在out目录
- print('baksmali classes.dex ...')
- outDex = os.path.join(outPath, 'classes.dex')
- baksmaliPath = file_utils.get_baksmali_path()
- outPath = file_utils.get_full_path(decompliePath, 'out')
- ret = file_utils.exec_jar_cmd(
- baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
- if ret:
- return ret
- # 将生成的文件拷贝到目标目录
- print('copy all log smali ...')
- smaliPath = file_utils.get_full_path(decompliePath, 'smali')
- ret = file_utils.copy_file_all_dir(outPath, smaliPath, True)
- if ret:
- return ret
- return 0
- def split_dex(game, sdk, sub_channel, config):
- """
- 分割dex
- """
- # 判断是否已经存在application
- # 存在,则往原application添加内容
- # 不存在,则拷贝一个默认的android.support.multidex.MultiDexApplication
- print('add MultiDex support...')
- decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- manifest = os.path.join(decompile_path, 'AndroidManifest.xml')
- application = xml_utils.get_application_attr(manifest, 'name')
- if application is None:
- ret = xml_utils.change_application_attr(manifest, 'name', 'android.support.multidex.MultiDexApplication')
- if ret:
- return ret
- else:
- smaliPath = os.path.join(decompile_path, 'smali')
- application_file = file_utils.get_package_path(smaliPath, application)
- application_file += '.smali'
- ret = change_application_dex(application_file)
- if ret:
- return ret
- return split_smali(game, sdk, sub_channel, config, application)
- def change_application_dex(file):
- """
- 修改application的smali文件,增加MultiDex操作
- """
- index = file_utils.get_application_smali_index(file)
- file_utils.insert_application_smali(file, index)
- return 0
- def split_smali(game, sdk, sub_channel, config, application):
- """
- 如果函数上限超过限制,自动拆分smali,以便生成多个dex文件
- """
- print('splitSmali...')
- decompliePath = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- smaliPath = os.path.join(decompliePath, 'smali')
- appPackage = None
- if application:
- appPackage = application[:application.rfind('.')]
- appPackage = appPackage.replace('.', '/')
- allFiles = []
- allFiles = file_utils.list_files(smaliPath, allFiles)
- # print('file count is %d' % len(allFiles))
- # maxFuncNum = 65535
- # 留一点空间,防止计算误差
- maxFuncNum = 64000
- currFucNum = 0
- totalFucNum = 0
- currDexIndex = 1
- allRefs = []
- # 保证Application等类在第一个classex.dex文件中
- for f in allFiles:
- f = f.replace('\\', '/')
- if (appPackage and appPackage in f) or '/android/support/multidex' in f:
- currFucNum += smali_utils.get_smali_method_count(f, allRefs)
- totalFucNum = currFucNum
- for f in allFiles:
- f = f.replace('\\', '/')
- if not f.endswith('.smali'):
- continue
- if (appPackage and appPackage in f) or '/android/support/multidex' in f:
- continue
- thisFucNum = smali_utils.get_smali_method_count(f, allRefs)
- totalFucNum += thisFucNum
- # print('%d # %d ==> %s' % (thisFucNum, currDexIndex, f))
- # print('totalFucNum is %d' % totalFucNum)
- if currFucNum + thisFucNum >= maxFuncNum:
- currFucNum = thisFucNum
- currDexIndex += 1
- newDexPath = os.path.join(
- decompliePath, 'smali_classes%d' % currDexIndex)
- os.makedirs(newDexPath)
- else:
- currFucNum += thisFucNum
- if currDexIndex > 1:
- newDexPath = os.path.join(
- decompliePath, 'smali_classes%d' % currDexIndex)
- targetFile = newDexPath + f[len(smaliPath):]
- file_utils.copy_file(f, targetFile, True)
- return 0
- def changeVersion(game, sdk, sub_channel, config):
- """
- 更改版本号
- """
- decompliePath = file_utils.get_decompile_path(
- game, sdk, sub_channel, config['cache'])
- yml = os.path.join(decompliePath, 'apktool.yml')
- versionCode = None
- versionName = None
- targetSdkVersion = None
- if 'versionCode' in config:
- versionCode = config['versionCode']
- if 'versionName' in config:
- versionName = config['versionName']
- if 'targetSdkVersion' in config:
- targetSdkVersion = config['targetSdkVersion']
- else:
- targetSdkVersion = 26
- print('changeVersion versionCode=%s,versionName=%s,targetSdkVersion=%s' %
- (versionCode, versionName, targetSdkVersion))
- return file_utils.changeVersion(yml, versionCode, versionName, targetSdkVersion)
- def recomplie(game, sdk, subChannel, config):
- '''
- 回编译
- '''
- print('recomplie apk...')
- apktoolPath = file_utils.get_apktool_path()
- decompliePath = file_utils.get_decompile_path(
- game, sdk, subChannel, config['cache'])
- outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
- useAppt2 = ' --use-aapt2'
- if config['aapt2disable']:
- useAppt2 = ''
- return file_utils.exec_jar_cmd(apktoolPath, 'b -f "%s" -o "%s"%s' % (decompliePath, outApk, useAppt2))
- def alignApk(game, sdk, subChannel, config):
- '''
- 对齐apk
- '''
- print('align apk...')
- outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
- alignApk = file_utils.getAlignApkPath(
- game, sdk, subChannel, config['cache'])
- alignapkTool = file_utils.get_zipalign_path()
- if os.path.exists(alignApk):
- os.remove(alignApk)
- ret = file_utils.get_exec_permission(alignapkTool)
- if ret:
- return ret
- # zipalign.exe -v -p 4 input.apk output.apk
- return file_utils.exec_format_cmd('"%s" -f -p 4 "%s" "%s"' % (alignapkTool, outApk, alignApk))
- def apk_signer_apk(game, sdk, sub_channel, config):
- """
- 签名apk
- """
- print('sign apk...')
- print('game = %s, sdk = %s, subChannel = %s, ...' %
- (game, sdk, sub_channel))
- path = os.path.join(file_utils.get_current_path(), 'keystore', 'key.json')
- jsonText = file_utils.read_file(path)
- signConfig = json.loads(jsonText)
- keystore = {}
- for key in signConfig.keys():
- print(key)
- if game.find(key) > -1 or game == key:
- if sdk in signConfig[key]:
- keystore = signConfig[key][sdk]
- break
- else:
- keystore = signConfig['default']
- else:
- keystore = signConfig['default']
- # if game in signConfig:
- # if sdk in signConfig[game]:
- # keystore = signConfig[game][sdk]
- # else:
- # keystore = signConfig['default']
- # else:
- # keystore = signConfig['default']
- print('storeFile is "%s"' % keystore['storeFile'])
- apksigner = file_utils.get_apksigner_path()
- alignApk = file_utils.getAlignApkPath(
- game, sdk, sub_channel, config['cache'])
- signedApk = file_utils.get_signed_apk_path(
- game, sdk, sub_channel, config['cache'])
- storeFile = os.path.join(file_utils.get_current_path(),
- 'keystore', keystore['storeFile'])
- # java -jar apksigner.jar sign --ks key.jks --ks-key-alias releasekey --ks-pass pass:pp123456 --key-pass pass:pp123456 --out output.apk input.apk
- v2disable = ''
- if 'v2disable' in config and config['v2disable']:
- v2disable = ' --v2-signing-enabled=false'
- return file_utils.exec_jar_cmd(apksigner,
- 'sign%s --ks "%s" --ks-key-alias %s --ks-pass pass:%s --key-pass pass:%s --out "%s" "%s"' % (
- v2disable, storeFile, keystore['keyAlias'], keystore['storePassword'],
- keystore['keyPassword'], signedApk, alignApk))
- def add_channel(game, sdk, sub_channel, config):
- """
- 添加渠道信息
- """
- if 'v2disable' in config and config['v2disable']:
- return 0
- walle = file_utils.getWallePath()
- signedApk = file_utils.get_signed_apk_path(game, sdk, sub_channel, config['cache'])
- walleApk = file_utils.getWalleApkPath(game, sdk, sub_channel, config['cache'])
- properties = config['properties']
- appid = ''
- appkey = ''
- host = ''
- if 'appid' in properties:
- appid = properties['appid']
- if 'appkey' in properties:
- appkey = properties['appkey']
- if 'host' in properties:
- host = properties['host']
- return file_utils.exec_jar_cmd(walle, 'put -e version=%s,agent=%s,appid=%s,appkey=%s,host=%s "%s" "%s"' % (
- config_utils.getDate(), properties['agent'], appid, appkey, host, signedApk, walleApk))
- def clearTemp(game, sdk, sub_channel, config):
- """
- 清空中间产生的文件
- """
- print('clear temp...')
- targetApkPath = file_utils.getTargetApkPath(game, sdk, config['cache'])
- if os.path.exists(targetApkPath):
- file_utils.delete_folder(targetApkPath)
- decompliePath = file_utils.get_decompile_path(
- game, sdk, sub_channel, config['cache'])
- if os.path.exists(decompliePath):
- file_utils.delete_folder(decompliePath)
- random = config['random']
- channelPath = file_utils.getChannelPath(game, random, sdk)
- if os.path.exists(channelPath):
- file_utils.delete_folder(channelPath)
- print('clear temp end')
- def packConsoleInput():
- '''
- 控制台打包
- '''
- if len(sys.argv) < 3:
- print('argument is missing')
- return 1
- # 校验参数
- game = sys.argv[1]
- sdk = sys.argv[2]
- # 可选参数,没有则默认打全部渠道
- subChannel = None
- if len(sys.argv) > 3:
- subChannel = sys.argv[3]
- return packConsole(game, sdk, subChannel)
- def packConsole(game, sdk, config, subChannel):
- """
- 控制台打包
- """
- cache_game_apk_path = file_utils.get_cache_game_apk(game, config['random'], sdk)
- print('cache game apk path %s' % cache_game_apk_path)
- if not os.path.exists(cache_game_apk_path):
- print('game "%s" not exists' % game)
- return 1
- if not os.path.exists(file_utils.get_full_sdk_path(sdk)):
- print('sdk "%s" not exists' % sdk)
- return 1
- global startTime
- startTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- # 读取配置
- random = config['random']
- channelPath = file_utils.getChannelPath(game, random, sdk)
- configPath = os.path.join(channelPath, 'config.json')
- if not os.path.exists(configPath):
- print('%s not exists' % configPath)
- return 1
- jsonText = file_utils.read_file(configPath)
- config = json.loads(jsonText)
- # 检查参数
- if not config_utils.checkConfig(config):
- return 1
- # 处理参数
- config_utils.replaceArgs(config)
- successCount = 0
- failureCount = 0
- if type(config) == dict:
- if subChannel is None or config['subChannel'] == subChannel:
- ret = pack(game, sdk, config)
- if ret:
- failureCount += 1
- else:
- successCount += 1
- else:
- print('subChannel "%s" no found' % subChannel)
- return 1
- elif type(config) == list:
- found = False
- for itemConfig in config:
- if subChannel is None or itemConfig['subChannel'] == subChannel:
- found = True
- ret = pack(game, sdk, itemConfig)
- if ret:
- failureCount += 1
- else:
- successCount += 1
- if not found:
- print('subChannel "%s" no found' % subChannel)
- return 1
- print('success %d, failure %d' % (successCount, failureCount))
- subChannelPath = os.path.join(channelPath, subChannel)
- print('------subChannelPath 目录清空:%s -------' % subChannelPath)
- file_utils.delete_folder(subChannelPath)
- return 0
- def formatXml(game, sdk, subChannel, config):
- decompliePath = file_utils.get_decompile_path(
- game, sdk, subChannel, config['cache'])
- manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
- return xml_utils.formatXml(manifest)
- def copy_v1_apk_2_out_dir(game, sdk, sub_channel, config):
- walleApk = file_utils.getWalleApkPath(game, sdk, sub_channel, config['cache'])
- releaseApkPath = ""
- if 'outName' in config and 'outPath' in config:
- if not os.path.exists(config['outPath']):
- os.makedirs(config['outPath'])
- releaseApkPath = os.path.join(config['outPath'], config['outName'] + '.apk')
- elif 'outName' in config:
- releaseApkPath = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
- print('------生成正式包路径 %s -------' % releaseApkPath)
- file_utils.copy_file(walleApk, releaseApkPath)
- def copy_v2_apk_2_out_dir(game, sdk, sub_channel, config):
- signed_apk = file_utils.get_signed_apk_path(game, sdk, sub_channel, config['cache'])
- release_apk_path = ""
- if 'outName' in config and 'outPath' in config:
- if not os.path.exists(config['outPath']):
- os.makedirs(config['outPath'])
- release_apk_path = os.path.join(config['outPath'], config['outName'] + '.apk')
- elif 'outName' in config:
- release_apk_path = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
- print('------生成正式包路径 %s -------' % release_apk_path)
- file_utils.copy_file(signed_apk, release_apk_path)
- def replace_hardware_accelerated(game, sdk, subChannel, config):
- decompliePath = file_utils.get_decompile_path(game, sdk, subChannel, config['cache'])
- manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
- lines = open(manifest).readlines()
- fp = open(manifest, "w")
- isReplaced = False
- for l in lines:
- if isReplaced == False and l.find("android:hardwareAccelerated=") >= 0:
- isReplace = True
- l = re.sub("android:hardwareAccelerated=\"false\"",
- "android:hardwareAccelerated=\"true\"", l)
- fp.write(l)
- fp.close()
- pass
- def remove_v2_old_abi(game, sdk, sub_channel, config):
- print('remove v2 old abi...')
- decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
- lib_path = os.path.join(decompile_path, 'lib')
- abi_folders = os.listdir(lib_path)
- for abi_folder in abi_folders:
- abi_folder_path = os.path.join(lib_path, abi_folder)
- abi_files = os.listdir(abi_folder_path)
- for abi in abi_files:
- if abi == 'libalicomphonenumberauthsdk_core.so':
- abi_path = os.path.join(abi_folder_path, abi)
- print(abi_path)
- os.remove(abi_path)
- if abi == 'libauth_number_product-2.12.1-log-online-standard-release_alijtca_plus.so':
- abi_path = os.path.join(abi_folder_path, abi)
- print(abi_path)
- os.remove(abi_path)
- if abi == 'libdolin-zap.so':
- abi_path = os.path.join(abi_folder_path, abi)
- print(abi_path)
- os.remove(abi_path)
- if abi == 'libmmkv.so':
- abi_path = os.path.join(abi_folder_path, abi)
- print(abi_path)
- os.remove(abi_path)
- if abi == 'libqsgamesdk.so':
- abi_path = os.path.join(abi_folder_path, abi)
- print(abi_path)
- os.remove(abi_path)
- if abi == 'libsecsdk.so':
- abi_path = os.path.join(abi_folder_path, abi)
- print(abi_path)
- os.remove(abi_path)
- def openFile(file, mode):
- return open(file, mode, encoding='UTF-8')
- def is_refactor_sdk(config) -> bool:
- return 'refactorSdk' in config and config['refactorSdk']
|