import fs from 'fs'; import path from 'path'; import compressing from 'compressing'; import child_process from 'child_process'; import XXTea from './XXTea'; const XXTEA_KEY = 'ba5c2f3d-e52f-48'; const ANDROID_BUILD_TOOLS = 'D:\\Android\\SDK\\build-tools\\30.0.3'; const KEYSTOTE = path.join(__dirname, 'lib', 'keystore', 'fish.jks'); const KEYSTOTE_PASSWORD = 'fish123456'; const KEYSTOTE_ALIAS = 'paopaobuyu'; const KEYSTOTE_ALIAS_PASSWORD = 'fish123456'; const unzipApk = async (apkPath: string): Promise => { const dirPath = path.dirname(apkPath); const outputPath = path.join(dirPath, '.___apk'); const newApkPath = path.join(dirPath, path.basename(apkPath, '.apk') + '_poco.apk'); console.log('创建输出目录'); fs.existsSync(outputPath) && removeFile(outputPath); fs.mkdirSync(outputPath); console.log('游戏解包'); await compressing.zip.uncompress(apkPath, outputPath); console.log('删除证书'); removeFile(path.join(outputPath, 'META-INF')); console.log('替换引擎库'); copyFile(path.join(__dirname, 'lib', 'so', 'libcocos2djs.so'), path.join(outputPath, 'lib', 'armeabi-v7a', 'libcocos2djs.so')); console.log('添加PocoSDK'); copyFile(path.join(__dirname, 'lib', 'sdk', 'Poco.js'), path.join(outputPath, 'assets', 'Poco.js')); console.log('修改入口脚本'); const scriptPath = path.join(outputPath, 'assets', 'main.js'); fs.existsSync(scriptPath) ? hackMain(scriptPath) : hackMain(scriptPath + 'c'); console.log('游戏打包'); removeFile(newApkPath); await compressing.zip.compressDir(outputPath, newApkPath, { ignoreBase: true }); console.log('删除临时文件'); removeFile(outputPath); console.log('游戏重新签名'); const signCmd = `${path.join(ANDROID_BUILD_TOOLS, 'apksigner')} sign --ks ${KEYSTOTE} --ks-pass pass:${KEYSTOTE_PASSWORD} --ks-key-alias ${KEYSTOTE_ALIAS} --key-pass pass:${KEYSTOTE_ALIAS_PASSWORD} ${newApkPath} `; child_process.execSync(signCmd); removeFile(newApkPath + '.idsig'); console.log('完成'); } const removeFile = (filePath: string): void => { if (!fs.existsSync(filePath)) return; const stat = fs.statSync(filePath); if (stat.isDirectory()) { const subFiles = fs.readdirSync(filePath); subFiles.forEach(value => removeFile(path.join(filePath, value))); fs.rmdirSync(filePath); } else { fs.unlinkSync(filePath); } } const copyFile = (filePath: string, destPath: string): void => { const stat = fs.statSync(filePath); if (stat.isDirectory()) { fs.existsSync(destPath) || fs.mkdirSync(destPath); const subFiles = fs.readdirSync(filePath); subFiles.forEach(value => copyFile(path.join(filePath, value), path.join(destPath, value))); } else { fs.existsSync(destPath) && removeFile(destPath); fs.copyFileSync(filePath, destPath); } } const hackMain = (scriptPath: string, isEncrypt: boolean = false): void => { let script = fs.readFileSync(scriptPath).toString(); if (isEncrypt) script = XXTea.decrypt(script, XXTEA_KEY); script = script.replace( 'var launchScene = settings.launchScene;', 'var launchScene = settings.launchScene; \n' + 'require("Poco.js"); \n' ) if (isEncrypt) script = XXTea.encrypt(script, XXTEA_KEY); fs.writeFileSync(scriptPath, script); } const apkPath = process.argv[2]; unzipApk(apkPath);