def merge(self, targetAndroidManifest, targetAssets, targetRes, targetLibs): ret = self.do_merge(targetAndroidManifest, targetAssets, targetRes, targetLibs) file_utils.del_file_folder(self.aarDir) file_utils.del_file_folder(self.aarFile) return ret
def checkCpuSupport(game, decompileDir): print("now to check cpu support...") cpus = ["armeabi", "armeabi-v7a", "x86", "mips", "arm64-v8a"] isfilter = ("cpuSupport" in game) and len(game["cpuSupport"]) > 0 filters = None if isfilter: filters = game["cpuSupport"].split('|') print(filters) cpuNotSupports = [f for f in cpus if f not in filters] print(cpuNotSupports) if cpuNotSupports: for c in cpuNotSupports: path = os.path.join(decompileDir, 'lib/'+c) file_utils.del_file_folder(path) #make sure so in armeabi and armeabi-v7a is same armeabiPath = os.path.join(decompileDir, 'lib/armeabi') armeabiv7aPath = os.path.join(decompileDir, 'lib/armeabi-v7a') if os.path.exists(armeabiPath) and os.path.exists(armeabiv7aPath): for f in os.listdir(armeabiPath): fv7 = os.path.join(armeabiv7aPath, f) if not os.path.exists(fv7): shutil.copy2(os.path.join(armeabiPath, f), fv7) for fv7 in os.listdir(armeabiv7aPath): f = os.path.join(armeabiPath, fv7) if not os.path.exists(f): shutil.copy2(os.path.join(armeabiv7aPath, fv7), f)
def generateNewRFile(newPackageName, decompileDir): """ Use all new resources to generate the new R.java, and compile it ,then copy it to the target smali dir """ ret = checkValueResources(decompileDir) if ret: return 1 decompileDir = file_utils.getFullPath(decompileDir) tempPath = os.path.dirname(decompileDir) tempPath = tempPath + "/temp" log_utils.debug("generate R:the temp path is %s", tempPath) if os.path.exists(tempPath): file_utils.del_file_folder(tempPath) if not os.path.exists(tempPath): os.makedirs(tempPath) resPath = os.path.join(decompileDir, "res") targetResPath = os.path.join(tempPath, "res") file_utils.copy_files(resPath, targetResPath) genPath = os.path.join(tempPath, "gen") if not os.path.exists(genPath): os.makedirs(genPath) aaptPath = file_utils.getFullToolPath("aapt") androidPath = file_utils.getFullToolPath("android.jar") manifestPath = os.path.join(decompileDir, "AndroidManifest.xml") cmd = '"%s" p -f -m -J "%s" -S "%s" -I "%s" -M "%s"' % (aaptPath, genPath, targetResPath, androidPath, manifestPath) ret = file_utils.execFormatCmd(cmd) if ret: return 1 rPath = newPackageName.replace('.', '/') rPath = os.path.join(genPath, rPath) rPath = os.path.join(rPath, "R.java") cmd = '"%sjavac" -source 1.7 -target 1.7 -encoding UTF-8 "%s"' % (file_utils.getJavaBinDir(), rPath) ret = file_utils.execFormatCmd(cmd) if ret: return 1 targetDexPath = os.path.join(tempPath, "classes.dex") dexToolPath = file_utils.getFullToolPath("/lib/dx.jar") cmd = file_utils.getJavaCMD() + ' -jar -Xmx512m -Xms512m "%s" --dex --output="%s" "%s"' % (dexToolPath, targetDexPath, genPath) ret = file_utils.execFormatCmd(cmd) if ret: return 1 smaliPath = os.path.join(decompileDir, "smali") ret = dex2smali(targetDexPath, smaliPath, "baksmali.jar") return ret
def copy_scripts(clientPath, outputPath): log_utils.debug("begin copy scripts folder:") sourcePath = os.path.join(clientPath, 'scripts') if not os.path.exists(sourcePath): log_utils.error("the scripts path not exists:" + sourcePath) return False targetPath = os.path.join(outputPath, 'scripts') file_utils.del_file_folder(targetPath) file_utils.copy_files(sourcePath, targetPath)
def unarchive(self): if not os.path.exists(self.aarFile): log_utils.error("the aar file not exists:" + self.aarFile) return False if os.path.exists(self.aarDir): file_utils.del_file_folder(self.aarDir) file_utils.unzip_file(self.aarFile, self.aarDir) return True
def copy_local(clientPath, outputPath): log_utils.debug("begin copy local folder:") sourcePath = os.path.join(clientPath, 'config/local') targetPath = os.path.join(outputPath, 'config/local') if not os.path.exists(sourcePath): log_utils.error("the local path not exists:" + sourcePath) return False file_utils.del_file_folder(targetPath) file_utils.copy_files(sourcePath, targetPath)
def flush(self): """flush all blocks to files""" # remove all [remove marked] blocks from origin file removedBlocks = self.get_removed_blocks() for f in removedBlocks: removedLst = removedBlocks[f] if len(removedLst) == 1 and removedLst[0].is_single_file(): log_utils.debug("remove duplicated file %s", f) file_utils.del_file_folder(f) else: ValueResourceParser.remove_blocks(f, removedLst) # merge styleable attrs. styleableBlocks = self.get_styleable_merged_blocks() for f in styleableBlocks: mergedLst = styleableBlocks[f] ValueResourceParser.merge_styleable_blocks(mergedLst) for b in mergedLst: if b.is_merged(): b.mark_removed() ValueResourceParser.remove_blocks(b.path(), [b]) # copy added files addedBlocks = self.get_added_blocks() for f in addedBlocks: addedLst = addedBlocks[f] targetFile = os.path.join(self.filePath, os.path.basename(f)) if os.path.exists(targetFile): log_utils.error("resource flush error. file already exists:%s", targetFile) continue file_utils.copy_file(f, targetFile) # log_utils.debug("copy a new file from %s to %s", f, targetFile) # merge blocks from files with same name. mergedBlocks = self.get_merged_blocks() for f in mergedBlocks: mergedLst = mergedBlocks[f] ValueResourceParser.merge_val_files( f, os.path.join(self.filePath, os.path.basename(f)))
def deleteXML(res): for f in os.listdir(res): sourcefile = os.path.join(res, f) sourcedir = os.path.dirname(sourcefile) if ((f == 'abc_btn_colored_borderless_text_material.xml' or f == 'abc_btn_colored_text_material.xml') and sourcedir.endswith('color')): file_utils.del_file_folder(sourcefile) if (f.startswith('abc_tint')): file_utils.del_file_folder(sourcefile) if os.path.isdir(sourcefile): deleteXML(sourcefile)
def decompileApk(source, targetdir, apktool = "apktool2.jar"): """ Decompile apk """ apkfile = file_utils.getFullPath(source) targetdir = file_utils.getFullPath(targetdir) apktool = file_utils.getFullToolPath(apktool) if os.path.exists(targetdir): file_utils.del_file_folder(targetdir) if not os.path.exists(targetdir): os.makedirs(targetdir) cmd = '"%s" -jar -Xms512m -Xmx512m "%s" -q d -b -f "%s" -o "%s"' % (file_utils.getJavaCMD(), apktool, apkfile, targetdir) #cmd = '"%s" -q d -d -f "%s" "%s"' % (apktool, apkfile, targetdir) #print("decompile cmd : "+ cmd) ret = file_utils.execFormatCmd(cmd) return ret
def copy_tool(clientPath, outputPath): log_utils.debug("begin copy tool folder:") sourcePath = os.path.join(clientPath, 'tool') if not os.path.exists(sourcePath): log_utils.error("the tool path not exists:" + sourcePath) return False targetPath = os.path.join(outputPath, 'tool') file_utils.del_file_folder(targetPath) subs = ['win', 'mac'] for sub in subs: file_utils.copy_files(os.path.join(sourcePath, sub), os.path.join(targetPath, sub))
def decompile(source, targetdir): """ decompile apk to targetdir """ apkfile = source apktool = file_utils.getFullToolPath('apktool2.jar') if os.path.exists(targetdir): file_utils.del_file_folder(targetdir) if not os.path.exists(targetdir): os.makedirs(targetdir) heapSize = config_utils.get_jvm_heap_size() cmd = '"%s" -jar -Xms%sm -Xmx%sm "%s" -v d -b --only-main-classes -f "%s" -o "%s"' % ( file_utils.getJavaCMD(), heapSize, heapSize, apktool, apkfile, targetdir) ret = file_utils.exec_cmd(cmd) return ret
def modify(channels, sourceApkFile): sourceApkFile = sourceApkFile.replace('\\', '/') if not os.path.exists(sourceApkFile): file_utils.printF("The source apk file is not exists") return tempFolder = file_utils.getFullPath('temp') if not os.path.exists(tempFolder): os.makedirs(tempFolder) empty_file = os.path.join(tempFolder, "temp.txt") f = open(empty_file, 'w') f.close() for channel in channels: generateNewChannelApk(sourceApkFile, empty_file, channel) file_utils.del_file_folder(tempFolder)
def generate_icon_with_mark(targetDir, iconPath, maskPath): if not os.path.exists(iconPath): log_utils.error("icon path is not exists:" + iconPath) return 1 if os.path.exists(targetDir): file_utils.del_file_folder(targetDir) if not os.path.exists(targetDir): os.makedirs(targetDir) log_utils.debug("begin generate_icon_with_mark:" + iconPath) baseName = os.path.basename(iconPath) targetIconPath = os.path.join(targetDir, baseName) file_utils.copy_file(iconPath, targetIconPath) if os.path.exists(maskPath): rlImg = Image.open(targetIconPath) maskTypes = [ "left-top.png", "left-bottom.png", "right-top.png", "right-bottom.png" ] for maskType in maskTypes: rPath = os.path.join(maskPath, maskType) log_utils.debug("handle mask:" + rPath) if os.path.exists(rPath): markIcon = Image.open(rPath) maskedIcon = image_utils.append_icon_mark( rlImg, markIcon, (0, 0)) maskedIcon.save(os.path.join(targetDir, maskType), "PNG") return 0
def generate_scaled_cached_splash(targetDir, splashPath, scaleSize): if not os.path.exists(splashPath): log_utils.error("splash path is not exists:" + splashPath) return 1 if os.path.exists(targetDir): file_utils.del_file_folder(targetDir) if not os.path.exists(targetDir): os.makedirs(targetDir) baseName = os.path.basename(splashPath) targetSplashPath = os.path.join(targetDir, baseName) file_utils.copy_file(splashPath, targetSplashPath) rlImg = Image.open(targetSplashPath) scaledImg = rlImg.resize(scaleSize, Image.ANTIALIAS) scaledImg.save(targetSplashPath, "PNG") return 0
def pack(game, channel, sourcepath, isPublic): sourcepath = sourcepath.replace('\\', '/') if not os.path.exists(sourcepath): return 1 appID = game['appID'] appKey = game['appKey'] appName = game['appName'] channelId = channel["id"] channelName = channel["name"] sdkName = channel["sdk"] log_utils.info("now to package %s...", channelName) workDir = 'workspace/' + appName + '/' + channelName workDir = file_utils.getFullPath(workDir) file_utils.del_file_folder(workDir) tempApkSource = workDir + "/temp.apk" file_utils.copy_file(sourcepath, tempApkSource) decompileDir = workDir + "/decompile" smaliDir = decompileDir + "/smali" #反编译APK ret = apk_utils.decompileApk(tempApkSource, decompileDir) if ret: return 1 #检查母包接入是否正确 ret = apk_utils.checkApkForU8SDK(workDir, decompileDir) if ret: return 1 #change xml config and so on newPackageName = apk_utils.renamePackageName(channel, decompileDir, channel['suffix'], isPublic) #copy third-plugins resources. note:The third plugins must be operated before the main sdk. ret = apk_utils.handleThirdPlugins(workDir, decompileDir, game, channel, newPackageName) if ret: return 1 #copy sdk code to decompileDir sdkSourceDir = 'config/sdk/' + sdkName sdkSourceDir = file_utils.getFullPath(sdkSourceDir) sdkDestDir = workDir + "/sdk/" + sdkName file_utils.copy_files(sdkSourceDir, sdkDestDir) #将公共库复制到临时目录,除了moyoihw渠道 if sdkName != 'moyoihw': promptDir = 'config/local/common-release.aar' promptDestDir = sdkDestDir + '/libs/common-release.aar'; file_utils.copy_files(promptDir, promptDestDir) #处理需要Gradle自动下载的库 if 'dependencies' in channel and channel['dependencies'] != None and len(channel['dependencies']) > 0: #将build.gradle复制到临时目录 localSourceDir = 'config/local/build.gradle' file_utils.copy_files(localSourceDir, sdkDestDir + '/build.gradle') #修改build.gradle config_utils.writeGradleDependencies(channel['dependencies'], sdkDestDir) #将SDK中所有aar文件解压,然后将里面各个类型的资源文件合并到SDK对应目录 file_utils.decomAAR(sdkDestDir) ret = apk_utils.jar2dex(sdkDestDir, sdkDestDir) if ret: return 1 ret = apk_utils.dexes2smali(sdkDestDir, smaliDir, "baksmali.jar") if ret: return 1 #copy main sdk resources. ret = apk_utils.copyResource(game, channel, newPackageName, sdkDestDir, decompileDir, channel['operations'], channelName) if ret: return 1 #auto handle icon apk_utils.appendChannelIconMark(game, channel, decompileDir) #copy channel special resources ret = apk_utils.copyChannelResources(game, channel, decompileDir) if ret: return 1 #copy game root resources and res resources apk_utils.copyAppResources(game, decompileDir) apk_utils.copyAppRootResources(game, decompileDir) #generate config files for apk to run. apk_utils.writeDevelopInfo(game, channel, decompileDir) apk_utils.writePluginInfo(channel, decompileDir) apk_utils.writeManifestMetaInfo(channel, decompileDir) apk_utils.writeLogConfig(game, decompileDir) #if the main sdk has special logic. execute the special logic script. ret = apk_utils.doSDKScript(channel, decompileDir, newPackageName, sdkDestDir) if ret: return 1 #if the game has some special logic. execute the special logic script.called post_script.py ret = apk_utils.doGamePostScript(game, channel, decompileDir, newPackageName) if ret: return 1 #here to config the splash screen. ret = apk_utils.addSplashScreen(workDir, channel, decompileDir) if ret: return 1 #check cpu supports apk_utils.checkCpuSupport(game, decompileDir) #modify game name if channel specified. apk_utils.modifyGameName(channel, decompileDir) #modify yml apk_utils.modifyYml(game, newPackageName, decompileDir) #generate new R.java ret = apk_utils.generateNewRFile(newPackageName, decompileDir, channel) if ret: return 1 #check to split dex apk_utils.splitDex(workDir, decompileDir) targetApk = workDir + "/output.apk" log_utils.debug("now to recompileApk....") ret = apk_utils.recompileApk(decompileDir, targetApk) if ret: return 1 apk_utils.copyRootResFiles(targetApk, decompileDir) if 'signApk' not in channel or channel['signApk'] != '0': apk_utils.xsigncode(workDir, game, channel, targetApk) apk_utils.signApk(workDir, game, channel, targetApk) else: log_utils.debug("the apk is set to unsigned.") channelNameStr = channelName.replace(' ', '') if isPublic: destApkName = apk_utils.getOutputApkName(game, channel, newPackageName, decompileDir) else: destApkName = channelNameStr + '-' + time.strftime('%Y%m%d%H') + '-debug.apk' destApkPath = file_utils.getFullOutputPath(appName, channelName) destApkPath = os.path.join(destApkPath, destApkName) ret = apk_utils.alignApk(targetApk, destApkPath) if ret: return 1 log_utils.info("channel %s package success.", channelName) return 0
def delete_aibei_res(decompileDir): """ remove aibei resources in base apk """ filelist = [ "colors", "dimens", "ids", "public", "strings", "styles", "values" ] for f in filelist: fpath = decompileDir + "/res/values/" + f + ".xml" if os.path.exists(fpath): tree = ET.parse(fpath) root = tree.getroot() for node in list(root): item = {} attribName = node.attrib.get('name') if attribName is None: continue if attribName.lower().startswith("ipay_"): root.remove(node) log_utils.debug("remove debug res index name:" + attribName + " from" + fpath) elif attribName.lower() == 'custom_dialog': root.remove(node) log_utils.debug("remove debug res index name:" + attribName + " from" + fpath) tree.write(fpath, "UTF-8") filelist = ["ab_login_values.xml", "ab_pay_values.xml"] for f in filelist: path = os.path.join(decompileDir, 'res/values', f) file_utils.del_file_folder(path) log_utils.debug("remove debug res file:" + path) resPath = decompileDir + "/res" filelist = file_utils.list_files(resPath, [], []) for f in filelist: if os.path.basename(f).lower().startswith("ipay_"): file_utils.del_file_folder(f) log_utils.debug("remove debug res file:" + f) devConfig = decompileDir + "/assets/u8_developer_config.properties" pluginConfig = decompileDir + "/assets/u8_plugin_config.xml" permissionConfig = decompileDir + "/assets/u8_permissions.xml" file_utils.del_file_folder(devConfig) file_utils.del_file_folder(pluginConfig) file_utils.del_file_folder(permissionConfig) smaliPath = decompileDir + "smali" smaliIndex = 1 otherSmaliFolder = "smali" while os.path.exists(os.path.join(decompileDir, otherSmaliFolder)): #check class dels = [ "com/u8/sdk/ABSDK", "com/u8/sdk/ABUser", "com/u8/sdk/ABPay", "com/iapppay/", "com/alipay/", "com/ta/utdid2/", "com/ut/device/", "org/json/alipay/", "org/apache/commons/", "org/apache/http/" ] for toDel in dels: file_utils.del_file_folder( os.path.join(decompileDir, otherSmaliFolder, toDel)) log_utils.debug("remove debug res :" + toDel) smaliIndex = smaliIndex + 1 otherSmaliFolder = "smali_classes" + str(smaliIndex) manifestFile = decompileDir + "/AndroidManifest.xml" ET.register_namespace('android', androidNS) tree = ET.parse(manifestFile) root = tree.getroot() permissionDels = [ "android.permission.ACCESS_NETWORK_STATE", "android.permission.CHANGE_NETWORK_STATE", "android.permission.ACCESS_WIFI_STATE", "android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_COARSE_LOCATION", "android.permission.READ_SMS", "android.permission.WRITE_SMS", "android.permission.RECEIVE_SMS", "android.permission.SEND_SMS", "android.permission.MOUNT_UNMOUNT_FILESYSTEMS", "android.permission.SYSTEM_ALERT_WINDOW" ] componentDes = [ "com.iapppay.sdk.main.WebActivity", "com.iapppay.ui.activity.PersonCenterActivity", "com.iapppay.ui.activity.PayHubActivity", "com.iapppay.ui.activity.SelectAmountActivity", "com.iapppay.ui.activity.ChargeActivity", "com.iapppay.ui.card.GamepayActivity", "com.alipay.sdk.app.H5PayActivity", "com.alipay.sdk.auth.AuthActivity", "com.iapppay.openid.channel.ui.LoginActivity", "com.iapppay.openid.channel.ui.RegisterActivity", "com.iapppay.openid.channel.ui.OneRegisterActivity", "com.iapppay.openid.channel.ui.OpenIdBaseActivity", "com.iapppay.openid.channel.ui.BindPhoneActivity", "com.iapppay.openid.channel.ui.NameAuthActivity", "com.iapppay.openid.channel.ui.FindPasswordActivity", "com.iapppay.openid.channel.ui.ModifyUserNameActivity", "com.iapppay.openid.channel.ui.ModifyPasswordActivity", "com.iapppay.openid.channel.ui.SettingCenterActivity", "com.iapppay.openid.channel.ui.UnbindPhoneActivity", "com.iapppay.openid.channel.ui.CommonWebActivity" ] key = '{' + androidNS + '}name' permissionLst = root.findall('uses-permission') if permissionLst != None and len(permissionLst) > 0: for aNode in permissionLst: permissionName = aNode.attrib[key] if permissionName in permissionDels: root.remove(aNode) log_utils.debug("remove debug permission:" + permissionName) permission23 = root.find('uses-permission-sdk-23') if permission23 != None: root.remove(permission23) log_utils.debug("remove debug permission:" + permission23.attrib[key]) appNode = root.find('application') if appNode != None: activityLst = appNode.findall('activity') if activityLst != None and len(activityLst) > 0: for aNode in activityLst: activityName = aNode.attrib[key] if activityName in componentDes: appNode.remove(aNode) log_utils.debug("remove debug activity:" + activityName) tree.write(manifestFile, "UTF-8")
def write_developer_properties(game, channel, targetFilePath): if os.path.exists(targetFilePath): file_utils.del_file_folder(targetFilePath) proStr = "" if channel['params'] != None and len(channel['params']) > 0: for param in channel['params']: print("write param:") print(param) if param['bWriteInClient'] == '1' and param['name'] != None: proStr = proStr + param['name'] + "=" + param['value'] + "\n" if "sdkLogicVersionCode" in channel and channel[ 'sdkLogicVersionCode'] != None and len( str(channel['sdkLogicVersionCode'])) > 0: proStr = proStr + "U8_SDK_VERSION_CODE=" + channel[ "sdkLogicVersionCode"] + "\n" proStr = proStr + "U8_Channel=" + str(channel['channelID']) + "\n" proStr = proStr + "U8_APPID=" + str(game["appID"]) + "\n" proStr = proStr + "U8_APPKEY=" + game["appKey"] + "\n" if "payPrivateKey" in game: proStr = proStr + "U8_PAY_PRIVATEKEY=" + game["payPrivateKey"] + "\n" showSplash = "false" if "splash" in channel and channel['splash'] != None and len( channel['splash']) > 0 and int(channel["splash"]) > 0: showSplash = "true" proStr = proStr + "U8_SDK_SHOW_SPLASH=" + showSplash + "\n" authUrl = None orderUrl = None analyticsUrl = None u8serverUrl = None u8analytics = "true" singleGame = "false" if "singleGame" in game and game["singleGame"] == 1: singleGame = "true" if "serverBaseUrl" in channel and channel["serverBaseUrl"] != None and len( channel["serverBaseUrl"].strip()) > 0: u8serverUrl = channel["serverBaseUrl"] elif "serverBaseUrl" in game and game["serverBaseUrl"] != None and len( game["serverBaseUrl"].strip()) > 0: u8serverUrl = game["serverBaseUrl"] # append u8 local config local_config = get_local_config() if u8serverUrl is None and "u8server_url" in local_config: u8serverUrl = local_config['u8server_url'] if u8serverUrl is not None: proStr = proStr + "U8SERVER_URL=" + u8serverUrl + "\n" if u8analytics is not None: proStr = proStr + "U8_ANALYTICS=" + u8analytics + "\n" if singleGame is not None: proStr = proStr + "U8_SINGLE_GAME=" + singleGame + "\n" # write third plugin info: plugins = channel.get('third-plugins') if plugins != None and len(plugins) > 0: for plugin in plugins: if 'params' in plugin and plugin['params'] != None and len( plugin['params']) > 0: for param in plugin['params']: if param['bWriteInClient'] == '1': proStr = proStr + param['name'] + "=" + param[ 'value'] + "\n" log_utils.debug("the develop info is %s", proStr) targetFile = open(targetFilePath, 'wb') proStr = proStr.encode('UTF-8') targetFile.write(proStr) targetFile.close()
def pack(game, channel, sourcepath, isPublic): sourcepath = sourcepath.replace('\\', '/') if not os.path.exists(sourcepath): return 1 appID = game['appID'] appKey = game['appKey'] appName = game['appName'] channelId = channel["id"] channelName = channel["name"] sdkName = channel["sdk"] log_utils.info("now to package %s...", channelName) workDir = 'workspace/' + appName + '/' + channelName workDir = file_utils.getFullPath(workDir) file_utils.del_file_folder(workDir) tempApkSource = workDir + "/temp.apk" file_utils.copy_file(sourcepath, tempApkSource) decompileDir = workDir + "/decompile" ret = apk_utils.decompileApk(tempApkSource, decompileDir) if ret: return 2 #检查母包接入是否正确 # ret = apk_utils.checkApkForU8SDK(workDir, decompileDir) # if ret: # return 1 #检查multidex那个jar包 apk_utils.checkMultiDexJar(workDir, decompileDir) #更改XML配置等 newPackageName = apk_utils.renamePackageName(channel, decompileDir, channel['suffix'], isPublic) #复制第三插件资源。注意:这第三个插件必须在主SDK之前运行。 ret = apk_utils.handleThirdPlugins(workDir, decompileDir, game, channel, newPackageName) if ret: return 3 #将SDK代码复制到反编译程序 sdkSourceDir = file_utils.getFullPath('config/sdk/' + sdkName) smaliDir = decompileDir + "/smali" sdkDestDir = workDir + "/sdk/" + sdkName file_utils.copy_files(sdkSourceDir, sdkDestDir) if (not os.path.exists(sdkSourceDir + "/classes.dex")): ret = apk_utils.jar2dex(sdkSourceDir, sdkDestDir) if ret: return 4 ret = apk_utils.dexes2smali(sdkDestDir, smaliDir, "baksmali.jar") if ret: return 5 #复制主SDK资源。 ret = apk_utils.copyResource(game, channel, newPackageName, sdkDestDir, decompileDir, channel['operations'], channelName) if ret: return 6 #自动处理图标 apk_utils.appendChannelIconMark(game, channel, decompileDir) #复制渠道专用资源 ret = apk_utils.copyChannelResources(game, channel, decompileDir) if ret: return 7 #复制游戏根资源和资源 apk_utils.copyAppResources(game, decompileDir) apk_utils.copyAppRootResources(game, decompileDir) #生成APK运行的配置文件。 apk_utils.writeDevelopInfo(game, channel, decompileDir) apk_utils.writePluginInfo(channel, decompileDir) apk_utils.writeManifestMetaInfo(channel, decompileDir) apk_utils.writeLogConfig(game, decompileDir) #如果主SDK具有特殊逻辑。执行特殊的逻辑脚本。 ret = apk_utils.doSDKScript(channel, decompileDir, newPackageName, sdkDestDir) if ret: return 8 #如果游戏有一些特殊的逻辑。执行特殊的逻辑脚本。 post_script.py ret = apk_utils.doGamePostScript(game, channel, decompileDir, newPackageName) if ret: return 9 #here to config the splash screen. ret = apk_utils.addSplashScreen(workDir, channel, decompileDir) if ret: return 10 #检查CPU支持 apk_utils.checkCpuSupport(game, decompileDir) #如果指定频道,修改游戏名称。 apk_utils.modifyGameName(channel, decompileDir) #修改YML apk_utils.modifyYml(game, newPackageName, decompileDir) #到达复制sdk到临时目录 #生成新的R.java print('生成新的R.java') print(newPackageName) print(decompileDir) print(channel) print('===================================') ret = apk_utils.generateNewRFile(newPackageName, decompileDir, channel) if ret: return 11 #检查分离DEX apk_utils.splitDex(workDir, decompileDir) targetApk = workDir + "/output.apk" log_utils.debug("现在重新编译APK....") ret = apk_utils.recompileApk(decompileDir, targetApk) if ret: return 12 apk_utils.copyRootResFiles(targetApk, decompileDir) #复制根目录 ### #destApkName = channelName + '.apk' channelNameStr = channelName.replace(' ', '') if isPublic: # 获取最终apk包名 #destApkName = channelNameStr + '-' + time.strftime('%Y%m%d%H') + '.apk' destApkName = apk_utils.getOutputApkName(game, channel, newPackageName, decompileDir) else: destApkName = channelNameStr + '-' + time.strftime( '%Y%m%d%H') + '-debug.apk' destApkPath = file_utils.getFullOutputPath(appName, channelName) destApkPath = os.path.join(destApkPath, destApkName) ret = apk_utils.alignApk(targetApk, destApkPath) if ret: return 13 if 'signApk' not in channel or channel['signApk'] != '0': ret = apk_utils.signApk(workDir, game, channel, destApkPath) #对已经输出的安装包进行签名 if ret: return 14 else: log_utils.debug("APK设置为未签名。") #clear workspace #file_utils.del_file_folder(workDir) log_utils.info("游戏 %s 渠道 %s 打包成功.", appName, channelName) return 0
def copy_sdk(clientPath, outputPath, sdk, isPlugin=False): sdkFolder = 'sdk' if isPlugin: sdkFolder = 'plugin' sourcePath = os.path.join(clientPath, 'config/' + sdkFolder + '/' + sdk) if not os.path.exists(sourcePath): log_utils.error("the sdk path not exists:" + sourcePath) return False workspacePath = os.path.join(outputPath, 'workspace/' + sdkFolder + '/' + sdk) if not os.path.isabs(workspacePath): workspacePath = os.path.abspath(workspacePath) file_utils.del_file_folder(workspacePath) if not os.path.exists(workspacePath): os.makedirs(workspacePath) # copy sdk folder workSdkPath = os.path.join(workspacePath, 'sdk') file_utils.copy_files(sourcePath, workSdkPath) # handle gradle and aar # copy temp proj gradleProjDir = os.path.join(clientPath, 'config/local/U8_Temp_AS_Project') targetProjDir = os.path.join(workspacePath, 'U8_Temp_AS_Project') file_utils.copy_files(gradleProjDir, targetProjDir) sdkObj = read_sdk_config(workSdkPath, sdk) if 'dependencyList' in sdkObj and len(sdkObj['dependencyList']) > 0: log_utils.debug("begin to handle gradle dependencies:") try: ret = gradle_utils.handle_dependencies(workSdkPath, sdkObj['dependencyList']) if not ret: log_utils.error("gradle handle failed for :" + sdk) return False except Exception as e: log_utils.error("can not parse config.xml.path:" + configFile) log_utils.exception(e) return False # handle aar log_utils.debug("begin to handle aar for " + sdk) manifestNames = [ 'SDKManifest.xml', 'SDKManifest_portrait.xml', 'SDKManifest_landscape.xml' ] for m in manifestNames: if not os.path.exists(os.path.join(workSdkPath, m)): continue ret = aar_utils.handle_sdk_aars(sdkObj, workSdkPath, m) if not ret: log_utils.error("handle sdk aar files failed:", sdk) return False # copy assets in jar log_utils.debug("begin to copy assets in jars for sdk:" + sdk) copy_assets_in_jars(workSdkPath) # dump config.xml dump_sdk_config(workSdkPath, sdkObj) targetPath = os.path.join(outputPath, 'config/' + sdkFolder + '/' + sdk) file_utils.del_file_folder(targetPath) file_utils.copy_files(workSdkPath, targetPath) log_utils.debug("handle sdk success for :" + sdk)
source_apk_path = package_dic['source_apk'] else: print '{"status":0}' if package_dic.has_key('target_apk') and len( package_dic['target_apk']) > 0: target_apk_path = package_dic['target_apk'] else: print '{"status":0}' if package_dic.has_key('jy_ad') and len(package_dic['jy_ad']) > 0: jy_ad = package_dic['jy_ad'] else: print '{"status":0}' if os.path.exists(target_apk_path + '/' + jy_ad): file_utils.del_file_folder(target_apk_path + '/' + jy_ad) #创建目标临时文件 temp_apk = target_apk_path + '/' + jy_ad + '/' + jy_ad + '.apk' file_utils.copy_file(source_apk_path, temp_apk) #获取配置文件 ret, cmd, result = unrar(source_apk_path, 'assets/jy_public_config.json', target_apk_path + '/' + jy_ad) json_path = target_apk_path + '/' + jy_ad + '/jy_public_config.json' #修改配置参数 m_json_data = get_new_json(json_path, 'JY_AD', jy_ad) rewrite_json_file(json_path, m_json_data) #将配置文件当道新的assets目录下并删除原有配置文件
def pack(game, channel, sourcepath, isPublic): sourcepath = sourcepath.replace("\\", "/") if not os.path.exists(sourcepath): return 1 appID = game["appID"] appKey = game["appKey"] appName = game["appName"] channelId = channel["id"] channelName = channel["name"] sdkName = channel["sdk"] log_utils.info("now to package %s...", channelName) workDir = "workspace/" + appName + "/" + channelName workDir = file_utils.getFullPath(workDir) file_utils.del_file_folder(workDir) tempApkSource = workDir + "/temp.apk" file_utils.copy_file(sourcepath, tempApkSource) decompileDir = workDir + "/decompile" ret = apk_utils.decompileApk(tempApkSource, decompileDir) if ret: return 1 # 检查母包接入是否正确 # ret = apk_utils.checkApkForU8SDK(workDir, decompileDir) # if ret: # return 1 # copy sdk code to decompileDir sdkSourceDir = file_utils.getFullPath("config/sdk/" + sdkName) smaliDir = decompileDir + "/smali" sdkDestDir = workDir + "/sdk/" + sdkName file_utils.copy_files(sdkSourceDir, sdkDestDir) if not os.path.exists(sdkSourceDir + "/classes.dex"): apk_utils.jar2dex(sdkSourceDir, sdkDestDir) sdkDexFile = sdkDestDir + "/classes.dex" ret = apk_utils.dex2smali(sdkDexFile, smaliDir, "baksmali.jar") if ret: return 1 # change xml config and so on newPackageName = apk_utils.renamePackageName(channel, decompileDir, channel["suffix"], isPublic) # copy third-plugins resources. note:The third plugins must be operated before the main sdk. ret = apk_utils.handleThirdPlugins(workDir, decompileDir, game, channel, newPackageName) if ret: return 1 # copy main sdk resources. ret = apk_utils.copyResource( game, channel, newPackageName, sdkDestDir, decompileDir, channel["operations"], channelName ) if ret: return 1 # copy channel special resources ret = apk_utils.copyChannelResources(game, channel, decompileDir) if ret: return 1 # copy game root resources and res resources apk_utils.copyAppResources(game, decompileDir) apk_utils.copyAppRootResources(game, decompileDir) apk_utils.appendChannelIconMark(game, channel, decompileDir) # generate config files for apk to run. apk_utils.writeDevelopInfo(appID, appKey, channel, decompileDir) apk_utils.writePluginInfo(channel, decompileDir) apk_utils.writeManifestMetaInfo(channel, decompileDir) # if the main sdk has special logic. execute the special logic script. ret = apk_utils.doSDKScript(channel, decompileDir, newPackageName, sdkDestDir) if ret: return 1 # if the game has some special logic. execute the special logic script.called post_script.py ret = apk_utils.doGamePostScript(game, channel, decompileDir, newPackageName) if ret: return 1 # here to config the splash screen. ret = apk_utils.addSplashScreen(workDir, channel, decompileDir) if ret: return 1 # check cpu supports apk_utils.checkCpuSupport(game, decompileDir) # modify game name if channel specified. apk_utils.modifyGameName(channel, decompileDir) # generate new R.java ret = apk_utils.generateNewRFile(newPackageName, decompileDir) if ret: return 1 targetApk = workDir + "/output.apk" ret = apk_utils.recompileApk(decompileDir, targetApk) if ret: return 1 apk_utils.copyRootResFiles(targetApk, decompileDir) ret = apk_utils.signApk(appName, channelId, targetApk) if ret: return 1 # destApkName = channelName + '.apk' channelNameStr = channelName.replace(" ", "") if isPublic: destApkName = channelNameStr + "-" + time.strftime("%Y%m%d%H") + ".apk" else: destApkName = channelNameStr + "-" + time.strftime("%Y%m%d%H") + "-debug.apk" destApkPath = file_utils.getFullOutputPath(appName, channelName) destApkPath = os.path.join(destApkPath, destApkName) ret = apk_utils.alignApk(targetApk, destApkPath) if ret: return 1 # clear workspace # file_utils.del_file_folder(workDir) log_utils.info("channel %s package success.", channelName) return 0
def pack(game, channel, sourcepath, isPublic): sourcepath = sourcepath.replace('\\', '/') if not os.path.exists(sourcepath): return 1 appID = game['appID'] appKey = game['appKey'] appName = game['appName'] channelId = channel["id"] channelName = channel["name"] sdkName = channel["sdk"] log_utils.info("now to package %s...", channelName) workDir = 'workspace/' + appName + '/' + channelName workDir = file_utils.getFullPath(workDir) file_utils.del_file_folder(workDir) tempApkSource = workDir + "/temp.apk" file_utils.copy_file(sourcepath, tempApkSource) decompileDir = workDir + "/decompile" ret = apk_utils.decompileApk(tempApkSource, decompileDir) if ret: return 1 #检查母包接入是否正确 # ret = apk_utils.checkApkForU8SDK(workDir, decompileDir) # if ret: # return 1 #检查multidex那个jar包 apk_utils.checkMultiDexJar(workDir, decompileDir) #change xml config and so on newPackageName = apk_utils.renamePackageName(channel, decompileDir, channel['suffix'], isPublic) #copy third-plugins resources. note:The third plugins must be operated before the main sdk. ret = apk_utils.handleThirdPlugins(workDir, decompileDir, game, channel, newPackageName) if ret: return 1 #copy sdk code to decompileDir sdkSourceDir = file_utils.getFullPath('config/sdk/' + sdkName) smaliDir = decompileDir + "/smali" sdkDestDir = workDir + "/sdk/" + sdkName file_utils.copy_files(sdkSourceDir, sdkDestDir) if (not os.path.exists(sdkSourceDir + "/classes.dex")): ret = apk_utils.jar2dex(sdkSourceDir, sdkDestDir) if ret: return 1 ret = apk_utils.dexes2smali(sdkDestDir, smaliDir, "baksmali.jar") if ret: return 1 #copy main sdk resources. ret = apk_utils.copyResource(game, channel, newPackageName, sdkDestDir, decompileDir, channel['operations'], channelName) if ret: return 1 #auto handle icon apk_utils.appendChannelIconMark(game, channel, decompileDir) #copy channel special resources ret = apk_utils.copyChannelResources(game, channel, decompileDir) if ret: return 1 #copy game root resources and res resources apk_utils.copyAppResources(game, decompileDir) apk_utils.copyAppRootResources(game, decompileDir) #generate config files for apk to run. apk_utils.writeDevelopInfo(game, channel, decompileDir) apk_utils.writePluginInfo(channel, decompileDir) apk_utils.writeManifestMetaInfo(channel, decompileDir) apk_utils.writeLogConfig(game, decompileDir) #if the main sdk has special logic. execute the special logic script. ret = apk_utils.doSDKScript(channel, decompileDir, newPackageName, sdkDestDir) if ret: return 1 #if the game has some special logic. execute the special logic script.called post_script.py ret = apk_utils.doGamePostScript(game, channel, decompileDir, newPackageName) if ret: return 1 #here to config the splash screen. ret = apk_utils.addSplashScreen(workDir, channel, decompileDir) if ret: return 1 #check cpu supports apk_utils.checkCpuSupport(game, decompileDir) #modify game name if channel specified. apk_utils.modifyGameName(channel, decompileDir) #modify yml apk_utils.modifyYml(game, newPackageName, decompileDir) #generate new R.java ret = apk_utils.generateNewRFile(newPackageName, decompileDir, channel) if ret: return 1 #check to split dex apk_utils.splitDex(workDir, decompileDir) targetApk = workDir + "/output.apk" log_utils.debug("now to recompileApk....") ret = apk_utils.recompileApk(decompileDir, targetApk) if ret: return 1 apk_utils.copyRootResFiles(targetApk, decompileDir) if 'signApk' not in channel or channel['signApk'] != '0': ret = apk_utils.signApk(workDir, game, channel, targetApk) if ret: return 1 else: log_utils.debug("the apk is set to unsigned.") #destApkName = channelName + '.apk' channelNameStr = channelName.replace(' ', '') if isPublic: #destApkName = channelNameStr + '-' + time.strftime('%Y%m%d%H') + '.apk' destApkName = apk_utils.getOutputApkName(game, channel, newPackageName, decompileDir) else: destApkName = channelNameStr + '-' + time.strftime( '%Y%m%d%H') + '-debug.apk' destApkPath = file_utils.getFullOutputPath(appName, channelName) destApkPath = os.path.join(destApkPath, destApkName) ret = apk_utils.alignApk(targetApk, destApkPath) if ret: return 1 #clear workspace #file_utils.del_file_folder(workDir) log_utils.info("channel %s package success.", channelName) return 0
def writeDeveloperProperties(game, channel, targetFilePath): targetFilePath = file_utils.getFullPath(targetFilePath) if os.path.exists(targetFilePath): file_utils.del_file_folder(targetFilePath) proStr = "" if channel['params'] != None and len(channel['params']) > 0: for param in channel['params']: if param['bWriteInClient'] == '1': proStr = proStr + param['name'] + "=" + param['value'] + "\n" if "sdkLogicVersionCode" in channel: proStr = proStr + "U8_SDK_VERSION_CODE=" + channel[ "sdkLogicVersionCode"] + "\n" if "isMutiPay" in channel and channel['isMutiPay'] != None: proStr = proStr + "isMutiPay=" + channel['isMutiPay'] + "\n" proStr = proStr + "U8_Channel=" + channel['id'] + "\n" proStr = proStr + "U8_APPID=" + game["appID"] + "\n" proStr = proStr + "U8_APPKEY=" + game["appKey"] + "\n" if "payPrivateKey" in game: proStr = proStr + "U8_PAY_PRIVATEKEY=" + game["payPrivateKey"] + "\n" showSplash = "false" if "splash" in channel and int(channel["splash"]) > 0: showSplash = "true" proStr = proStr + "U8_SDK_SHOW_SPLASH=" + showSplash + "\n" authUrl = None orderUrl = None analyticsUrl = None u8serverUrl = None u8analytics = None if "u8_auth_url" in game: authUrl = game["u8_auth_url"] if "u8_order_url" in game: orderUrl = game["u8_order_url"] if "u8_analytics_url" in game: analyticsUrl = game["u8_analytics_url"] if "u8server_url" in game: u8serverUrl = game["u8server_url"] if "u8_analytics" in game: u8analytics = game["u8_analytics"] #append u8 local config local_config = getLocalConfig() if authUrl is None and "u8_auth_url" in local_config: authUrl = local_config['u8_auth_url'] if orderUrl is None and "u8_order_url" in local_config: orderUrl = local_config['u8_order_url'] if u8serverUrl is None and "u8server_url" in local_config: u8serverUrl = local_config['u8server_url'] if u8analytics is None and "u8_analytics" in local_config: u8analytics = local_config['u8_analytics'] if analyticsUrl is None and "u8_analytics_url" in local_config: analyticsUrl = local_config['u8_analytics_url'] if authUrl is not None: proStr = proStr + "U8_AUTH_URL=" + authUrl + "\n" if orderUrl is not None: proStr = proStr + "U8_ORDER_URL=" + orderUrl + "\n" if analyticsUrl is not None: proStr = proStr + "U8_ANALYTICS_URL=" + analyticsUrl + "\n" if u8serverUrl is not None: proStr = proStr + "U8SERVER_URL=" + u8serverUrl + "\n" if u8analytics is not None: proStr = proStr + "U8_ANALYTICS=" + u8analytics + "\n" #write third plugin info: plugins = channel.get('third-plugins') if plugins != None and len(plugins) > 0: for plugin in plugins: if 'params' in plugin and plugin['params'] != None and len( plugin['params']) > 0: for param in plugin['params']: if param['bWriteInClient'] == '1': proStr = proStr + param['name'] + "=" + param[ 'value'] + "\n" log_utils.debug("the develop info is %s", proStr) targetFile = open(targetFilePath, 'wb') proStr = proStr.encode('UTF-8') targetFile.write(proStr) targetFile.close()
def doPack(package_info): channelConfig, logger, logfilepath = getChannelConfig(package_info) workDirCls = dir_utils.WorkDirCls( rootDir, channelConfig['game_info']['game_id'], channelConfig['game_info']['game_bundle_id'], channelConfig['game_info']['channel_flag'], channelConfig['game_info']['channel_version']) logger.info(channelConfig) workDir = workDirCls.workRootDir if not os.path.exists(workDir): os.makedirs(workDir) # 反编译apk logger.info('clean workdir') file_utils.del_file_folder(workDir) logger.info("copy sourceapk to workdir") apkSource = os.path.join(workDir, 'temp.apk') file_utils.copy_file(channelConfig['game_info']['source_apk'], apkSource) logger.info("decompile apk") ret, cmd, result = apk_utils.decompileApk(apkSource, workDirCls.workDecompileDir, apktoolPath) ###反编译 logger.info(cmd) logger.info(str(ret) + "======" + result) #删除原SDK相关内容 logger.info("delete default sdk info") ret, result = apk_utils.removeDefaultSDKInfo(workDirCls.workDecompileDir, defaultSDKInfoConfigFile) logger.info(str(ret) + "======" + result) # 对资源进行特殊处理(删除layout-v26/abc_screen_toolbar.xml中的android:keyboardNavigationCluster、删除drawable-v24/ic_launcher_foreground.xml中的android:fillType) logger.info("handle special resource") ret, result = apk_utils.handleSpecialResource(workDirCls.workDecompileDir) logger.info(str(ret) + "======" + result) #拷贝sdk插件到工作目录 logger.info("copy sdk plugin to workdir") #拷贝渠道SDK到工作目录 channelSdk = os.path.join(channelSdkPath, channelConfig['game_info']['channel_flag'], channelConfig['game_info']['channel_version']) file_utils.copy_files(channelSdk, workDirCls.workSDKDir) #拷贝媒体SDK到工作目录 if channelConfig['ad_sdk'].has_key( 'media_flag') and channelConfig['ad_sdk']['media_flag'] > 0: madiaSdk = os.path.join(mediaSdkPath, channelConfig['ad_sdk']['media_flag'], channelConfig['game_info']['media_version']) file_utils.copy_files(madiaSdk, workDirCls.workSDKDir) #copy头条aar #logger.info("if has toutiao, copy toutiao plugin to workdir") #if channelConfig['ad_sdk'].has_key('tt_id') and len(channelConfig['ad_sdk']['tt_id']) > 0: # toutiaoPluginDir = os.path.join(workDirCls.channelsDir, 'toutiao') # file_utils.copy_files(toutiaoPluginDir, workDirCls.workSDKDir) #copy广点通aar #logger.info("if has gdt, copy gdt plugin to workdir") #if channelConfig['ad_sdk'].has_key('gdt_id') and channelConfig['ad_sdk'].has_key('gdt_secret_key') and len(channelConfig['ad_sdk']['gdt_id']) > 0 and len(channelConfig['ad_sdk']['gdt_secret_key']) > 0: # gdtPluginDir = os.path.join(workDirCls.channelsDir, 'gdt') # file_utils.copy_files(gdtPluginDir, workDirCls.workSDKDir) #copy快手aar #logger.info("if has kuaishou, copy kuaishou plugin to workdir") #if channelConfig['ad_sdk'].has_key('ks_id') and len(channelConfig['ad_sdk']['ks_id']) > 0 and channelConfig['ad_sdk'].has_key('ks_name') and len(channelConfig['ad_sdk']['ks_name']) > 0: # kuaishouPluginDir = os.path.join(workDirCls.channelsDir, 'kuaishou') # file_utils.copy_files(kuaishouPluginDir, workDirCls.workSDKDir) #copy独代aar #logger.info("if has dudai, copy dudai plugin to workdir") #if channelConfig['game_info'].has_key('is_dudai') and channelConfig['game_info']['is_dudai'] == 'true': # dudaiPluginDir = os.path.join(workDirCls.channelsDir, 'dudai') # file_utils.copy_files(dudaiPluginDir, workDirCls.workSDKDir) #aar模式需进行解压和资源合并 logger.info("in workdir, unzip aar and zip, then merge") if apk_utils.isAarMode(workDirCls.workSDKDir): apk_utils.unzipAarFiles(workDirCls.workSDKDir) apk_utils.mergeAarFiles(workDirCls.workSDKDir) # copy libs(.jar除外) logger.info("copy sdk libs(except jar) to decompile dir") ret, result = apk_utils.copyLibs( os.path.join(workDirCls.workSDKDir, 'libs'), os.path.join(workDirCls.workDecompileDir, 'lib')) logger.info(str(ret) + "======" + result) # 处理lib文件夹,仅保留一个,防止不一致导致部分机型崩溃 logger.info("handle lib dir(cpu type)") ret, result = apk_utils.deleteOtherLibDir( os.path.join(workDirCls.workDecompileDir, 'lib'), channelConfig['game_info']['partner_id']) logger.info(str(ret) + "======" + result) #copy 渠道res logger.info("copy sdk res to decompile res dir") ret, result = apk_utils.copyResToApk( os.path.join(workDirCls.workSDKDir, 'res'), os.path.join(workDirCls.workDecompileDir, 'res')) logger.info(str(ret) + "======" + result) #copy 渠道assets logger.info("copy sdk assets to decompile assets dir") ret, result = apk_utils.copyResToApk( os.path.join(workDirCls.workSDKDir, 'assets'), os.path.join(workDirCls.workDecompileDir, 'assets')) logger.info(str(ret) + "======" + result) #copy 其他资源 logger.info("copy sdk other res to decompile dir") ret, result = apk_utils.copyOtherResToApk(workDirCls.workSDKDir, workDirCls.workDecompileDir) logger.info(str(ret) + "======" + result) #配置写入 独代配置暂时写死,没有更新 logger.info("update conf file()") apk_utils.updateConfFile(channelConfig, workDirCls.workDecompileDir) #修改apktool.yml 版本号 targetSdkVersion logger.info( "update apktool.yml, include targetSdkVersion, version_code etc.") apk_utils.updateApktoolYmlFile(channelConfig, workDirCls.workDecompileDir) #修改包名,合并manifest 2019-08-01新增:应用宝渠道,在主activity里面添加url scheme 格式:scheme://host/path(path为分包名) logger.info("merge manifest") ret, result, oldPackageName = apk_utils.mergeManifest( os.path.join(workDirCls.workDecompileDir, 'AndroidManifest.xml'), os.path.join(workDirCls.workSDKDir, 'sdkmanifest.xml'), channelConfig) logger.info(str(ret) + "======" + result) #替换AndroidManifest里面的占位符 logger.info("replace placeholder in manifest") apk_utils.replaceSpecialString( os.path.join(workDirCls.workDecompileDir, 'AndroidManifest.xml'), channelConfig, oldPackageName) #修改应用名称 logger.info("update app display name") ret, result = apk_utils.updateAppDisplayName( workDirCls.workDecompileDir, channelConfig['game_info']['game_name']) logger.info(str(ret) + "======" + result) apk_utils.handle_drawable_v4(workDirCls.workDecompileDir) #修改icon if channelConfig['game_info'].has_key( 'icon_file') and channelConfig['game_info'].has_key('icon_name'): logger.info("handle app icon") ret, result = apk_utils.handlePackageIcon( channelConfig['game_info']['icon_file'], workDirCls.workDecompileDir, channelConfig['game_info']['icon_name']) logger.info(str(ret) + "======" + result) #替换游戏素材(闪屏、loading、登录背景图) logger.info("replace app resource") if channelConfig['game_info'].has_key('game_resources') and len( channelConfig['game_info']['game_resources'] ) > 0 and channelConfig['game_info'].has_key('resource_path') and len( channelConfig['game_info']['resource_path']) > 0: oldGameResourcePath = os.path.join( workDirCls.workDecompileDir, channelConfig['game_info']['resource_path'].replace('/', os.sep)) for newGameResourcePath in channelConfig['game_info'][ 'game_resources']: file_utils.copy_file( newGameResourcePath, os.path.join(oldGameResourcePath, os.path.basename(newGameResourcePath))) #重新生成R文件,编译,然后生成jar包搭配渠道的libs目录下 logger.info("generate R file") ret, cmd, result = apk_utils.generateNewRFile( oldPackageName, channelConfig['game_info']['game_bundle_id'], workDirCls.workDecompileDir, toolsDir, channelConfig) logger.info(cmd) logger.info(str(ret) + "======" + result) #jar to dex logger.info("convert jar to dex") if not os.path.exists( os.path.join(workDirCls.currentChannelDir, "classes.dex")): ret, cmd, result = apk_utils.jar2dex(workDirCls.workSDKDir, workDirCls.workSDKDir, channelConfig) logger.info(cmd) logger.info(str(ret) + "======" + result) #dex to smali logger.info("convert dex to smali") sdkDexFile = os.path.join(workDirCls.workSDKDir, "classes.dex") ret, cmd, result = apk_utils.dex2smali(sdkDexFile, workDirCls.workDecompileSmaliDir, baksmaliJarPath) logger.info(cmd) logger.info(str(ret) + "======" + result) #应用宝/小米 多Dex处理 if channelConfig['game_info']['partner_id'] == '3' or channelConfig[ 'game_info']['partner_id'] == '9': logger.info("handle multi dex") apk_utils.splitDex(workDirCls.workDecompileDir) # 处理需要特殊处理的smali文件 apk_utils.handleSmali(channelConfig, workDirCls.workDecompileDir) #重新编译 logger.info("compile new apk") targetApkFile = os.path.join(workDirCls.workTempDir, "output.apk") ret, cmd, result = apk_utils.recompileApk(workDirCls.workTempDir, workDirCls.workDecompileDir, targetApkFile, apktoolPath) logger.info(cmd) logger.info(str(ret) + "======" + result) #签名 logger.info("sign apk") signInfo = { "keystore": os.path.join(commonConfigDir, '7yol_default.keystore'), "password": "******", "aliaskey": "7yol_default", "aliaspwd": "Aa314159" } ret, cmd, result = apk_utils.signApk(targetApkFile, signInfo) logger.info(cmd) logger.info(str(ret) + "======" + result) #对齐 logger.info("align apk") targetZApk = os.path.join(workDirCls.workTempDir, "outputZ.apk") ret, cmd, result = apk_utils.alignApk(zipalignToolPath, targetApkFile, targetZApk) logger.info(cmd) logger.info(str(ret) + "======" + result) #copy到target目录 logger.info("copy apk to target dir") targetApkFileName = os.path.splitext(os.path.basename(logfilepath))[0] targetApkFilePath = os.path.join( channelConfig['game_info']['target_apk'], channelConfig['game_info']['game_id'], channelConfig['game_info']['channel_flag'], channelConfig['game_info']['game_bundle_id'], targetApkFileName + '.apk') file_utils.copy_file(targetZApk, targetApkFilePath) if os.path.exists(targetApkFilePath): logger.info("pack success!!!===target apk is: %s" % targetApkFilePath) print '{"status":1, "apkPath":"%s", "logPath": "%s"}' % ( targetApkFilePath, logfilepath) else: logger.info("pack fail") print '{"status":0, "logPath": "%s"}' % (logfilepath)