123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- from PrintLog import PrintLog
- import os
- import file_utils, xml_utils, path_utils, apk_tool, contants
- def pack(apk_decompile_tmp_dir, channel_path, sdk_name,package_name):
- PrintLog('删剔除母包融合SDK代码(cn/yyxx)')
- ret = remove_yyxx_old_code(apk_decompile_tmp_dir)
- if ret:
- return ret
- PrintLog('删除一些不支持的属性')
- ret = remove_no_support_attr(apk_decompile_tmp_dir)
- if ret:
- return ret
- PrintLog('修改minSdkVersion为21,删除res里仅支持21以下的资源目录')
- ret = change_un_support_config(apk_decompile_tmp_dir)
- if ret:
- return ret
- PrintLog('修改关于反编译后不符合要求的资源目录 eg:drawable-hdpi-v4')
- ret = merge_darwable_res_end_with_v4(apk_decompile_tmp_dir)
- if ret:
- return ret
- PrintLog('移除母包SDK的res资源')
- ret = remove_old_res(apk_decompile_tmp_dir)
- if ret:
- return ret
- PrintLog('移除母包SDK的.so文件')
- ret = remove_old_abi(apk_decompile_tmp_dir)
- if ret:
- return ret
- PrintLog('移除打包目录中values的重复资源')
- ret = remove_same_values_res(apk_decompile_tmp_dir, channel_path)
- if ret:
- return ret
- PrintLog('复制渠道SDK资源')
- ret = copy_res(apk_decompile_tmp_dir, channel_path)
- if ret:
- return ret
- # 合并主文件
- PrintLog('合并Androidmanifest.xml 文件')
- ret = merge_manifest_res(apk_decompile_tmp_dir, channel_path, sdk_name)
- if ret:
- return ret
- # 打包lib依赖
- PrintLog('将SDK中jar包打进临时打包目录')
- ret = pack_jar(apk_decompile_tmp_dir, channel_path)
- if ret:
- return ret
- # 修改${applicationId}
- PrintLog('修改替换AndroidManifest.xml中${applicationId}关键字')
- temp_manifest_path = os.path.join(apk_decompile_tmp_dir,'AndroidManifest.xml')
- file_utils.replace_content(temp_manifest_path, '${applicationId}', package_name)
- # 生成R文件
- PrintLog('生成R文件')
- ret = apk_tool.create_R_file(apk_decompile_tmp_dir,package_name)
- if ret:
- return ret
- def remove_yyxx_old_code(apk_decompile_tmp_dir):
- yyxx_code_path = os.path.join(apk_decompile_tmp_dir, 'smali', 'cn', 'yyxx')
- file_utils.safeFileDelete(yyxx_code_path)
- return 0
- def remove_no_support_attr(apk_decompile_tmp_dir):
- """
- 删除一些不支持的属性
- """
- manifest = os.path.join(apk_decompile_tmp_dir, 'AndroidManifest.xml')
- xml_utils.remove_root_attr(manifest, 'compileSdkVersion')
- xml_utils.remove_root_attr(manifest, 'compileSdkVersionCodename')
- return 0
- def change_un_support_config(apk_decompile_tmp_dir):
- """
- 默认最低版本为21
- 1.修改 minSdkVersion 为21
- 2.删除res里仅支持21以下的资源目录
- :param apk_decompile_tmp_dir:
- :return:
- """
- min_sdk_version = 21
- yml = os.path.join(apk_decompile_tmp_dir, 'apktool.yml')
- file_utils.change_min_sdk_version(yml, min_sdk_version)
- res_path = os.path.join(apk_decompile_tmp_dir, '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)
- PrintLog('version = %d' % version)
- if version < min_sdk_version:
- un_support_path = os.path.join(res_path, res)
- file_utils.delete_folder(un_support_path)
- PrintLog('[un_support_path] : %s \n has been deleted ' % un_support_path)
- def merge_darwable_res_end_with_v4(apk_decompile_tmp_dir):
- """
- 修改关于反编译后不符合要求的资源目录
- eg:drawable-hdpi-v4
- :param apk_decompile_tmp_dir:
- :return:
- """
- res_path = os.path.join(apk_decompile_tmp_dir, 'res')
- for path in os.listdir(res_path):
- # 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(res_path, path)
- drawablePath = os.path.join(res_path, 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_old_res(apk_decompile_tmp_dir):
- """
- 该步骤未完善,考虑如果覆盖res资源,即可不用执行
- :param apk_decompile_tmp_dir:
- :return:
- """
- res_path = os.path.join(apk_decompile_tmp_dir, 'res')
- public_xml = os.path.join(res_path, 'values', 'public.xml')
- if os.path.exists(public_xml):
- file_utils.safeFileDelete(public_xml)
- sub_folders = os.listdir(res_path)
- for folder in sub_folders:
- sub_folder_path = os.path.join(res_path, folder)
- res_xml_docs = os.listdir(sub_folder_path)
- for xml in res_xml_docs:
- if xml.startswith('hnyy_') or xml.startswith('xy_') or xml.startswith('xy_') or xml.startswith('qj_') \
- or xml.startswith('xinrui_') or xml.startswith('yyxx_'):
- xml_path = os.path.join(sub_folder_path, xml)
- print(xml_path)
- os.remove(xml_path)
- return 0
- def remove_old_abi(apk_decompile_tmp_dir):
- libs_name = ['libdolin-zap.so', 'libmmkv.so', 'libsecsdk.so', 'libyyxxgame.so']
- lib_path = os.path.join(apk_decompile_tmp_dir, 'lib')
- if not os.path.exists(lib_path):
- return
- 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 in libs_name:
- abi_path = os.path.join(abi_folder_path, abi)
- os.remove(abi_path)
- PrintLog("remove [abi_path]:%s" % abi_path)
- def remove_same_values_res(apk_decompile_tmp_dir, channel_path):
- sdk_res_path = os.path.join(channel_path, 'res')
- temp_res_path = os.path.join(apk_decompile_tmp_dir, 'res')
- res_list = []
- for value_dir in os.listdir(sdk_res_path):
- if not value_dir.startswith('values'):
- continue
- value_path = os.path.join(sdk_res_path, value_dir)
- for res_file in os.listdir(value_path):
- if res_file.endswith('.DS_Store'):
- continue
- res_list = xml_utils.read_all_res(os.path.join(value_path, res_file), res_list)
- if len(res_list) == 0:
- PrintLog('no same res found')
- return 0
- # 移除相同的资源
- for path in os.listdir(temp_res_path):
- if not path.startswith('values'):
- continue
- abs_path = os.path.join(temp_res_path, 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 copy_res(apk_decompile_tmp_dir, channel_path):
- sdk_res_path = os.path.join(channel_path, 'res')
- print('[sdk_res_path]: %s ' % sdk_res_path)
- temp_res_path = os.path.join(apk_decompile_tmp_dir, 'res')
- print('[temp_res_path]: %s ' % temp_res_path)
- for d in os.listdir(sdk_res_path):
- copy_res_with_type(sdk_res_path, temp_res_path, d)
- # 拷贝assets
- print('copy assets...')
- sdk_assets_path = os.path.join(channel_path, 'res')
- temp_assets_path = os.path.join(apk_decompile_tmp_dir, 'res')
- if os.path.exists(sdk_assets_path):
- ret = file_utils.copy_file_all_dir(sdk_assets_path, temp_assets_path)
- if ret:
- return ret
- 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.copyAllFile(resDir, target)
- elif not os.path.exists(target):
- return file_utils.copyAllFile(resDir, targetV4)
- else:
- return file_utils.copyAllFile(resDir, target)
- def merge_manifest_res(apk_decompile_tmp_dir, channel_path, sdk_name):
- """
- 合并AndroidManifest.xml文件
- """
- sdkConfigPath = os.path.join(channel_path, sdk_name + '_sdk_config.xml')
- apkManifestPath = os.path.join(apk_decompile_tmp_dir, 'AndroidManifest.xml')
- return file_utils.mergeManifest(sdkConfigPath, apkManifestPath)
- def pack_jar(apk_decompile_tmp_dir, channel_path):
- """
- 打包所有的jar
- :param apk_decompile_tmp_dir:
- :param channel_path:
- :param sdk_name:
- :return:
- """
- temp_gen_path = os.path.join(apk_decompile_tmp_dir, 'gen')
- print('[temp_gen_path]: %s ' % temp_gen_path)
- if not os.path.exists(temp_gen_path):
- os.makedirs(temp_gen_path)
- if contants.IS_USE_AAPT2:
- dx = path_utils.get_dx_path()
- dex_cmd = '--dex --no-warning --output="%s"' % temp_gen_path
- else:
- dx = path_utils.get_d8_path()
- android_jar = path_utils.get_android_compile_tool_path()
- dex_cmd = '--lib "%s" --output "%s"' % (android_jar, temp_gen_path)
- # 找到所有lib依赖,编译成class.dex
- sdk_lib_path = os.path.join(channel_path, 'lib')
- path_list = file_utils.iterate_dir_path(sdk_lib_path)
- lib_list = ''
- for sdk_lib in path_list:
- if sdk_lib.endswith('.DS_Store'):
- continue
- lib_list += ' ' + sdk_lib
- dex_cmd = dex_cmd + lib_list
- PrintLog('packaging all jar ...')
- ret = apk_tool.exec_jar_cmd(dx, dex_cmd)
- if ret:
- return ret
- PrintLog('baksmali classes.dex ...')
- out_dex = os.path.join(temp_gen_path, 'classes.dex')
- bak_smali_path = path_utils.get_baksmali_path()
- out_smali_path = os.path.join(temp_gen_path, 'out')
- ret = apk_tool.exec_jar_cmd(bak_smali_path, 'd "%s" -o "%s"' % (out_dex, out_smali_path))
- if ret:
- return ret
- # 将生成的文件拷贝到目标目录
- print('copy all smali ...')
- temp_smali_path = os.path.join(apk_decompile_tmp_dir, 'smali')
- ret = file_utils.copy_file_all_dir(out_smali_path, temp_smali_path, True)
- if ret:
- return ret
- if __name__ == "__main__":
- pack_jar('/Users/kaiweicai/Documents/Project/PackKit/YYXXPackKit/game/817050/dcm_tmphuawei',
- '/Users/kaiweicai/Documents/Project/PackKit/YYXXPackKit/channel/huawei')
|