import file_utils import common_utils import xml_utils import os.path import xml.etree.ElementTree as ET import zipfile namespaces = {'android' : 'http://schemas.android.com/apk/res/android'} encoding = 'UTF-8' def execute(game, sdk, config): if not checkConfig(config): return 1 subChannel = config['subChannel'] createJmhyProperties(game, sdk, subChannel, config) createEjyxProperties(game, sdk, subChannel, config) #ret = deleteSplash(game, sdk, subChannel, config) ret = generateV7RFile(game, sdk, subChannel, config) if ret: return ret common_utils.changeApplication(game, sdk, subChannel, config, 'com.ejyx.common.EJYXApplication') return 0 def checkConfig(config): ''' 检查配置 ''' if 'properties' not in config: print('properties not exists in config') return False properties = config['properties'] if 'agent' not in properties or 'version' not in properties: print('agent or version not exists in properties') return False '''if 'appid' not in config or 'appkey' not in config: print('appid or appkey not exists in config') return False''' return True def createJmhyProperties(game, sdk, subChannel, config): ''' 创建jmhy.properties ''' print('create jmhy.properties') propValue = config['properties'] decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache']) properties = os.path.join(decompliePath, 'assets', 'jmhy.properties') content = '' for key in propValue: content = '%s%s=%s\n' % (content, key, propValue[key]) file_utils.createFile(properties, content) return 0 def createEjyxProperties(game, sdk, subChannel, config): ''' 创建jmhy.properties ''' print('创建 ejyx.properties ......') decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache']) properties = os.path.join(decompliePath, 'assets', 'ejyx.properties') content = 'version=1.1\n' content = '%s%s=%s\n' % (content, 'agent', config['channel_id']) file_utils.createFile(properties, content) return 0 def deleteSplash(game, sdk, subChannel, config): ''' 删除闪屏 ''' if game != 'wzjh': return 0 channelPath = file_utils.getSubChannelPath(game, sdk, subChannel) print('delete Splash...') decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache']) manifest = os.path.join(decompliePath, 'AndroidManifest.xml') activity = xml_utils.getLauncherActivityName(manifest) activity = xml_utils.removeLauncherActivity(manifest) xml_utils.deleteActivityByName(manifest,'com.hugenstar.nanobox.NaNoUnityContext') addLauncherActivity(manifest, config['screenOrientation'], 'com.hugenstar.nanobox.NaNoUnityContext') return 0 def addLauncherActivity(manifest, screenOrientation, activity): ''' 添加启动的activity ''' for key in namespaces: ET.register_namespace(key, namespaces[key]) tree = ET.parse(manifest) root = tree.getroot() # activity ''' ''' activity = ET.Element('activity', {'android:name' : activity, 'android:theme' : '@android:style/Theme.Holo.Light.NoActionBar.Fullscreen', 'android:launchMode' : 'singleTop', 'android:configChanges' : 'orientation|screenSize|keyboardHidden', 'android:screenOrientation' : screenOrientation}) intent = ET.Element('intent-filter') action = ET.Element('action', {'android:name' : 'android.intent.action.MAIN'}) category = ET.Element('category', {'android:name' : 'android.intent.category.LAUNCHER'}) intent.append(action) intent.append(category) activity.append(intent) intent2 = ET.Element('intent-filter') category = ET.Element('category', {'android:name' : 'android.intent.category.LEANBACK_LAUNCHER'}) intent2.append(category) activity.append(intent2) application = root.find('application') application.insert(0, activity) tree.write(manifest, encoding) def generateV7RFile(game, sdk, subChannel, config): ''' 生成新的R文件 ''' decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache']) androidPlatforms = file_utils.getAndroidCompileToolPath() manifest = os.path.join(decompliePath, 'assets','AndroidManifest.xml') decomplieResPath = file_utils.getFullPath(decompliePath, 'res') compliePath = file_utils.getFullPath(decompliePath, 'gen') if not os.path.exists(compliePath): os.makedirs(compliePath) # 生成R文件 print('生成R文件 ...') if config['aapt2disable']: aapt = file_utils.getAAPTPath() ret = file_utils.getExecPermission(aapt) if ret: return ret createRCmd = '"%s" p -f -m -J "%s" -S "%s" -I "%s" -M "%s"' % (aapt, compliePath, decomplieResPath, androidPlatforms, manifest) ret = file_utils.execFormatCmd(createRCmd) if ret: return ret else: # compile aapt = file_utils.getAAPT2Path() ret = file_utils.getExecPermission(aapt) if ret: return ret print('compiled res ...') complieResPath = os.path.join(compliePath, 'compiled') complieResCmd = '"%s" compile --dir "%s" -o "%s"' % (aapt, decomplieResPath, complieResPath) file_utils.execFormatCmd(complieResCmd) # unzip print('unzip compiled res ...') unzipResPath = os.path.join(compliePath, 'aapt2_res') with zipfile.ZipFile(complieResPath) as zf: zf.extractall(unzipResPath) print('create unzip %s' % unzipResPath) # link print('link res ...') outApk = os.path.join(compliePath, 'res.apk') linkResCmd = '"%s" link -o "%s" -I "%s" --manifest "%s" --java "%s" --auto-add-overlay' % (aapt, outApk, androidPlatforms, manifest, compliePath) for filename in os.listdir(unzipResPath): linkResCmd += ' %s' % filename print('link cmd len is %s' % len(linkResCmd)) ret = file_utils.execFormatCmd(linkResCmd, unzipResPath) if ret: return ret # 编译R文件 print('complie R.java ...') packageName = xml_utils.getPackageName(manifest) packagePath = file_utils.getPackagePath(compliePath, packageName) RSourceFile = os.path.join(packagePath, 'R.java') complieRCmd = 'javac -source 1.8 -target 1.8 -encoding UTF-8 "%s"' % RSourceFile ret = file_utils.execFormatCmd(complieRCmd) if ret: return ret # 生成dex print('dex R.class ...') outDex = os.path.join(compliePath, 'classes.dex') if config['aapt2disable']: dx = file_utils.getDxPath() dexCmd = '--dex --no-warning --output="%s" "%s"' % (outDex, compliePath) else: dx = file_utils.getD8Path() clazz = os.path.join(packagePath, '*.class') dexCmd = '--lib "%s" --output "%s" %s' % (androidPlatforms, compliePath, clazz) ret = file_utils.execJarCmd(dx, dexCmd) if ret: return ret # 反向dex生成smali # 存放在out目录 print('baksmali classes.dex ...') baksmaliPath = file_utils.getBaksmaliPath() outPath = file_utils.getFullPath(decompliePath, 'out') ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath)) if ret: return ret # 将生成的文件拷贝到目标目录 print('copy R.smali ...') smaliPath = file_utils.getFullPath(decompliePath, 'smali') file_utils.copyFileAllDir(outPath, smaliPath) return 0