package_utils.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. from PrintLog import PrintLog
  2. import os
  3. import file_utils, xml_utils, path_utils, apk_tool, contants
  4. def pack(apk_decompile_tmp_dir, channel_path, sdk_name,package_name):
  5. PrintLog('删剔除母包融合SDK代码(cn/yyxx)')
  6. ret = remove_yyxx_old_code(apk_decompile_tmp_dir)
  7. if ret:
  8. return ret
  9. PrintLog('删除一些不支持的属性')
  10. ret = remove_no_support_attr(apk_decompile_tmp_dir)
  11. if ret:
  12. return ret
  13. PrintLog('修改minSdkVersion为21,删除res里仅支持21以下的资源目录')
  14. ret = change_un_support_config(apk_decompile_tmp_dir)
  15. if ret:
  16. return ret
  17. PrintLog('修改关于反编译后不符合要求的资源目录 eg:drawable-hdpi-v4')
  18. ret = merge_darwable_res_end_with_v4(apk_decompile_tmp_dir)
  19. if ret:
  20. return ret
  21. PrintLog('移除母包SDK的res资源')
  22. ret = remove_old_res(apk_decompile_tmp_dir)
  23. if ret:
  24. return ret
  25. PrintLog('移除母包SDK的.so文件')
  26. ret = remove_old_abi(apk_decompile_tmp_dir)
  27. if ret:
  28. return ret
  29. PrintLog('移除打包目录中values的重复资源')
  30. ret = remove_same_values_res(apk_decompile_tmp_dir, channel_path)
  31. if ret:
  32. return ret
  33. PrintLog('复制渠道SDK资源')
  34. ret = copy_res(apk_decompile_tmp_dir, channel_path)
  35. if ret:
  36. return ret
  37. # 合并主文件
  38. PrintLog('合并Androidmanifest.xml 文件')
  39. ret = merge_manifest_res(apk_decompile_tmp_dir, channel_path, sdk_name)
  40. if ret:
  41. return ret
  42. # 打包lib依赖
  43. PrintLog('将SDK中jar包打进临时打包目录')
  44. ret = pack_jar(apk_decompile_tmp_dir, channel_path)
  45. if ret:
  46. return ret
  47. # 修改${applicationId}
  48. PrintLog('修改替换AndroidManifest.xml中${applicationId}关键字')
  49. temp_manifest_path = os.path.join(apk_decompile_tmp_dir,'AndroidManifest.xml')
  50. file_utils.replace_content(temp_manifest_path, '${applicationId}', package_name)
  51. # 生成R文件
  52. PrintLog('生成R文件')
  53. ret = apk_tool.create_R_file(apk_decompile_tmp_dir,package_name)
  54. if ret:
  55. return ret
  56. def remove_yyxx_old_code(apk_decompile_tmp_dir):
  57. yyxx_code_path = os.path.join(apk_decompile_tmp_dir, 'smali', 'cn', 'yyxx')
  58. file_utils.safeFileDelete(yyxx_code_path)
  59. return 0
  60. def remove_no_support_attr(apk_decompile_tmp_dir):
  61. """
  62. 删除一些不支持的属性
  63. """
  64. manifest = os.path.join(apk_decompile_tmp_dir, 'AndroidManifest.xml')
  65. xml_utils.remove_root_attr(manifest, 'compileSdkVersion')
  66. xml_utils.remove_root_attr(manifest, 'compileSdkVersionCodename')
  67. return 0
  68. def change_un_support_config(apk_decompile_tmp_dir):
  69. """
  70. 默认最低版本为21
  71. 1.修改 minSdkVersion 为21
  72. 2.删除res里仅支持21以下的资源目录
  73. :param apk_decompile_tmp_dir:
  74. :return:
  75. """
  76. min_sdk_version = 21
  77. yml = os.path.join(apk_decompile_tmp_dir, 'apktool.yml')
  78. file_utils.change_min_sdk_version(yml, min_sdk_version)
  79. res_path = os.path.join(apk_decompile_tmp_dir, 'res')
  80. tag = '-v'
  81. for res in os.listdir(res_path):
  82. # print('res = ' + res)
  83. if res.startswith('values') and tag in res:
  84. start = res.index(tag)
  85. version = res[start + len(tag):]
  86. if not version.isdigit():
  87. continue
  88. version = int(version)
  89. PrintLog('version = %d' % version)
  90. if version < min_sdk_version:
  91. un_support_path = os.path.join(res_path, res)
  92. file_utils.delete_folder(un_support_path)
  93. PrintLog('[un_support_path] : %s \n has been deleted ' % un_support_path)
  94. def merge_darwable_res_end_with_v4(apk_decompile_tmp_dir):
  95. """
  96. 修改关于反编译后不符合要求的资源目录
  97. eg:drawable-hdpi-v4
  98. :param apk_decompile_tmp_dir:
  99. :return:
  100. """
  101. res_path = os.path.join(apk_decompile_tmp_dir, 'res')
  102. for path in os.listdir(res_path):
  103. # print('res path %s' % path)
  104. if (path.startswith('drawable') or path.startswith('mipmap')) and path.endswith('-v4'):
  105. # print('merge path %s' % path)
  106. v4DrawablePath = os.path.join(res_path, path)
  107. drawablePath = os.path.join(res_path, path[:-3])
  108. if os.path.exists(drawablePath):
  109. ret = file_utils.copy_file_all_dir(
  110. v4DrawablePath, drawablePath, True)
  111. if ret:
  112. return ret
  113. else:
  114. os.rename(v4DrawablePath, drawablePath)
  115. return 0
  116. def remove_old_res(apk_decompile_tmp_dir):
  117. """
  118. 该步骤未完善,考虑如果覆盖res资源,即可不用执行
  119. :param apk_decompile_tmp_dir:
  120. :return:
  121. """
  122. res_path = os.path.join(apk_decompile_tmp_dir, 'res')
  123. public_xml = os.path.join(res_path, 'values', 'public.xml')
  124. if os.path.exists(public_xml):
  125. file_utils.safeFileDelete(public_xml)
  126. sub_folders = os.listdir(res_path)
  127. for folder in sub_folders:
  128. sub_folder_path = os.path.join(res_path, folder)
  129. res_xml_docs = os.listdir(sub_folder_path)
  130. for xml in res_xml_docs:
  131. if xml.startswith('hnyy_') or xml.startswith('xy_') or xml.startswith('xy_') or xml.startswith('qj_') \
  132. or xml.startswith('xinrui_') or xml.startswith('yyxx_'):
  133. xml_path = os.path.join(sub_folder_path, xml)
  134. print(xml_path)
  135. os.remove(xml_path)
  136. return 0
  137. def remove_old_abi(apk_decompile_tmp_dir):
  138. libs_name = ['libdolin-zap.so', 'libmmkv.so', 'libsecsdk.so', 'libyyxxgame.so']
  139. lib_path = os.path.join(apk_decompile_tmp_dir, 'lib')
  140. if not os.path.exists(lib_path):
  141. return
  142. abi_folders = os.listdir(lib_path)
  143. for abi_folder in abi_folders:
  144. abi_folder_path = os.path.join(lib_path, abi_folder)
  145. abi_files = os.listdir(abi_folder_path)
  146. for abi in abi_files:
  147. if abi in libs_name:
  148. abi_path = os.path.join(abi_folder_path, abi)
  149. os.remove(abi_path)
  150. PrintLog("remove [abi_path]:%s" % abi_path)
  151. def remove_same_values_res(apk_decompile_tmp_dir, channel_path):
  152. sdk_res_path = os.path.join(channel_path, 'res')
  153. temp_res_path = os.path.join(apk_decompile_tmp_dir, 'res')
  154. res_list = []
  155. for value_dir in os.listdir(sdk_res_path):
  156. if not value_dir.startswith('values'):
  157. continue
  158. value_path = os.path.join(sdk_res_path, value_dir)
  159. for res_file in os.listdir(value_path):
  160. if res_file.endswith('.DS_Store'):
  161. continue
  162. res_list = xml_utils.read_all_res(os.path.join(value_path, res_file), res_list)
  163. if len(res_list) == 0:
  164. PrintLog('no same res found')
  165. return 0
  166. # 移除相同的资源
  167. for path in os.listdir(temp_res_path):
  168. if not path.startswith('values'):
  169. continue
  170. abs_path = os.path.join(temp_res_path, path)
  171. for res_file in os.listdir(abs_path):
  172. xml_utils.remove_same_values_res(os.path.join(abs_path, res_file), res_list)
  173. return 0
  174. def copy_res(apk_decompile_tmp_dir, channel_path):
  175. sdk_res_path = os.path.join(channel_path, 'res')
  176. print('[sdk_res_path]: %s ' % sdk_res_path)
  177. temp_res_path = os.path.join(apk_decompile_tmp_dir, 'res')
  178. print('[temp_res_path]: %s ' % temp_res_path)
  179. for d in os.listdir(sdk_res_path):
  180. copy_res_with_type(sdk_res_path, temp_res_path, d)
  181. # 拷贝assets
  182. print('copy assets...')
  183. sdk_assets_path = os.path.join(channel_path, 'res')
  184. temp_assets_path = os.path.join(apk_decompile_tmp_dir, 'res')
  185. if os.path.exists(sdk_assets_path):
  186. ret = file_utils.copy_file_all_dir(sdk_assets_path, temp_assets_path)
  187. if ret:
  188. return ret
  189. def copy_res_with_type(res_path, decompile_res_path, type_name):
  190. # aapt的打包目录会带-v4后缀
  191. resDir = os.path.join(res_path, type_name)
  192. target = os.path.join(decompile_res_path, type_name)
  193. targetV4 = os.path.join(decompile_res_path, type_name + '-v4')
  194. if not os.path.exists(target) and not os.path.exists(targetV4):
  195. os.makedirs(target)
  196. return file_utils.copyAllFile(resDir, target)
  197. elif not os.path.exists(target):
  198. return file_utils.copyAllFile(resDir, targetV4)
  199. else:
  200. return file_utils.copyAllFile(resDir, target)
  201. def merge_manifest_res(apk_decompile_tmp_dir, channel_path, sdk_name):
  202. """
  203. 合并AndroidManifest.xml文件
  204. """
  205. sdkConfigPath = os.path.join(channel_path, sdk_name + '_sdk_config.xml')
  206. apkManifestPath = os.path.join(apk_decompile_tmp_dir, 'AndroidManifest.xml')
  207. return file_utils.mergeManifest(sdkConfigPath, apkManifestPath)
  208. def pack_jar(apk_decompile_tmp_dir, channel_path):
  209. """
  210. 打包所有的jar
  211. :param apk_decompile_tmp_dir:
  212. :param channel_path:
  213. :param sdk_name:
  214. :return:
  215. """
  216. temp_gen_path = os.path.join(apk_decompile_tmp_dir, 'gen')
  217. print('[temp_gen_path]: %s ' % temp_gen_path)
  218. if not os.path.exists(temp_gen_path):
  219. os.makedirs(temp_gen_path)
  220. if contants.IS_USE_AAPT2:
  221. dx = path_utils.get_dx_path()
  222. dex_cmd = '--dex --no-warning --output="%s"' % temp_gen_path
  223. else:
  224. dx = path_utils.get_d8_path()
  225. android_jar = path_utils.get_android_compile_tool_path()
  226. dex_cmd = '--lib "%s" --output "%s"' % (android_jar, temp_gen_path)
  227. # 找到所有lib依赖,编译成class.dex
  228. sdk_lib_path = os.path.join(channel_path, 'lib')
  229. path_list = file_utils.iterate_dir_path(sdk_lib_path)
  230. lib_list = ''
  231. for sdk_lib in path_list:
  232. if sdk_lib.endswith('.DS_Store'):
  233. continue
  234. lib_list += ' ' + sdk_lib
  235. dex_cmd = dex_cmd + lib_list
  236. PrintLog('packaging all jar ...')
  237. ret = apk_tool.exec_jar_cmd(dx, dex_cmd)
  238. if ret:
  239. return ret
  240. PrintLog('baksmali classes.dex ...')
  241. out_dex = os.path.join(temp_gen_path, 'classes.dex')
  242. bak_smali_path = path_utils.get_baksmali_path()
  243. out_smali_path = os.path.join(temp_gen_path, 'out')
  244. ret = apk_tool.exec_jar_cmd(bak_smali_path, 'd "%s" -o "%s"' % (out_dex, out_smali_path))
  245. if ret:
  246. return ret
  247. # 将生成的文件拷贝到目标目录
  248. print('copy all smali ...')
  249. temp_smali_path = os.path.join(apk_decompile_tmp_dir, 'smali')
  250. ret = file_utils.copy_file_all_dir(out_smali_path, temp_smali_path, True)
  251. if ret:
  252. return ret
  253. if __name__ == "__main__":
  254. pack_jar('/Users/kaiweicai/Documents/Project/PackKit/YYXXPackKit/game/817050/dcm_tmphuawei',
  255. '/Users/kaiweicai/Documents/Project/PackKit/YYXXPackKit/channel/huawei')