package_utils.py 65 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910
  1. # 安卓游戏打包脚本
  2. # 1.用apktool解包
  3. # 2.复制res资源、assets资源、jniLib资源
  4. # 3.修改包名、app名、渠道文件
  5. # 4.添加app icon、合并AndroidManifest文件
  6. # 5.添加app启动图,修改AndroidManifest文件
  7. # 6.生成新的R文件
  8. # 7.将新的R文件编译,生成dex,再用baksmali生成smali,替换旧的R文件
  9. # 8.将jar资源打包成dex,再用baksmali生成smali,拷贝到smali目录下
  10. # 9.统计方法量,并分割dex(将smali文件拷贝到目录smali_classes2)
  11. # 10.用apktool回包
  12. # 11.重新签名
  13. import datetime
  14. import importlib
  15. import json
  16. import os
  17. import os.path
  18. import re
  19. import sys
  20. import uuid
  21. import zipfile
  22. import common_utils
  23. import config_utils
  24. import file_utils
  25. import game_utils
  26. import smali_utils
  27. import xml_utils
  28. ignoreLauncher = ['jm_ysdk', 'jm_yijie', 'jm_quick',
  29. 'jm_beiyu', 'jm_xq_jrtt', 'jm_zy_ysdk']
  30. adaptApp = ['yjzx']
  31. startTime = ''
  32. def pack(game, sdk, config):
  33. config['cache'] = uuid.uuid1()
  34. sub_channel = config['subChannel']
  35. print('game = %s, sdk = %s, subChannel = %s, ...' % (game, sdk, sub_channel))
  36. # 解包
  37. print('解包')
  38. ret = decomplie(game, sdk, sub_channel, config)
  39. if ret:
  40. return ret
  41. if is_refactor_sdk(config):
  42. return pack_v2(game, sdk, sub_channel, config)
  43. else:
  44. return pack_v1(game, sdk, sub_channel, config)
  45. def pack_v1(game, sdk, sub_channel, config):
  46. # 删除旧代码
  47. print('删除旧代码')
  48. ret = handle_jm_old_code(game, sdk, sub_channel, config)
  49. if ret:
  50. return ret
  51. # 删除一些不支持的属性
  52. print('删除一些不支持的属性')
  53. ret = remove_no_support_attr(game, sdk, sub_channel, config)
  54. if ret:
  55. return ret
  56. # 删除一些不支持的配置
  57. print('删除一些不支持的配置')
  58. ret = fix_un_support_config(game, sdk, sub_channel, config)
  59. if ret:
  60. return ret
  61. # 合并Drawable-v4目录
  62. ret = merge_drawable_res(game, sdk, sub_channel, config)
  63. if ret:
  64. return ret
  65. # 移除相同的资源
  66. ret = remove_same_values_res(game, sdk, sub_channel, config)
  67. if ret:
  68. return ret
  69. # 复制res资源
  70. ret = copy_res(game, sdk, sub_channel, config)
  71. if ret:
  72. return ret
  73. # 合并主文件
  74. ret = merge_manifest_res(game, sdk, sub_channel, config)
  75. if ret:
  76. return ret
  77. # 替换占位符
  78. ret = change_placeholders(game, sdk, sub_channel, config)
  79. if ret:
  80. return ret
  81. # 添加meta-data
  82. ret = add_meta_data(game, sdk, sub_channel, config)
  83. if ret:
  84. return ret
  85. # 增加配置文件
  86. ret = add_v1_config(game, sdk, sub_channel, config)
  87. if ret:
  88. return ret
  89. # 复制app res资源
  90. ret = copy_app_res(game, sdk, sub_channel, config)
  91. if ret:
  92. return ret
  93. # 更改包名
  94. if 'packageName' in config and config['packageName'] != '':
  95. ret = change_package_name(game, sdk, sub_channel, config)
  96. if ret:
  97. return ret
  98. # 更改app名
  99. if 'name' in config and config['name'] != '':
  100. ret = change_app_name(game, sdk, sub_channel, config)
  101. if ret:
  102. return ret
  103. # 更改app icon
  104. if config['changeIcon']:
  105. ret = change_app_icon(game, sdk, sub_channel, config)
  106. if ret:
  107. return ret
  108. # 添加启动图操作
  109. if config['addLauncher']:
  110. ret = add_launcher(game, sdk, sub_channel, config)
  111. if ret:
  112. return ret
  113. # 添加多图标
  114. # ret = addMoreIcon(game, sdk, subChannel, config)
  115. # 复制icon图标到res
  116. copy_icon(game, sdk, sub_channel, config)
  117. # 打包lib依赖
  118. ret = pack_jar(game, sdk, sub_channel, config)
  119. if ret:
  120. return ret
  121. # 修改继承Application
  122. print('修改继承Application')
  123. common_utils.change_application(game, sdk, sub_channel, config, 'com.jmhy.sdk.common.JMApplication')
  124. # sdk脚本处理
  125. ret = do_sdk_post_script(game, sdk, config)
  126. if ret:
  127. return ret
  128. # 乐变sdk的特殊处理
  129. ret = game_utils.handle_lebian_sdk_manifest(game, sdk, config)
  130. if ret:
  131. return ret
  132. # 游戏脚本处理
  133. ret = do_game_post_script(game, sdk, config)
  134. if ret:
  135. return ret
  136. # 游戏独立处理
  137. ret = do_game_script(game, sdk, config)
  138. if ret:
  139. return ret
  140. # log sdk
  141. if 'logSdk' in config:
  142. for log in config['logSdk']:
  143. ret = add_log_sdk(game, sdk, sub_channel, config, log)
  144. if ret:
  145. return ret
  146. # oaid sdk
  147. ret = addOaidSdk(game, sdk, sub_channel, config, "1.0.10")
  148. if ret:
  149. return ret
  150. # 生成R文件
  151. '''ret = generateNewRFile(game, sdk, subChannel, config)
  152. if ret:
  153. return ret'''
  154. # 添加MultiDex支持
  155. if config['splitDex']:
  156. ret = split_dex(game, sdk, sub_channel, config)
  157. if ret:
  158. return ret
  159. # 更改版本号
  160. ret = changeVersion(game, sdk, sub_channel, config)
  161. if ret:
  162. return ret
  163. # 更改HardwareAccelerated属性
  164. replace_hardware_accelerated(game, sdk, sub_channel, config)
  165. if ret:
  166. return ret
  167. # 回编译
  168. ret = recomplie(game, sdk, sub_channel, config)
  169. if ret:
  170. return ret
  171. # 对齐apk
  172. ret = alignApk(game, sdk, sub_channel, config)
  173. if ret:
  174. return ret
  175. # 签名
  176. ret = apk_signer_apk(game, sdk, sub_channel, config)
  177. if ret:
  178. return ret
  179. # 添加渠道信息
  180. ret = add_channel(game, sdk, sub_channel, config)
  181. if ret:
  182. return ret
  183. copy_v1_apk_2_out_dir(game, sdk, sub_channel, config)
  184. if ret:
  185. return ret
  186. # 清理产生的中间文件
  187. if config['clearCache']:
  188. clearTemp(game, sdk, sub_channel, config)
  189. endTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  190. d1 = datetime.datetime.strptime(endTime, '%Y-%m-%d %H:%M:%S')
  191. d2 = datetime.datetime.strptime(startTime, '%Y-%m-%d %H:%M:%S')
  192. d = d1 - d2
  193. print('开始时间:' + startTime)
  194. print('结束时间:' + endTime)
  195. print('用时:{}'.format(config_utils.getTime(d.seconds)))
  196. return 0
  197. def pack_v2(game, sdk, sub_channel, config):
  198. # 删除旧代码
  199. ret = handle_qingshi_old_code(game, sdk, sub_channel, config)
  200. if ret:
  201. return ret
  202. # 删除一些不支持的属性
  203. ret = remove_no_support_attr(game, sdk, sub_channel, config)
  204. if ret:
  205. return ret
  206. # 删除一些不支持的配置
  207. ret = fix_un_support_config(game, sdk, sub_channel, config)
  208. if ret:
  209. return ret
  210. # 合并Drawable-v4目录
  211. ret = merge_drawable_res(game, sdk, sub_channel, config)
  212. if ret:
  213. return ret
  214. # 移除旧sdk资源
  215. remove_v2_old_res(game, sdk, sub_channel, config)
  216. # 移除旧abi文件
  217. remove_v2_old_abi(game, sdk, sub_channel, config)
  218. # 移除相同的资源
  219. ret = remove_same_values_res(game, sdk, sub_channel, config)
  220. if ret:
  221. return ret
  222. # 复制res资源
  223. ret = copy_res(game, sdk, sub_channel, config)
  224. if ret:
  225. return ret
  226. # 合并主文件
  227. ret = merge_manifest_res(game, sdk, sub_channel, config)
  228. if ret:
  229. return ret
  230. # 替换占位符
  231. ret = change_placeholders(game, sdk, sub_channel, config)
  232. if ret:
  233. return ret
  234. # 添加meta-data
  235. ret = add_meta_data(game, sdk, sub_channel, config)
  236. if ret:
  237. return ret
  238. # 增加配置文件
  239. ret = add_v2_config(game, sdk, sub_channel, config)
  240. if ret:
  241. return ret
  242. # 复制app res资源
  243. ret = copy_app_res(game, sdk, sub_channel, config)
  244. if ret:
  245. return ret
  246. # 更改包名
  247. if 'packageName' in config and config['packageName'] != '':
  248. ret = change_package_name(game, sdk, sub_channel, config)
  249. if ret:
  250. return ret
  251. # 更改app名
  252. if 'name' in config and config['name'] != '':
  253. ret = change_app_name(game, sdk, sub_channel, config)
  254. if ret:
  255. return ret
  256. # 更改app icon
  257. if config['changeIcon']:
  258. ret = change_app_icon(game, sdk, sub_channel, config)
  259. if ret:
  260. return ret
  261. # 添加启动图操作
  262. if config['addLauncher']:
  263. ret = add_launcher(game, sdk, sub_channel, config)
  264. if ret:
  265. return ret
  266. copy_icon(game, sdk, sub_channel, config)
  267. # 打包lib依赖
  268. ret = pack_jar(game, sdk, sub_channel, config)
  269. if ret:
  270. return ret
  271. # sdk脚本处理
  272. ret = do_sdk_post_script(game, sdk, config)
  273. if ret:
  274. return ret
  275. # 乐变sdk的特殊处理
  276. ret = game_utils.handle_lebian_sdk_manifest(game, sdk, config)
  277. if ret:
  278. return ret
  279. # 游戏脚本处理
  280. ret = do_game_post_script(game, sdk, config)
  281. if ret:
  282. return ret
  283. # 游戏独立处理
  284. ret = do_game_script(game, sdk, config)
  285. if ret:
  286. return ret
  287. # log sdk
  288. if 'logSdk' in config:
  289. for log in config['logSdk']:
  290. ret = add_log_sdk(game, sdk, sub_channel, config, log)
  291. if ret:
  292. return ret
  293. # 生成R文件
  294. '''ret = generateNewRFile(game, sdk, subChannel, config)
  295. if ret:
  296. return ret'''
  297. # 添加MultiDex支持
  298. if config['splitDex']:
  299. print('重构sdk split smali')
  300. decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  301. manifest = os.path.join(decompile_path, 'AndroidManifest.xml')
  302. application = xml_utils.get_application_attr(manifest, 'name')
  303. ret = split_smali(game, sdk, sub_channel, config, application)
  304. if ret:
  305. return ret
  306. # 更改版本号
  307. ret = changeVersion(game, sdk, sub_channel, config)
  308. if ret:
  309. return ret
  310. # 更改HardwareAccelerated属性
  311. replace_hardware_accelerated(game, sdk, sub_channel, config)
  312. if ret:
  313. return ret
  314. # 回编译
  315. ret = recomplie(game, sdk, sub_channel, config)
  316. if ret:
  317. return ret
  318. # 对齐apk
  319. ret = alignApk(game, sdk, sub_channel, config)
  320. if ret:
  321. return ret
  322. # 签名
  323. ret = apk_signer_apk(game, sdk, sub_channel, config)
  324. if ret:
  325. return ret
  326. copy_v2_apk_2_out_dir(game, sdk, sub_channel, config)
  327. if ret:
  328. return ret
  329. # 清理产生的中间文件
  330. if config['clearCache']:
  331. clearTemp(game, sdk, sub_channel, config)
  332. endTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  333. d1 = datetime.datetime.strptime(endTime, '%Y-%m-%d %H:%M:%S')
  334. d2 = datetime.datetime.strptime(startTime, '%Y-%m-%d %H:%M:%S')
  335. d = d1 - d2
  336. print('开始时间:' + startTime)
  337. print('结束时间:' + endTime)
  338. print('用时:{}'.format(config_utils.getTime(d.seconds)))
  339. return 0
  340. def decomplie(game, sdk, sub_channel, config):
  341. """
  342. 解包
  343. """
  344. apktoolPath = file_utils.get_apktool_path()
  345. cacheGameApk = file_utils.get_cache_game_apk(game, config['random'], sdk)
  346. decompliePath = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  347. if os.path.exists(decompliePath):
  348. print('delete decomplie folder...')
  349. file_utils.delete_folder(decompliePath)
  350. print('decomplie apk...')
  351. return file_utils.exec_jar_cmd(apktoolPath, 'd -f "%s" -o "%s"' % (cacheGameApk, decompliePath))
  352. def remove_old_code(game, sdk, sub_channel, config):
  353. """
  354. 删除旧代码
  355. """
  356. print(config)
  357. if config['refactorSdk']:
  358. return handle_qingshi_old_code(game, sdk, sub_channel, config)
  359. else:
  360. return handle_jm_old_code(game, sdk, sub_channel, config)
  361. def handle_jm_old_code(game, sdk, sub_channel, config):
  362. decompliePath = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  363. codePath = os.path.join(decompliePath, 'smali', 'com', 'jmhy', 'sdk')
  364. # file_utils.deleteFolder(codePath)
  365. allFiles = []
  366. allFiles = file_utils.list_files(codePath, allFiles)
  367. for f in allFiles:
  368. fpath, fname = os.path.split(f) # 分离文件名和路径
  369. if fname == 'R.smali' or fname.startswith('R$'):
  370. continue
  371. os.remove(f)
  372. return 0
  373. def handle_qingshi_old_code(game, sdk, sub_channel, config):
  374. print('handle_qingshi_old_code')
  375. decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  376. qingshi_path = os.path.join(decompile_path, 'smali', 'cn', 'qingshi')
  377. support_path = os.path.join(decompile_path, 'smali', 'cn', 'yyxx')
  378. xi_path = os.path.join(decompile_path, 'smali', 'XI')
  379. ali_path = os.path.join(decompile_path, 'smali', 'com', 'alibaba')
  380. asus_path = os.path.join(decompile_path, 'smali', 'com', 'asus')
  381. bun_path = os.path.join(decompile_path, 'smali', 'com', 'bun')
  382. cmic_path = os.path.join(decompile_path, 'smali', 'com', 'cmic')
  383. dolin_path = os.path.join(decompile_path, 'smali', 'com', 'dolin')
  384. huawei_path = os.path.join(decompile_path, 'smali', 'com', 'huawei')
  385. mobile_path = os.path.join(decompile_path, 'smali', 'com', 'mobile')
  386. netease_path = os.path.join(decompile_path, 'smali', 'com', 'netease')
  387. nirvana_path = os.path.join(decompile_path, 'smali', 'com', 'nirvana')
  388. samsung_path = os.path.join(decompile_path, 'smali', 'com', 'samsung')
  389. mmkv_path = os.path.join(decompile_path, 'smali', 'com', 'tencent', 'mmkv')
  390. zui_path = os.path.join(decompile_path, 'smali', 'com', 'zui')
  391. annotation_path = os.path.join(decompile_path, 'smali', 'android', 'support', 'annotation')
  392. v4_path = os.path.join(decompile_path, 'smali', 'android', 'support', 'v4')
  393. file_utils.delete_folder(qingshi_path)
  394. file_utils.delete_folder(support_path)
  395. file_utils.delete_folder(xi_path)
  396. file_utils.delete_folder(ali_path)
  397. file_utils.delete_folder(asus_path)
  398. file_utils.delete_folder(bun_path)
  399. file_utils.delete_folder(cmic_path)
  400. file_utils.delete_folder(dolin_path)
  401. file_utils.delete_folder(huawei_path)
  402. file_utils.delete_folder(mobile_path)
  403. file_utils.delete_folder(netease_path)
  404. file_utils.delete_folder(nirvana_path)
  405. file_utils.delete_folder(samsung_path)
  406. file_utils.delete_folder(mmkv_path)
  407. file_utils.delete_folder(zui_path)
  408. file_utils.delete_folder(qingshi_path)
  409. file_utils.delete_folder(annotation_path)
  410. file_utils.delete_folder(v4_path)
  411. return 0
  412. def copy_res(game, sdk, sub_channel, config):
  413. """
  414. 复制res资源
  415. """
  416. # 拷贝sdk资源
  417. print('copy res...')
  418. decompliePath = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  419. sdkPath = file_utils.get_full_sdk_path(sdk)
  420. resPath = os.path.join(sdkPath, 'res')
  421. decomplieResPath = file_utils.get_full_path(decompliePath, 'res')
  422. for d in os.listdir(resPath):
  423. copy_res_with_type(resPath, decomplieResPath, d)
  424. # 拷贝assets
  425. print('copy assets...')
  426. assetsPath = file_utils.get_full_path(sdkPath, 'assets')
  427. decomplieAssetsPath = file_utils.get_full_path(decompliePath, 'assets')
  428. if os.path.exists(assetsPath):
  429. ret = file_utils.copy_file_all_dir(assetsPath, decomplieAssetsPath)
  430. if ret:
  431. return ret
  432. # 拷贝jniLib
  433. print('copy jniLibs...')
  434. jniPath = file_utils.get_full_path(sdkPath, 'jniLibs')
  435. decomplieJniPath = file_utils.get_full_path(decompliePath, 'lib')
  436. abiFilters = []
  437. if os.path.exists(decomplieJniPath):
  438. for abi in os.listdir(decomplieJniPath):
  439. # if abi == 'armeabi-v7a' or abi == 'armeabi' or abi == 'arm64-v8a':
  440. print('append : ' + abi)
  441. abiFilters.append(abi)
  442. else:
  443. abiFilters = ['armeabi-v7a']
  444. if os.path.exists(jniPath):
  445. ret = file_utils.copy_file_all_dir(
  446. jniPath, decomplieJniPath, False, abiFilters)
  447. if ret:
  448. return ret
  449. return 0
  450. def merge_drawable_res(game, sdk, sub_channel, config):
  451. """
  452. 合并Drawable-v4目录
  453. """
  454. print('merge drawable path...')
  455. decompliePath = file_utils.get_decompile_path(
  456. game, sdk, sub_channel, config['cache'])
  457. resPath = os.path.join(decompliePath, 'res')
  458. for path in os.listdir(resPath):
  459. # print('res path %s' % path)
  460. if (path.startswith('drawable') or path.startswith('mipmap')) and path.endswith('-v4'):
  461. # print('merge path %s' % path)
  462. v4DrawablePath = os.path.join(resPath, path)
  463. drawablePath = os.path.join(resPath, path[:-3])
  464. if os.path.exists(drawablePath):
  465. ret = file_utils.copy_file_all_dir(
  466. v4DrawablePath, drawablePath, True)
  467. if ret:
  468. return ret
  469. else:
  470. os.rename(v4DrawablePath, drawablePath)
  471. return 0
  472. def remove_v2_old_res(game, sdk, sub_channel, config):
  473. print('remove v2 sdk old res...')
  474. decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  475. res_path = os.path.join(decompile_path, 'res')
  476. public_xml = os.path.join(res_path, 'values', 'public.xml')
  477. # 移除public.xml
  478. if os.path.exists(public_xml):
  479. print('remove public.xml')
  480. os.remove(public_xml)
  481. sub_folders = os.listdir(res_path)
  482. for folder in sub_folders:
  483. sub_folder_path = os.path.join(res_path, folder)
  484. qs_xml_docs = os.listdir(sub_folder_path)
  485. for xml in qs_xml_docs:
  486. if xml.startswith('qs_') or xml.startswith('authsdk_'):
  487. xml_path = os.path.join(sub_folder_path, xml)
  488. print(xml_path)
  489. os.remove(xml_path)
  490. if xml == 'widget_pns_action_bar.xml' or xml == 'widget_pns_optional_viewgroup.xml' or xml == 'widget_pns_protocol.xml':
  491. xml_path = os.path.join(sub_folder_path, xml)
  492. print(xml_path)
  493. os.remove(xml_path)
  494. def remove_same_values_res(game, sdk, sub_channel, config):
  495. """
  496. 移除相同的资源
  497. """
  498. # 读取sdk的资源
  499. print('remove same res...')
  500. decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  501. sdk_path = file_utils.get_full_sdk_path(sdk)
  502. sdk_res_path = os.path.join(sdk_path, 'res')
  503. print('sdk res path: %s' % sdk_res_path)
  504. res_list = []
  505. for path in os.listdir(sdk_res_path):
  506. print('path: %s' % path)
  507. if not path.startswith('values'):
  508. continue
  509. abs_path = os.path.join(sdk_res_path, path)
  510. print('abs path: %s' % abs_path)
  511. for res_file in os.listdir(abs_path):
  512. if res_file.endswith('.DS_Store'):
  513. continue
  514. res_list = xml_utils.read_all_res(os.path.join(abs_path, res_file), res_list)
  515. if len(res_list) == 0:
  516. print('no same res found')
  517. return 0
  518. # 移除相同的资源
  519. resPath = os.path.join(decompile_path, 'res')
  520. for path in os.listdir(resPath):
  521. if not path.startswith('values'):
  522. continue
  523. abs_path = os.path.join(resPath, path)
  524. for res_file in os.listdir(abs_path):
  525. xml_utils.remove_same_values_res(os.path.join(abs_path, res_file), res_list)
  526. return 0
  527. def merge_manifest_res(game, sdk, sub_channel, config):
  528. """
  529. 合并主文件
  530. """
  531. print('merge AndroidManifest...')
  532. decompliePath = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  533. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  534. sdkPath = file_utils.get_full_sdk_path(sdk)
  535. libManifest = file_utils.get_full_path(sdkPath, 'manifest.xml')
  536. return xml_utils.merge_manifest_res(manifest, libManifest)
  537. def copy_app_res(game, sdk, sub_channel, config):
  538. """
  539. 拷贝app的资源,比如app icon、启动图等
  540. """
  541. random = config['random']
  542. channelPath = file_utils.getSubChannelPath(game, sdk, random, sub_channel)
  543. decompliePath = file_utils.get_decompile_path(
  544. game, sdk, sub_channel, config['cache'])
  545. # assets
  546. print('copy assets...')
  547. # 适配一剑斩仙
  548. if game in adaptApp:
  549. print('适配一剑斩仙...')
  550. decomplieAssetsPath = file_utils.get_full_path(decompliePath, 'assets')
  551. skinZipPath = os.path.join(decomplieAssetsPath, 'skin.zip')
  552. skinPath = os.path.join(decomplieAssetsPath, 'skin')
  553. if os.path.exists(skinZipPath):
  554. with zipfile.ZipFile(skinZipPath) as zf:
  555. zf.extractall(decomplieAssetsPath)
  556. print('create unzip skin')
  557. assetsPath = file_utils.get_full_path(channelPath, 'assets')
  558. decomplieAssetsPath = file_utils.get_full_path(
  559. decompliePath, 'assets')
  560. if os.path.exists(assetsPath):
  561. ret = file_utils.copy_file_all_dir(
  562. assetsPath, decomplieAssetsPath)
  563. with zipfile.ZipFile(skinZipPath, 'w') as z:
  564. for root, dirs, files in os.walk(skinPath):
  565. for single_file in files:
  566. filepath = os.path.join(root, single_file)
  567. print('create zip ---> ' + filepath)
  568. temPath = 'skin/' + single_file
  569. z.write(filepath, temPath)
  570. z.close()
  571. else:
  572. print('normal copy assets...')
  573. assetsPath = file_utils.get_full_path(channelPath, 'assets')
  574. decomplieAssetsPath = file_utils.get_full_path(
  575. decompliePath, 'assets')
  576. if os.path.exists(assetsPath):
  577. ret = file_utils.copy_file_all_dir(
  578. assetsPath, decomplieAssetsPath)
  579. if ret:
  580. return ret
  581. else:
  582. print('normal copy assets...')
  583. assetsPath = file_utils.get_full_path(channelPath, 'assets')
  584. decomplieAssetsPath = file_utils.get_full_path(decompliePath, 'assets')
  585. if os.path.exists(assetsPath):
  586. ret = file_utils.copy_file_all_dir(assetsPath, decomplieAssetsPath)
  587. if ret:
  588. return ret
  589. # icon
  590. print('copy icon...')
  591. ret = copy_app_res_with_type(decompliePath, channelPath, 'icon')
  592. if ret:
  593. return ret
  594. # 启动图
  595. print('copy splash...')
  596. ret = copy_app_res_with_type(decompliePath, channelPath, 'splash')
  597. if ret:
  598. return ret
  599. # 其他图片
  600. print('copy image...')
  601. ret = copy_app_res_with_type(decompliePath, channelPath, 'image')
  602. if ret:
  603. return ret
  604. return 0
  605. def copy_app_res_with_type(decompile_path, channel_path, type_name):
  606. decomplieResPath = os.path.join(decompile_path, 'res')
  607. iconPath = os.path.join(channel_path, type_name)
  608. if not os.path.exists(iconPath):
  609. print('dir "%s" not exists' % iconPath)
  610. return 0
  611. for d in os.listdir(iconPath):
  612. ret = copy_res_with_type(iconPath, decomplieResPath, d)
  613. if ret:
  614. return ret
  615. return 0
  616. def copy_res_with_type(res_path, decompile_res_path, type_name):
  617. # aapt的打包目录会带-v4后缀
  618. resDir = os.path.join(res_path, type_name)
  619. target = os.path.join(decompile_res_path, type_name)
  620. targetV4 = os.path.join(decompile_res_path, type_name + '-v4')
  621. if not os.path.exists(target) and not os.path.exists(targetV4):
  622. os.makedirs(target)
  623. return file_utils.copy_file_all_dir(resDir, target, False)
  624. elif not os.path.exists(target):
  625. return file_utils.copy_file_all_dir(resDir, targetV4, False)
  626. else:
  627. return file_utils.copy_file_all_dir(resDir, target, False)
  628. def remove_no_support_attr(game, sdk, sub_channel, config):
  629. """
  630. 删除一些不支持的属性
  631. """
  632. decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  633. manifest = os.path.join(decompile_path, 'AndroidManifest.xml')
  634. xml_utils.remove_root_attr(manifest, 'compileSdkVersion')
  635. xml_utils.remove_root_attr(manifest, 'compileSdkVersionCodename')
  636. return 0
  637. def fix_un_support_config(game, sdk, sub_channel, config):
  638. """
  639. 删除一些不支持的配置
  640. """
  641. # 检查minSdkVersion
  642. decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  643. yml = os.path.join(decompile_path, 'apktool.yml')
  644. min_sdk_version = 21
  645. file_utils.change_min_sdk_version(yml, min_sdk_version)
  646. res_path = os.path.join(decompile_path, 'res')
  647. tag = '-v'
  648. for res in os.listdir(res_path):
  649. # print('res = ' + res)
  650. if res.startswith('values') and tag in res:
  651. start = res.index(tag)
  652. version = res[start + len(tag):]
  653. if not version.isdigit():
  654. continue
  655. version = int(version)
  656. print('version = %d' % version)
  657. if version < min_sdk_version:
  658. un_support_path = os.path.join(res_path, res)
  659. print('un_support_path = ' + un_support_path)
  660. file_utils.delete_folder(un_support_path)
  661. print('deleteFolder = ' + un_support_path)
  662. return 0
  663. def change_package_name(game, sdk, sub_channel, config):
  664. """
  665. 更改包名
  666. """
  667. # 全局替换AndroidManifest里面的包名
  668. newPackageName = config['packageName']
  669. decompliePath = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  670. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  671. packageName = xml_utils.get_package_name(manifest)
  672. config['oldPackageName'] = packageName
  673. xml_utils.change_package_name(manifest, newPackageName)
  674. print('change package name %s --> %s' % (packageName, newPackageName))
  675. return 0
  676. def change_app_name(game, sdk, sub_channel, config):
  677. """
  678. 更改app名
  679. """
  680. # 生成string.xml文件
  681. name = config['name']
  682. resName = 'common_sdk_name'
  683. if 'outName' in config:
  684. resName = resName + '_' + config['outName']
  685. decompliePath = file_utils.get_decompile_path(
  686. game, sdk, sub_channel, config['cache'])
  687. stringFile = os.path.join(decompliePath, 'res',
  688. 'values', 'sdk_strings_temp.xml')
  689. content = '<?xml version="1.0" encoding="utf-8"?><resources><string name="%s">%s</string></resources>' % (
  690. resName, name)
  691. file_utils.create_file(stringFile, content)
  692. # 修改主文件的app名的值
  693. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  694. xml_utils.change_app_name(manifest, '@string/%s' % resName)
  695. print('change app name %s' % name)
  696. return 0
  697. def change_app_icon(game, sdk, subChannel, config):
  698. '''
  699. 更改app icon
  700. '''
  701. print('change app icon...')
  702. resName = 'common_sdk_icon'
  703. decompliePath = file_utils.get_decompile_path(
  704. game, sdk, subChannel, config['cache'])
  705. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  706. xml_utils.change_app_icon(manifest, '@mipmap/%s' % resName)
  707. return 0
  708. def add_meta_data(game, sdk, subChannel, config):
  709. '''
  710. 添加meta-data
  711. '''
  712. if 'metaData' not in config:
  713. return 0
  714. print('add meta-data...')
  715. decompliePath = file_utils.get_decompile_path(
  716. game, sdk, subChannel, config['cache'])
  717. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  718. xml_utils.addMetaData(manifest, config['metaData'])
  719. return 0
  720. def add_v1_config(game, sdk, sub_channel, config):
  721. """
  722. 添加config.json
  723. """
  724. if 'configData' not in config:
  725. return 0
  726. print('add config.json...')
  727. decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  728. configJson = os.path.join(decompile_path, 'assets', 'jmhy_config.json')
  729. jsonText = json.dumps(config['configData'], ensure_ascii=False)
  730. file_utils.create_file(configJson, jsonText)
  731. return 0
  732. def add_v2_config(game, sdk, sub_channel, config):
  733. """
  734. 添加config.json
  735. """
  736. if 'configData' not in config:
  737. return 0
  738. print('add config.json...')
  739. decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  740. config_json = os.path.join(decompile_path, 'assets', 'qs_game', 'qs_analytics.json')
  741. if os.path.exists(config_json):
  742. os.remove(config_json)
  743. json_text = json.dumps(config['configData']['channel_sdk_list'], ensure_ascii=False)
  744. file_utils.create_file(config_json, json_text)
  745. return 0
  746. def change_placeholders(game, sdk, sub_channel, config):
  747. """
  748. 处理掉占位符
  749. """
  750. if 'placeholders' not in config:
  751. return 0
  752. decompliePath = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  753. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  754. placeholders = config['placeholders']
  755. for placeholder in placeholders:
  756. oldText = '${%s}' % placeholder
  757. newText = placeholders[placeholder]
  758. print('change placeholder %s -> %s' % (oldText, newText))
  759. file_utils.replace_content(manifest, oldText, newText)
  760. return 0
  761. def add_launcher(game, sdk, subChannel, config):
  762. '''
  763. 添加启动图
  764. '''
  765. # ysdk的特殊处理
  766. if sdk in ignoreLauncher:
  767. return 0
  768. random = config['random']
  769. channelPath = file_utils.getSubChannelPath(game, sdk, random, subChannel)
  770. splashPath = os.path.join(channelPath, 'splash')
  771. if len(os.listdir(splashPath)) == 0:
  772. print('dir splash is empty')
  773. return 0
  774. print('add launcher...')
  775. decompliePath = file_utils.get_decompile_path(
  776. game, sdk, subChannel, config['cache'])
  777. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  778. activity = xml_utils.get_launcher_activity_name(manifest)
  779. if activity == 'com.jmhy.sdk.template.LauncherActivity':
  780. print('add launcher already exist...')
  781. return 1
  782. # 添加关联资源
  783. internalPath = file_utils.getFullInternalPath()
  784. ret = copy_app_res_with_type(decompliePath, internalPath, 'launcher_res')
  785. if ret:
  786. return ret
  787. # 拷贝代码
  788. print('copy launcher code...')
  789. codePath = os.path.join(internalPath, 'launcher_code', 'smali')
  790. smaliPath = file_utils.get_full_path(decompliePath, 'smali')
  791. ret = file_utils.copy_file_all_dir(codePath, smaliPath)
  792. if ret:
  793. return ret
  794. # 修改主文件信息
  795. print('change launcher config...')
  796. orientation = xml_utils.get_screen_orientation(manifest)
  797. activity = xml_utils.remove_launcher_activity(manifest)
  798. xml_utils.add_launcher_activity(
  799. manifest, orientation, 'com.jmhy.sdk.template.LauncherActivity')
  800. # 修改跳转的
  801. launcherActivity = os.path.join(
  802. decompliePath, 'smali', 'com', 'jmhy', 'sdk', 'template', 'LauncherActivity.smali')
  803. file_utils.replace_content(launcherActivity, '{class}', activity)
  804. print('change launcher %s to %s' %
  805. (activity, 'com.jmhy.sdk.template.LauncherActivity'))
  806. # config['oldLauncher'] = activity
  807. if 'launcherTime' in config:
  808. timeHex = formatHex(config['launcherTime'])
  809. file_utils.replace_content(launcherActivity, '0x0BB8', timeHex)
  810. return 0
  811. def addMoreIcon(game, sdk, subChannel, config):
  812. '''
  813. 添加多个图标
  814. '''
  815. print('add more icon support...')
  816. decompliePath = file_utils.get_decompile_path(
  817. game, sdk, subChannel, config['cache'])
  818. icon = '@mipmap/common_sdk_icon'
  819. if not config['changeIcon']:
  820. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  821. icon = xml_utils.get_application_attr(manifest, 'icon')
  822. switchIcon = icon
  823. if config['switchIcon']:
  824. switchIcon = '@mipmap/common_sdk_icon2'
  825. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  826. return xml_utils.add_more_icon(manifest, icon, switchIcon)
  827. def copy_icon(game, sdk, subChannel, config):
  828. '''
  829. 复制icon到res ,一键登录使用
  830. '''
  831. if config['changeIcon']:
  832. decompliePath = file_utils.get_decompile_path(game, sdk, subChannel, config['cache'])
  833. decomplieResPath = file_utils.get_full_path(decompliePath, 'res')
  834. iconPath = os.path.join(decomplieResPath, 'mipmap-xhdpi', 'common_sdk_icon.png')
  835. desPath = os.path.join(
  836. decomplieResPath, 'drawable-hdpi', 'jm_cmcc_icon.png')
  837. file_utils.copy_file(iconPath, desPath)
  838. else:
  839. decompliePath = file_utils.get_decompile_path(game, sdk, subChannel, config['cache'])
  840. decomplieResPath = file_utils.get_full_path(decompliePath, 'res')
  841. desPath = os.path.join(decomplieResPath, 'drawable-hdpi', 'jm_cmcc_icon.png')
  842. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  843. icon = xml_utils.get_application_attr(manifest, 'icon')
  844. tag = icon[1:].split("/")
  845. if len(tag) < 1:
  846. return
  847. hdpi = ['-xhdpi', '-xxhdpi', '-xxxhdpi']
  848. for h in hdpi:
  849. p1 = '%s%s' % (tag[0], h)
  850. png = tag[1] + ".png"
  851. iconPath = os.path.join(decomplieResPath, p1, png)
  852. if os.path.exists(iconPath):
  853. print('iconPath = ' + iconPath)
  854. file_utils.copy_file(iconPath, desPath)
  855. break
  856. def formatHex(millisecond):
  857. '''
  858. 将毫秒转为16进制,4位格式
  859. '''
  860. timeHex = str(hex(millisecond)).upper()
  861. timeHex = timeHex[2:]
  862. formatHex = ''
  863. if len(timeHex) == 3:
  864. formatHex = '0x0' + timeHexaddLauncher
  865. elif len(timeHex) == 4:
  866. formatHex = '0x' + timeHex
  867. else:
  868. formatHex = '0x0BB8'
  869. return formatHex
  870. def do_sdk_post_script(game, sdk, config):
  871. """
  872. 执行sdk相关特殊处理脚本
  873. """
  874. sdkPath = file_utils.get_full_sdk_path(sdk)
  875. scriptPath = os.path.join(sdkPath, 'script')
  876. targetScript = os.path.join(scriptPath, 'sdk_script.py')
  877. if not os.path.exists(targetScript):
  878. print('sdk_script no exists')
  879. return 0
  880. print('do sdk post script...')
  881. sys.path.append(scriptPath)
  882. module = importlib.import_module('sdk_script')
  883. ret = module.execute(game, sdk, config)
  884. sys.path.remove(scriptPath)
  885. return ret
  886. def do_game_post_script(game, sdk, config):
  887. """
  888. 执行游戏相关特殊处理脚本
  889. """
  890. channelPath = file_utils.get_full_game_path(game)
  891. scriptPath = os.path.join(channelPath, 'script')
  892. targetScript = os.path.join(scriptPath, 'game_script.py')
  893. if not os.path.exists(targetScript):
  894. print('game_script no exists')
  895. return 0
  896. print('doGamePostScript...')
  897. sys.path.append(scriptPath)
  898. module = importlib.import_module('game_script')
  899. ret = module.execute(game, sdk, config)
  900. sys.path.remove(scriptPath)
  901. return ret
  902. def do_game_script(game, sdk, config):
  903. """
  904. 执行游戏相关特殊处理脚本
  905. """
  906. channelPath = file_utils.get_full_path('game_script', game)
  907. targetScript = os.path.join(channelPath, 'game_script.py')
  908. print(targetScript + "--------")
  909. if not os.path.exists(targetScript):
  910. print('game_script no exists')
  911. return 0
  912. print('doGameScript...')
  913. sys.path.append(channelPath)
  914. module = importlib.import_module('game_script')
  915. ret = module.execute(game, sdk, config)
  916. sys.path.remove(channelPath)
  917. return ret
  918. def add_log_sdk(game, sdk, sub_channel, config, logSdk):
  919. # 拷贝jniLibs
  920. decompliePath = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  921. print('add log sdk, sdk:' + sdk)
  922. if sdk == 'jm_beta_sdk' or sdk == 'beta_sdk':
  923. sdk_path = file_utils.get_full_log_sdk_path(logSdk, True)
  924. elif sdk == 'qingshi':
  925. sdk_path = file_utils.get_full_log_sdk_v2_path(logSdk)
  926. else:
  927. sdk_path = file_utils.get_full_log_sdk_path(logSdk)
  928. print('copy log jniLibs...')
  929. jni_path = file_utils.get_full_path(sdk_path, 'jniLibs')
  930. decomplie_jni_path = file_utils.get_full_path(decompliePath, 'lib')
  931. abiFilters = []
  932. if os.path.exists(decomplie_jni_path):
  933. for abi in os.listdir(decomplie_jni_path):
  934. if abi == 'armeabi-v7a' or abi == 'x86' or abi == 'x86_64' or abi == 'arm64-v8a':
  935. abiFilters.append(abi)
  936. else:
  937. abiFilters = ['armeabi-v7a']
  938. if os.path.exists(jni_path):
  939. ret = file_utils.copy_file_all_dir(jni_path, decomplie_jni_path, False, abiFilters)
  940. if ret:
  941. return ret
  942. print('merge log AndroidManifest...')
  943. libManifest = file_utils.get_full_path(sdk_path, 'manifest.xml')
  944. if os.path.exists(libManifest):
  945. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  946. ret = xml_utils.merge_manifest_res(manifest, libManifest)
  947. if ret:
  948. return ret
  949. change_placeholders(game, sdk, sub_channel, config)
  950. return pack_log_jar(game, sdk, sub_channel, config, logSdk)
  951. def addOaidSdk(game, sdk, subChannel, config, oaidVersion):
  952. sdkPath = file_utils.getFullOaidSDKPath(oaidVersion)
  953. decompliePath = file_utils.get_decompile_path(
  954. game, sdk, subChannel, config['cache'])
  955. # 拷贝assets
  956. print('copy oaid assets...')
  957. assetsPath = file_utils.get_full_path(sdkPath, 'assets')
  958. decomplieAssetsPath = file_utils.get_full_path(decompliePath, 'assets')
  959. if os.path.exists(assetsPath):
  960. ret = file_utils.copy_file_all_dir(assetsPath, decomplieAssetsPath)
  961. if ret:
  962. return ret
  963. # 拷贝jniLibs
  964. print('copy oaid jniLibs...')
  965. jniPath = file_utils.get_full_path(sdkPath, 'jniLibs')
  966. decomplieJniPath = file_utils.get_full_path(decompliePath, 'lib')
  967. abiFilters = []
  968. if os.path.exists(decomplieJniPath):
  969. for abi in os.listdir(decomplieJniPath):
  970. if abi == 'armeabi-v7a' or abi == 'armeabi':
  971. abiFilters.append(abi)
  972. else:
  973. abiFilters = ['armeabi-v7a']
  974. if os.path.exists(jniPath):
  975. ret = file_utils.copy_file_all_dir(
  976. jniPath, decomplieJniPath, False, abiFilters)
  977. if ret:
  978. return ret
  979. print('merge oaid AndroidManifest...')
  980. libManifest = file_utils.get_full_path(sdkPath, 'manifest.xml')
  981. if os.path.exists(libManifest):
  982. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  983. ret = xml_utils.merge_manifest_res(manifest, libManifest)
  984. if ret:
  985. return ret
  986. return packOaidJar(game, sdk, subChannel, config, oaidVersion)
  987. def generateNewRFile(game, sdk, subChannel, config):
  988. """
  989. 生成新的R文件
  990. """
  991. decompliePath = file_utils.get_decompile_path(
  992. game, sdk, subChannel, config['cache'])
  993. androidPlatforms = file_utils.get_android_compile_tool_path()
  994. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  995. decomplieResPath = file_utils.get_full_path(decompliePath, 'res')
  996. compliePath = file_utils.get_full_path(decompliePath, 'gen')
  997. if not os.path.exists(compliePath):
  998. os.makedirs(compliePath)
  999. # 生成R文件
  1000. print('生成R文件 ...')
  1001. if config['aapt2disable']:
  1002. aapt = file_utils.get_aapt_path()
  1003. ret = file_utils.get_exec_permission(aapt)
  1004. if ret:
  1005. return ret
  1006. createRCmd = '"%s" p -f -m -J "%s" -S "%s" -I "%s" -M "%s"' % (
  1007. aapt, compliePath, decomplieResPath, androidPlatforms, manifest)
  1008. ret = file_utils.exec_format_cmd(createRCmd)
  1009. if ret:
  1010. return ret
  1011. else:
  1012. # compile
  1013. aapt = file_utils.get_aapt2_path()
  1014. ret = file_utils.get_exec_permission(aapt)
  1015. if ret:
  1016. return ret
  1017. print('compiled res ...')
  1018. complieResPath = os.path.join(compliePath, 'compiled')
  1019. complieResCmd = '"%s" compile --dir "%s" -o "%s"' % (
  1020. aapt, decomplieResPath, complieResPath)
  1021. file_utils.exec_format_cmd(complieResCmd)
  1022. # unzip
  1023. print('unzip compiled res ...')
  1024. unzipResPath = os.path.join(compliePath, 'aapt2_res')
  1025. with zipfile.ZipFile(complieResPath) as zf:
  1026. zf.extractall(unzipResPath)
  1027. print('create unzip %s' % unzipResPath)
  1028. # link
  1029. print('link res ...')
  1030. outApk = os.path.join(compliePath, 'res.apk')
  1031. linkResCmd = '"%s" link -o "%s" -I "%s" --manifest "%s" --java "%s" --auto-add-overlay' % (
  1032. aapt, outApk, androidPlatforms, manifest, compliePath)
  1033. for filename in os.listdir(unzipResPath):
  1034. linkResCmd += ' %s' % filename
  1035. print('link cmd len is %s' % len(linkResCmd))
  1036. ret = file_utils.exec_format_cmd(linkResCmd, unzipResPath)
  1037. if ret:
  1038. return ret
  1039. # 编译R文件
  1040. print('complie R.java ...')
  1041. packageName = xml_utils.get_package_name(manifest)
  1042. packagePath = file_utils.get_package_path(compliePath, packageName)
  1043. RSourceFile = os.path.join(packagePath, 'R.java')
  1044. complieRCmd = 'javac -source 1.8 -target 1.8 -encoding UTF-8 "%s"' % RSourceFile
  1045. ret = file_utils.exec_format_cmd(complieRCmd)
  1046. if ret:
  1047. return ret
  1048. # 生成dex
  1049. print('dex R.class ...')
  1050. outDex = os.path.join(compliePath, 'classes.dex')
  1051. if config['aapt2disable']:
  1052. dx = file_utils.get_dx_path()
  1053. dexCmd = '--dex --no-warning --output="%s" "%s"' % (
  1054. outDex, compliePath)
  1055. else:
  1056. dx = file_utils.get_d8_path()
  1057. clazz = os.path.join(packagePath, '*.class')
  1058. dexCmd = '--lib "%s" --output "%s" %s' % (
  1059. androidPlatforms, compliePath, clazz)
  1060. ret = file_utils.exec_jar_cmd(dx, dexCmd)
  1061. if ret:
  1062. return ret
  1063. # 反向dex生成smali
  1064. # 存放在out目录
  1065. print('baksmali classes.dex ...')
  1066. baksmaliPath = file_utils.get_baksmali_path()
  1067. outPath = file_utils.get_full_path(decompliePath, 'out')
  1068. ret = file_utils.exec_jar_cmd(
  1069. baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
  1070. if ret:
  1071. return ret
  1072. # 将生成的文件拷贝到目标目录
  1073. print('copy R.smali ...')
  1074. smaliPath = file_utils.get_full_path(decompliePath, 'smali')
  1075. file_utils.copy_file_all_dir(outPath, smaliPath)
  1076. return 0
  1077. def pack_jar(game, sdk, sub_channel, config):
  1078. """
  1079. 打包所有的jar
  1080. """
  1081. split_dex = config['splitDex']
  1082. decompile_path = file_utils.get_decompile_path(
  1083. game, sdk, sub_channel, config['cache'])
  1084. outPath = file_utils.get_full_path(decompile_path, 'gen')
  1085. if not os.path.exists(outPath):
  1086. os.makedirs(outPath)
  1087. if config['aapt2disable']:
  1088. dx = file_utils.get_dx_path()
  1089. dex_cmd = '--dex --no-warning --output="%s"' % outPath
  1090. else:
  1091. dx = file_utils.get_d8_path()
  1092. androidPlatforms = file_utils.get_android_compile_tool_path()
  1093. dex_cmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
  1094. # 找到所有lib依赖
  1095. sdk_path = file_utils.get_full_sdk_path(sdk)
  1096. libs = os.path.join(sdk_path, 'libs')
  1097. libConfig = os.path.join(libs, 'config.json')
  1098. # 存在配置文件
  1099. if os.path.exists(libConfig):
  1100. jsonText = file_utils.read_file(libConfig)
  1101. libConf = json.loads(jsonText)
  1102. if 'libConfig' in config and config['libConfig'] in libConf:
  1103. conf = config['libConfig']
  1104. libList = libConf[conf]
  1105. for jar in libList:
  1106. dex_cmd += ' ' + os.path.join(libs, jar)
  1107. elif 'default' in libConf:
  1108. libList = libConf['default']
  1109. for jar in libList:
  1110. dex_cmd += ' ' + os.path.join(libs, jar)
  1111. else:
  1112. for jar in os.listdir(libs):
  1113. if not jar.endswith('.jar'):
  1114. continue
  1115. dex_cmd += ' ' + os.path.join(libs, jar)
  1116. else:
  1117. for jar in os.listdir(libs):
  1118. if not jar.endswith('.jar'):
  1119. continue
  1120. dex_cmd += ' ' + os.path.join(libs, jar)
  1121. if 'refactorSdk' in config and config['refactorSdk']:
  1122. pass
  1123. else:
  1124. # multidex.jar
  1125. if split_dex:
  1126. print('getMultiDexPath ...')
  1127. dex_cmd += ' ' + file_utils.get_multidex_path()
  1128. # sdk实现类
  1129. dex_cmd += ' ' + os.path.join(sdk_path, '%s.jar' % sdk)
  1130. print('packaging all jar ...')
  1131. ret = file_utils.exec_jar_cmd(dx, dex_cmd)
  1132. if ret:
  1133. return ret
  1134. # 反向dex生成smali
  1135. # 存放在out目录
  1136. print('baksmali classes.dex ...')
  1137. outDex = os.path.join(outPath, 'classes.dex')
  1138. baksmaliPath = file_utils.get_baksmali_path()
  1139. outPath = file_utils.get_full_path(decompile_path, 'out')
  1140. ret = file_utils.exec_jar_cmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
  1141. if ret:
  1142. return ret
  1143. # 将生成的文件拷贝到目标目录
  1144. print('copy all smali ...')
  1145. smaliPath = file_utils.get_full_path(decompile_path, 'smali')
  1146. ret = file_utils.copy_file_all_dir(outPath, smaliPath, True)
  1147. if ret:
  1148. return ret
  1149. return 0
  1150. def pack_log_jar(game, sdk, sub_channel, config, log_sdk):
  1151. """
  1152. 打包Log jar
  1153. """
  1154. decompliePath = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  1155. outPath = file_utils.get_full_path(decompliePath, 'gen')
  1156. if not os.path.exists(outPath):
  1157. os.makedirs(outPath)
  1158. if config['aapt2disable']:
  1159. dx = file_utils.get_dx_path()
  1160. dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
  1161. else:
  1162. dx = file_utils.get_d8_path()
  1163. androidPlatforms = file_utils.get_android_compile_tool_path()
  1164. dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
  1165. # 找到所有lib依赖
  1166. if sdk == 'jm_beta_sdk' or sdk == 'beta_sdk':
  1167. sdk_path = file_utils.get_full_log_sdk_path(log_sdk, True)
  1168. elif sdk == 'qingshi':
  1169. sdk_path = file_utils.get_full_log_sdk_v2_path(log_sdk)
  1170. else:
  1171. sdk_path = file_utils.get_full_log_sdk_path(log_sdk)
  1172. libs = os.path.join(sdk_path, 'libs')
  1173. lib_config = os.path.join(libs, 'config.json')
  1174. # 存在配置文件
  1175. if os.path.exists(lib_config):
  1176. json_text = file_utils.read_file(lib_config)
  1177. lib_list = json.loads(json_text)
  1178. for jar in lib_list:
  1179. if not jar.endswith('.jar'):
  1180. continue
  1181. dexCmd += ' ' + os.path.join(libs, jar)
  1182. else:
  1183. for jar in os.listdir(libs):
  1184. if not jar.endswith('.jar'):
  1185. continue
  1186. dexCmd += ' ' + os.path.join(libs, jar)
  1187. # sdk实现类
  1188. print('packaging all log jar ...')
  1189. if sdk != 'qingshi':
  1190. dexCmd += ' ' + os.path.join(sdk_path, '%s.jar' % log_sdk)
  1191. ret = file_utils.exec_jar_cmd(dx, dexCmd)
  1192. if ret:
  1193. return ret
  1194. # 反向dex生成smali
  1195. # 存放在out目录
  1196. print('baksmali classes.dex ...')
  1197. outDex = os.path.join(outPath, 'classes.dex')
  1198. baksmaliPath = file_utils.get_baksmali_path()
  1199. outPath = file_utils.get_full_path(decompliePath, 'out')
  1200. ret = file_utils.exec_jar_cmd(
  1201. baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
  1202. if ret:
  1203. return ret
  1204. # 将生成的文件拷贝到目标目录
  1205. print('copy all log smali ...')
  1206. smaliPath = file_utils.get_full_path(decompliePath, 'smali')
  1207. ret = file_utils.copy_file_all_dir(outPath, smaliPath, True)
  1208. if ret:
  1209. return ret
  1210. return 0
  1211. def packOaidJar(game, sdk, subChannel, config, oaidVerion):
  1212. '''
  1213. 打包oaid jar
  1214. '''
  1215. decompliePath = file_utils.get_decompile_path(
  1216. game, sdk, subChannel, config['cache'])
  1217. outPath = file_utils.get_full_path(decompliePath, 'gen')
  1218. if not os.path.exists(outPath):
  1219. os.makedirs(outPath)
  1220. if config['aapt2disable']:
  1221. dx = file_utils.get_dx_path()
  1222. dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
  1223. else:
  1224. dx = file_utils.get_d8_path()
  1225. androidPlatforms = file_utils.get_android_compile_tool_path()
  1226. dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
  1227. # 找到所有lib依赖
  1228. sdkPath = file_utils.getFullOaidSDKPath(oaidVerion)
  1229. libs = os.path.join(sdkPath, 'libs')
  1230. libConfig = os.path.join(libs, 'config.json')
  1231. # 存在配置文件
  1232. # if os.path.exists(libConfig):
  1233. # jsonText = file_utils.readFile(libConfig)
  1234. # libList = json.loads(jsonText)
  1235. # for jar in libList:
  1236. # if not jar.endswith('.jar'):
  1237. # continue
  1238. # dexCmd += ' ' + os.path.join(libs, jar)
  1239. # else:
  1240. # for jar in os.listdir(libs):
  1241. # if not jar.endswith('.jar'):
  1242. # continue
  1243. # dexCmd += ' ' + os.path.join(libs, jar)
  1244. # sdk实现类
  1245. print('packageing oaid jar ...')
  1246. dexCmd += ' ' + os.path.join(libs, 'miit_mdid_%s.jar' % oaidVerion)
  1247. ret = file_utils.exec_jar_cmd(dx, dexCmd)
  1248. if ret:
  1249. return ret
  1250. # 反向dex生成smali
  1251. # 存放在out目录
  1252. print('baksmali classes.dex ...')
  1253. outDex = os.path.join(outPath, 'classes.dex')
  1254. baksmaliPath = file_utils.get_baksmali_path()
  1255. outPath = file_utils.get_full_path(decompliePath, 'out')
  1256. ret = file_utils.exec_jar_cmd(
  1257. baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
  1258. if ret:
  1259. return ret
  1260. # 将生成的文件拷贝到目标目录
  1261. print('copy all log smali ...')
  1262. smaliPath = file_utils.get_full_path(decompliePath, 'smali')
  1263. ret = file_utils.copy_file_all_dir(outPath, smaliPath, True)
  1264. if ret:
  1265. return ret
  1266. return 0
  1267. def split_dex(game, sdk, sub_channel, config):
  1268. """
  1269. 分割dex
  1270. """
  1271. # 判断是否已经存在application
  1272. # 存在,则往原application添加内容
  1273. # 不存在,则拷贝一个默认的android.support.multidex.MultiDexApplication
  1274. print('add MultiDex support...')
  1275. decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  1276. manifest = os.path.join(decompile_path, 'AndroidManifest.xml')
  1277. application = xml_utils.get_application_attr(manifest, 'name')
  1278. if application is None:
  1279. ret = xml_utils.change_application_attr(manifest, 'name', 'android.support.multidex.MultiDexApplication')
  1280. if ret:
  1281. return ret
  1282. else:
  1283. smaliPath = os.path.join(decompile_path, 'smali')
  1284. application_file = file_utils.get_package_path(smaliPath, application)
  1285. application_file += '.smali'
  1286. ret = change_application_dex(application_file)
  1287. if ret:
  1288. return ret
  1289. return split_smali(game, sdk, sub_channel, config, application)
  1290. def change_application_dex(file):
  1291. """
  1292. 修改application的smali文件,增加MultiDex操作
  1293. """
  1294. index = file_utils.get_application_smali_index(file)
  1295. file_utils.insert_application_smali(file, index)
  1296. return 0
  1297. def split_smali(game, sdk, sub_channel, config, application):
  1298. """
  1299. 如果函数上限超过限制,自动拆分smali,以便生成多个dex文件
  1300. """
  1301. print('splitSmali...')
  1302. decompliePath = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  1303. smaliPath = os.path.join(decompliePath, 'smali')
  1304. appPackage = None
  1305. if application:
  1306. appPackage = application[:application.rfind('.')]
  1307. appPackage = appPackage.replace('.', '/')
  1308. allFiles = []
  1309. allFiles = file_utils.list_files(smaliPath, allFiles)
  1310. # print('file count is %d' % len(allFiles))
  1311. # maxFuncNum = 65535
  1312. # 留一点空间,防止计算误差
  1313. maxFuncNum = 64000
  1314. currFucNum = 0
  1315. totalFucNum = 0
  1316. currDexIndex = 1
  1317. allRefs = []
  1318. # 保证Application等类在第一个classex.dex文件中
  1319. for f in allFiles:
  1320. f = f.replace('\\', '/')
  1321. if (appPackage and appPackage in f) or '/android/support/multidex' in f:
  1322. currFucNum += smali_utils.get_smali_method_count(f, allRefs)
  1323. totalFucNum = currFucNum
  1324. for f in allFiles:
  1325. f = f.replace('\\', '/')
  1326. if not f.endswith('.smali'):
  1327. continue
  1328. if (appPackage and appPackage in f) or '/android/support/multidex' in f:
  1329. continue
  1330. thisFucNum = smali_utils.get_smali_method_count(f, allRefs)
  1331. totalFucNum += thisFucNum
  1332. # print('%d # %d ==> %s' % (thisFucNum, currDexIndex, f))
  1333. # print('totalFucNum is %d' % totalFucNum)
  1334. if currFucNum + thisFucNum >= maxFuncNum:
  1335. currFucNum = thisFucNum
  1336. currDexIndex += 1
  1337. newDexPath = os.path.join(
  1338. decompliePath, 'smali_classes%d' % currDexIndex)
  1339. os.makedirs(newDexPath)
  1340. else:
  1341. currFucNum += thisFucNum
  1342. if currDexIndex > 1:
  1343. newDexPath = os.path.join(
  1344. decompliePath, 'smali_classes%d' % currDexIndex)
  1345. targetFile = newDexPath + f[len(smaliPath):]
  1346. file_utils.copy_file(f, targetFile, True)
  1347. return 0
  1348. def changeVersion(game, sdk, sub_channel, config):
  1349. """
  1350. 更改版本号
  1351. """
  1352. decompliePath = file_utils.get_decompile_path(
  1353. game, sdk, sub_channel, config['cache'])
  1354. yml = os.path.join(decompliePath, 'apktool.yml')
  1355. versionCode = None
  1356. versionName = None
  1357. targetSdkVersion = None
  1358. if 'versionCode' in config:
  1359. versionCode = config['versionCode']
  1360. if 'versionName' in config:
  1361. versionName = config['versionName']
  1362. if 'targetSdkVersion' in config:
  1363. targetSdkVersion = config['targetSdkVersion']
  1364. else:
  1365. targetSdkVersion = 26
  1366. print('changeVersion versionCode=%s,versionName=%s,targetSdkVersion=%s' %
  1367. (versionCode, versionName, targetSdkVersion))
  1368. return file_utils.changeVersion(yml, versionCode, versionName, targetSdkVersion)
  1369. def recomplie(game, sdk, subChannel, config):
  1370. '''
  1371. 回编译
  1372. '''
  1373. print('recomplie apk...')
  1374. apktoolPath = file_utils.get_apktool_path()
  1375. decompliePath = file_utils.get_decompile_path(
  1376. game, sdk, subChannel, config['cache'])
  1377. outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
  1378. useAppt2 = ' --use-aapt2'
  1379. if config['aapt2disable']:
  1380. useAppt2 = ''
  1381. return file_utils.exec_jar_cmd(apktoolPath, 'b -f "%s" -o "%s"%s' % (decompliePath, outApk, useAppt2))
  1382. def alignApk(game, sdk, subChannel, config):
  1383. '''
  1384. 对齐apk
  1385. '''
  1386. print('align apk...')
  1387. outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
  1388. alignApk = file_utils.getAlignApkPath(
  1389. game, sdk, subChannel, config['cache'])
  1390. alignapkTool = file_utils.get_zipalign_path()
  1391. if os.path.exists(alignApk):
  1392. os.remove(alignApk)
  1393. ret = file_utils.get_exec_permission(alignapkTool)
  1394. if ret:
  1395. return ret
  1396. # zipalign.exe -v -p 4 input.apk output.apk
  1397. return file_utils.exec_format_cmd('"%s" -f -p 4 "%s" "%s"' % (alignapkTool, outApk, alignApk))
  1398. def apk_signer_apk(game, sdk, sub_channel, config):
  1399. """
  1400. 签名apk
  1401. """
  1402. print('sign apk...')
  1403. print('game = %s, sdk = %s, subChannel = %s, ...' %
  1404. (game, sdk, sub_channel))
  1405. path = os.path.join(file_utils.get_current_path(), 'keystore', 'key.json')
  1406. jsonText = file_utils.read_file(path)
  1407. signConfig = json.loads(jsonText)
  1408. keystore = {}
  1409. for key in signConfig.keys():
  1410. print(key)
  1411. if game.find(key) > -1 or game == key:
  1412. if sdk in signConfig[key]:
  1413. keystore = signConfig[key][sdk]
  1414. break
  1415. else:
  1416. keystore = signConfig['default']
  1417. else:
  1418. keystore = signConfig['default']
  1419. # if game in signConfig:
  1420. # if sdk in signConfig[game]:
  1421. # keystore = signConfig[game][sdk]
  1422. # else:
  1423. # keystore = signConfig['default']
  1424. # else:
  1425. # keystore = signConfig['default']
  1426. print('storeFile is "%s"' % keystore['storeFile'])
  1427. apksigner = file_utils.get_apksigner_path()
  1428. alignApk = file_utils.getAlignApkPath(
  1429. game, sdk, sub_channel, config['cache'])
  1430. signedApk = file_utils.get_signed_apk_path(
  1431. game, sdk, sub_channel, config['cache'])
  1432. storeFile = os.path.join(file_utils.get_current_path(),
  1433. 'keystore', keystore['storeFile'])
  1434. # 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
  1435. v2disable = ''
  1436. if 'v2disable' in config and config['v2disable']:
  1437. v2disable = ' --v2-signing-enabled=false'
  1438. return file_utils.exec_jar_cmd(apksigner,
  1439. 'sign%s --ks "%s" --ks-key-alias %s --ks-pass pass:%s --key-pass pass:%s --out "%s" "%s"' % (
  1440. v2disable, storeFile, keystore['keyAlias'], keystore['storePassword'],
  1441. keystore['keyPassword'], signedApk, alignApk))
  1442. def add_channel(game, sdk, sub_channel, config):
  1443. """
  1444. 添加渠道信息
  1445. """
  1446. if 'v2disable' in config and config['v2disable']:
  1447. return 0
  1448. walle = file_utils.getWallePath()
  1449. signedApk = file_utils.get_signed_apk_path(game, sdk, sub_channel, config['cache'])
  1450. walleApk = file_utils.getWalleApkPath(game, sdk, sub_channel, config['cache'])
  1451. properties = config['properties']
  1452. appid = ''
  1453. appkey = ''
  1454. host = ''
  1455. if 'appid' in properties:
  1456. appid = properties['appid']
  1457. if 'appkey' in properties:
  1458. appkey = properties['appkey']
  1459. if 'host' in properties:
  1460. host = properties['host']
  1461. return file_utils.exec_jar_cmd(walle, 'put -e version=%s,agent=%s,appid=%s,appkey=%s,host=%s "%s" "%s"' % (
  1462. config_utils.getDate(), properties['agent'], appid, appkey, host, signedApk, walleApk))
  1463. def clearTemp(game, sdk, sub_channel, config):
  1464. """
  1465. 清空中间产生的文件
  1466. """
  1467. print('clear temp...')
  1468. targetApkPath = file_utils.getTargetApkPath(game, sdk, config['cache'])
  1469. if os.path.exists(targetApkPath):
  1470. file_utils.delete_folder(targetApkPath)
  1471. decompliePath = file_utils.get_decompile_path(
  1472. game, sdk, sub_channel, config['cache'])
  1473. if os.path.exists(decompliePath):
  1474. file_utils.delete_folder(decompliePath)
  1475. random = config['random']
  1476. channelPath = file_utils.getChannelPath(game, random, sdk)
  1477. if os.path.exists(channelPath):
  1478. file_utils.delete_folder(channelPath)
  1479. print('clear temp end')
  1480. def packConsoleInput():
  1481. '''
  1482. 控制台打包
  1483. '''
  1484. if len(sys.argv) < 3:
  1485. print('argument is missing')
  1486. return 1
  1487. # 校验参数
  1488. game = sys.argv[1]
  1489. sdk = sys.argv[2]
  1490. # 可选参数,没有则默认打全部渠道
  1491. subChannel = None
  1492. if len(sys.argv) > 3:
  1493. subChannel = sys.argv[3]
  1494. return packConsole(game, sdk, subChannel)
  1495. def packConsole(game, sdk, config, subChannel):
  1496. """
  1497. 控制台打包
  1498. """
  1499. cache_game_apk_path = file_utils.get_cache_game_apk(game, config['random'], sdk)
  1500. print('cache game apk path %s' % cache_game_apk_path)
  1501. if not os.path.exists(cache_game_apk_path):
  1502. print('game "%s" not exists' % game)
  1503. return 1
  1504. if not os.path.exists(file_utils.get_full_sdk_path(sdk)):
  1505. print('sdk "%s" not exists' % sdk)
  1506. return 1
  1507. global startTime
  1508. startTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  1509. # 读取配置
  1510. random = config['random']
  1511. channelPath = file_utils.getChannelPath(game, random, sdk)
  1512. configPath = os.path.join(channelPath, 'config.json')
  1513. if not os.path.exists(configPath):
  1514. print('%s not exists' % configPath)
  1515. return 1
  1516. jsonText = file_utils.read_file(configPath)
  1517. config = json.loads(jsonText)
  1518. # 检查参数
  1519. if not config_utils.checkConfig(config):
  1520. return 1
  1521. # 处理参数
  1522. config_utils.replaceArgs(config)
  1523. successCount = 0
  1524. failureCount = 0
  1525. if type(config) == dict:
  1526. if subChannel is None or config['subChannel'] == subChannel:
  1527. ret = pack(game, sdk, config)
  1528. if ret:
  1529. failureCount += 1
  1530. else:
  1531. successCount += 1
  1532. else:
  1533. print('subChannel "%s" no found' % subChannel)
  1534. return 1
  1535. elif type(config) == list:
  1536. found = False
  1537. for itemConfig in config:
  1538. if subChannel is None or itemConfig['subChannel'] == subChannel:
  1539. found = True
  1540. ret = pack(game, sdk, itemConfig)
  1541. if ret:
  1542. failureCount += 1
  1543. else:
  1544. successCount += 1
  1545. if not found:
  1546. print('subChannel "%s" no found' % subChannel)
  1547. return 1
  1548. print('success %d, failure %d' % (successCount, failureCount))
  1549. subChannelPath = os.path.join(channelPath, subChannel)
  1550. print('------subChannelPath 目录清空:%s -------' % subChannelPath)
  1551. file_utils.delete_folder(subChannelPath)
  1552. return 0
  1553. def formatXml(game, sdk, subChannel, config):
  1554. decompliePath = file_utils.get_decompile_path(
  1555. game, sdk, subChannel, config['cache'])
  1556. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  1557. return xml_utils.formatXml(manifest)
  1558. def copy_v1_apk_2_out_dir(game, sdk, sub_channel, config):
  1559. walleApk = file_utils.getWalleApkPath(game, sdk, sub_channel, config['cache'])
  1560. releaseApkPath = ""
  1561. if 'outName' in config and 'outPath' in config:
  1562. if not os.path.exists(config['outPath']):
  1563. os.makedirs(config['outPath'])
  1564. releaseApkPath = os.path.join(config['outPath'], config['outName'] + '.apk')
  1565. elif 'outName' in config:
  1566. releaseApkPath = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
  1567. print('------生成正式包路径 %s -------' % releaseApkPath)
  1568. file_utils.copy_file(walleApk, releaseApkPath)
  1569. def copy_v2_apk_2_out_dir(game, sdk, sub_channel, config):
  1570. signed_apk = file_utils.get_signed_apk_path(game, sdk, sub_channel, config['cache'])
  1571. release_apk_path = ""
  1572. if 'outName' in config and 'outPath' in config:
  1573. if not os.path.exists(config['outPath']):
  1574. os.makedirs(config['outPath'])
  1575. release_apk_path = os.path.join(config['outPath'], config['outName'] + '.apk')
  1576. elif 'outName' in config:
  1577. release_apk_path = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
  1578. print('------生成正式包路径 %s -------' % release_apk_path)
  1579. file_utils.copy_file(signed_apk, release_apk_path)
  1580. def replace_hardware_accelerated(game, sdk, subChannel, config):
  1581. decompliePath = file_utils.get_decompile_path(game, sdk, subChannel, config['cache'])
  1582. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  1583. lines = open(manifest).readlines()
  1584. fp = open(manifest, "w")
  1585. isReplaced = False
  1586. for l in lines:
  1587. if isReplaced == False and l.find("android:hardwareAccelerated=") >= 0:
  1588. isReplace = True
  1589. l = re.sub("android:hardwareAccelerated=\"false\"",
  1590. "android:hardwareAccelerated=\"true\"", l)
  1591. fp.write(l)
  1592. fp.close()
  1593. pass
  1594. def remove_v2_old_abi(game, sdk, sub_channel, config):
  1595. print('remove v2 old abi...')
  1596. decompile_path = file_utils.get_decompile_path(game, sdk, sub_channel, config['cache'])
  1597. lib_path = os.path.join(decompile_path, 'lib')
  1598. abi_folders = os.listdir(lib_path)
  1599. for abi_folder in abi_folders:
  1600. abi_folder_path = os.path.join(lib_path, abi_folder)
  1601. abi_files = os.listdir(abi_folder_path)
  1602. for abi in abi_files:
  1603. if abi == 'libalicomphonenumberauthsdk_core.so':
  1604. abi_path = os.path.join(abi_folder_path, abi)
  1605. print(abi_path)
  1606. os.remove(abi_path)
  1607. if abi == 'libauth_number_product-2.12.1-log-online-standard-release_alijtca_plus.so':
  1608. abi_path = os.path.join(abi_folder_path, abi)
  1609. print(abi_path)
  1610. os.remove(abi_path)
  1611. if abi == 'libdolin-zap.so':
  1612. abi_path = os.path.join(abi_folder_path, abi)
  1613. print(abi_path)
  1614. os.remove(abi_path)
  1615. if abi == 'libmmkv.so':
  1616. abi_path = os.path.join(abi_folder_path, abi)
  1617. print(abi_path)
  1618. os.remove(abi_path)
  1619. if abi == 'libqsgamesdk.so':
  1620. abi_path = os.path.join(abi_folder_path, abi)
  1621. print(abi_path)
  1622. os.remove(abi_path)
  1623. if abi == 'libsecsdk.so':
  1624. abi_path = os.path.join(abi_folder_path, abi)
  1625. print(abi_path)
  1626. os.remove(abi_path)
  1627. def openFile(file, mode):
  1628. return open(file, mode, encoding='UTF-8')
  1629. def is_refactor_sdk(config) -> bool:
  1630. return 'refactorSdk' in config and config['refactorSdk']