# -*- coding:utf-8 -*- import sys import os import xml.etree.ElementTree as ET import print_log from print_log import printlog import shutil import json import traceback import time import file_utils, Replace, contants, http_utils, icon_utils, apk_tool, text_utils keystorepath = "/opt/packing_tool/keystore/yyrh.jks" storepass = "yyrh123456" keypass = "yyrh123456" alias = "yyrh" def startMerge(config_json_path): global ad_code_list, sp_code, apk_decompile_tmp_dir isSuccess = False errorMsg = "切包失败,请联系开发人员" time_start = time.time() try: json_text = file_utils.read_file(config_json_path) config = json.loads(json_text) sp_code = config['sp_code'] print_log.LOGFILE = "%s/%s.txt" % (contants.sdk_log_path, sp_code) if os.path.exists(print_log.LOGFILE): os.remove(print_log.LOGFILE) printlog("[LOGFILE] : %s" % print_log.LOGFILE) printlog("[sp_code] : %s" % sp_code) origin_apk_full_path = config['sub_apk_path'] printlog("[origin_apk_full_path] : %s" % origin_apk_full_path) origin_apk_dir = os.path.dirname(origin_apk_full_path) origin_apk_full_name = os.path.basename(origin_apk_full_path) printlog("[origin_apk_dir] %s" % origin_apk_dir) randomNumber = text_utils.getRamdomNumber(6) origin_apk_name = os.path.splitext(origin_apk_full_name)[0] apk_decompile_tmp_dir = os.path.join(origin_apk_dir, randomNumber, 'dcm_tmp', origin_apk_name) ad_sdk_type = config['ad_sdk_type'] printlog("[ad_sdk_type] : %s" % ad_sdk_type) ad_allow_pt = config['ad_allow_pt'] printlog("[ad_allow_pt] : %s" % ad_allow_pt) if config.get('ad_code_list'): ad_code_list = json.dumps(config['ad_code_list']) else: ad_code_list = '' printlog("[ad_code_list] : %s" % ad_code_list) sdk_code = config['sdk_code'] printlog("[sdk_code] : %s" % sdk_code) if config.get('channel_map_id'): channel_map_id = config['channel_map_id'] else: channel_map_id = '' printlog("[channel_map_id] : %s" % channel_map_id) # 包名 if config.get('package_name'): package_name = config['package_name'] else: package_name = '' printlog("[package_name] : %s" % package_name) if config.get('meta_config_value'): meta_config_value = config['meta_config_value'] else: meta_config_value = config.get('meta_config_value', '') printlog("meta_config_value:%s" % str(meta_config_value)) # 版本号 version = '' v_code = '' targetSdkVersion = '' # icon路径 icon_path = config.get('icon_path', '') printlog("[icon_path]: %s" % icon_path) unsignedApkPath = "%s_unsigned.apk" % apk_decompile_tmp_dir printlog("unsignedApkPath: %s" % unsignedApkPath) signedApkPath = "%s_signed.apk" % apk_decompile_tmp_dir printlog("signedApkPath: %s" % signedApkPath) zipalignApkPath = "%s_zipaligned.apk" % apk_decompile_tmp_dir printlog("zipalignApkPath: %s" % zipalignApkPath) http_utils.notify_sp_cut_state(sp_code, "10", "正在反编译文件", ad_code_list) printlog("----- begin decompile -----") ret = apk_tool.decompile(origin_apk_full_path, apk_decompile_tmp_dir) if ret == 1: errorMsg = "找不到游戏母包,请检查" printlog(errorMsg) http_utils.notify_sp_cut_state(sp_code, "99", errorMsg, ad_code_list) return printlog("----- begin replace params -----") temp_xml_path = os.path.join(apk_decompile_tmp_dir, 'AndroidManifest.xml') printlog("temp_xml_path %s" % temp_xml_path) http_utils.notify_sp_cut_state(sp_code, "30", "正在修改SP_CODE", ad_code_list) if ad_allow_pt != 0: add_andriod_node(temp_xml_path, "yyrh_sp_code", sp_code) http_utils.notify_sp_cut_state(sp_code, "40", "正在修改合并渠道", ad_code_list) if ad_sdk_type == 2: sdk_root_dir = contants.ad_sdk_path file_utils.mergeManifest(os.path.join(sdk_root_dir, sdk_code, sdk_code + '_sdk_config.xml'), temp_xml_path) Replace.mergeResources(os.path.join(sdk_root_dir, sdk_code, sdk_code), apk_decompile_tmp_dir) sdk_param_conf = config['sdk_param_conf'] printlog("channel sdk_param_conf: %s" % str(sdk_param_conf)) # 替换Androidmanifest.xml中的 package_name值为包名 file_utils.replace_content(temp_xml_path, 'package_name', package_name) if sdk_param_conf: keys = sdk_param_conf.keys() for key in keys: # 替换AndroidManifest.xml中的meta-data字段 file_utils.replace_manifest_meta_data(temp_xml_path, key, sdk_param_conf[key]) # 替换assets/YyrhAdParam.cnf中的关键字 file_utils.replace_assets_param( os.path.join(apk_decompile_tmp_dir, 'assets', 'YyrhAdParam.cnf'), key, sdk_param_conf[key]) # 特殊渠道需要特殊处理 # Replace.special_replace(sdk_name, apk_decompile_tmp_dir, DIR_SPLIT, key, sdk_param_conf[key]) pass # 修改包Apk文件名 # 修改包名 file_utils.modifyPkgName(apk_decompile_tmp_dir, package_name) # 替换Icon printlog("----- begin replace resource -----") http_utils.notify_sp_cut_state(sp_code, "50", "正在替换资源", ad_code_list) if icon_path: icon_utils.replace_icon(apk_decompile_tmp_dir, icon_path) # 替换启动页 splash_path = config.get('splash_path', '') printlog("splash_path:%s" % splash_path) if splash_path: if os.path.exists(splash_path): shutil.copy(splash_path, "%s/assets/yyrh_start_image.jpg" % apk_decompile_tmp_dir) else: errorMsg = "找不到闪屏文件,请检查" printlog(errorMsg) http_utils.notify_sp_cut_state(sp_code, "99", errorMsg, ad_code_list) return # 获取游戏名,版本号,版本名,targetSdkVersion,屏幕方向关键字 if meta_config_value: keys = meta_config_value.keys() for key in keys: if key == "APP_NAME": file_utils.replace_string_app_name(apk_decompile_tmp_dir, meta_config_value[key]) elif key == "version": version = meta_config_value[key] elif key == "v_code": v_code = meta_config_value[key] elif key == "targetSdkVersion": targetSdkVersion = meta_config_value[key] pass # 修改版本号 targetSdkVersion http_utils.notify_sp_cut_state(sp_code, "60", "正在修改版本号", ad_code_list) yml = os.path.join(apk_decompile_tmp_dir, 'apktool.yml') file_utils.changeVersion(yml, v_code, version, targetSdkVersion) file_utils.change_min_sdk_version(yml, 21) http_utils.notify_sp_cut_state(sp_code, "70", "正在替换游戏资源", ad_code_list) # 替换游戏资源 if config.get('game_resource_replace_path'): game_resource_replace_path = config['game_resource_replace_path'] printlog('[game_resource_replace_path]:%s' % game_resource_replace_path) if game_resource_replace_path: for resource in game_resource_replace_path: if os.path.exists(resource[1]): file_utils.copy_file(resource[1], os.path.join(apk_decompile_tmp_dir, resource[0]), False) printlog("----- begin recompile apk -----") http_utils.notify_sp_cut_state(sp_code, "80", "正在回编译APK", ad_code_list) ret = apk_tool.recompile(apk_decompile_tmp_dir, unsignedApkPath) if ret: printlog('apk回编译失败') return ret printlog("unsignedApkPath: %s" % unsignedApkPath) printlog("----- begin resign apk -----") http_utils.notify_sp_cut_state(sp_code, "90", "正在重签名,对齐APK", ad_code_list) ret = apk_tool.V1signer(unsignedApkPath, signedApkPath, keystorepath, storepass, alias, keypass) if ret: printlog('apk签名失败') return ret printlog("signedApkPath %s" % signedApkPath) printlog("----- begin zipalign apk -----") ret = apk_tool.zipalign(signedApkPath, zipalignApkPath) if ret: printlog('apk压缩失败') return ret printlog("zipalignApkPath %s" % zipalignApkPath) dis_path = os.path.join(contants.sp_out_put_dir, "%s_%s.apk" % (origin_apk_name, sp_code)) printlog("origin_apk_name %s" % origin_apk_name) if ad_allow_pt == 0 and ad_sdk_type == 2: dis_path = os.path.join(contants.sp_out_put_dir, "%s_%s_%s.apk" % (origin_apk_name, sdk_code, channel_map_id)) if ad_allow_pt == 0 and ad_sdk_type == 1: dis_path = os.path.join(contants.sp_out_put_dir, "%s_%s_%s.apk" % (origin_apk_name, sdk_code, channel_map_id)) dst_dir = os.path.dirname(dis_path) if not os.path.exists(dst_dir): os.makedirs(dst_dir) printlog("apkDstPath %s" % dis_path) shutil.copyfile(zipalignApkPath, dis_path) time_end = time.time() time_c = time_end - time_start printlog("切包总用时:%s秒" % time_c) http_utils.notify_sp_cut_state(sp_code, "100", "切包成功(点击复制链接)", ad_code_list) isSuccess = True except Exception as err: http_utils.notify_sp_cut_state(sp_code, "99", errorMsg, ad_code_list) printlog("cut error occur:%s" % err) printlog(traceback.format_exc()) finally: if apk_decompile_tmp_dir: Replace.safeFileDelete(os.path.dirname(apk_decompile_tmp_dir)) return isSuccess def add_andriod_node(xmlpath, key, value): global child ET.register_namespace('android', 'http://schemas.android.com/apk/res/android') tree = ET.parse(xmlpath) root = tree.getroot() node = ET.Element("meta-data") node.set("android:name", key) node.set("android:value", value) node.tail = "\n\t" for i in root.iter("application"): for child in i: pass child.tail = '\n\t\t' for a in root.iter("application"): a.append(node) break tree.write(xmlpath, encoding="utf-8", xml_declaration=True) pass