package_utils_record.py 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246
  1. # 安卓游戏打包脚本
  2. # 1.用apktool解包
  3. # 2.复制res资源、assets资源、jniLib资源
  4. # 3.修改包名、app名、渠道文件
  5. # 4.添加app icon、合并AndroidManifest文件
  6. # 5.添加app启动图,修改AndroidManifest文件
  7. # 6.生成新的R文件
  8. # 7.将新的R文件编译,生成dex,再用baksmali生成smali,替换旧的R文件
  9. # 8.将jar资源打包成dex,再用baksmali生成smali,拷贝到smali目录下
  10. # 9.统计方法量,并分割dex(将smali文件拷贝到目录smali_classes2)
  11. # 10.用apktool回包
  12. # 11.重新签名
  13. import file_utils
  14. import xml_utils
  15. import smali_utils
  16. import config_utils_record
  17. import game_utils
  18. import os
  19. import os.path
  20. import json
  21. import sys
  22. import importlib
  23. import uuid
  24. import zipfile
  25. from xml.etree import ElementTree as ET
  26. from xml.etree.ElementTree import SubElement
  27. def pack(game, sdk, config):
  28. config['cache'] = uuid.uuid1()
  29. subChannel = config['subChannel']
  30. # 解包
  31. ret = decomplie(game, sdk, subChannel, config)
  32. if ret:
  33. return ret
  34. # 删除旧代码
  35. ret = removeOldCode(game, sdk, subChannel, config)
  36. if ret:
  37. return ret
  38. if 'deleteList' in config:
  39. # 删除旧资源
  40. ret = removeOldRes(game, sdk, subChannel, config)
  41. if ret:
  42. return ret
  43. # 删除一些不支持的属性
  44. ret = removeNoSupportAttr(game, sdk, subChannel, config)
  45. if ret:
  46. return ret
  47. # 删除一些不支持的配置
  48. ret = fixUnSupportConfig(game, sdk, subChannel, config)
  49. if ret:
  50. return ret
  51. # 合并Drawable-v4目录
  52. ret = mergeDrawableRes(game, sdk, subChannel, config)
  53. if ret:
  54. return ret
  55. # 移除相同的资源
  56. ret = removeSameRes(game, sdk, subChannel, config)
  57. if ret:
  58. return ret
  59. # 复制res资源
  60. ret = copyRes(game, sdk, subChannel, config)
  61. if ret:
  62. return ret
  63. # 合并主文件
  64. ret = mergeManifestRes(game, sdk, subChannel, config)
  65. if ret:
  66. return ret
  67. # 替换占位符
  68. ret = changePlaceholders(game, sdk, subChannel, config)
  69. if ret:
  70. return ret
  71. # 添加meta-data
  72. ret = addMetaData(game, sdk, subChannel, config)
  73. if ret:
  74. return ret
  75. # 复制app res资源
  76. ret = copyAppRes(game, sdk, subChannel, config)
  77. if ret:
  78. return ret
  79. # 合并语言文件
  80. ret = mergeLanguage(game, sdk, subChannel, config)
  81. if ret:
  82. return ret
  83. # 增加配置文件
  84. ret = addConfig(game, sdk, subChannel, config)
  85. if ret:
  86. return ret
  87. #保存旧包名
  88. config['oldPackageName'] = getPackageName(game, sdk, subChannel, config)
  89. # 更改包名
  90. if 'packageName' in config and config['packageName'] != '':
  91. ret = changePackageName(game, sdk, subChannel, config)
  92. if ret:
  93. return ret
  94. else:
  95. config['packageName'] = getPackageName(game, sdk, subChannel, config)
  96. # 更改app名
  97. if 'name' in config and config['name'] != '':
  98. ret = changeAppName(game, sdk, subChannel, config)
  99. if ret:
  100. return ret
  101. # 更改app icon
  102. if config['changeIcon']:
  103. ret = changeAppIcon(game, sdk, subChannel, config)
  104. if ret:
  105. return ret
  106. # 添加启动图操作
  107. if config['addLauncher']:
  108. ret = addLauncher(game, sdk, subChannel, config)
  109. if ret:
  110. return ret
  111. # 打包lib依赖
  112. ret = packJar(game, sdk, subChannel, config)
  113. if ret:
  114. return ret
  115. # sdk脚本处理
  116. ret = doSDKPostScript(game, sdk, config)
  117. if ret:
  118. return ret
  119. # 乐变sdk的特殊处理
  120. ret = game_utils.sdkLebianChange(game, sdk, config)
  121. if ret:
  122. return ret
  123. # 复制EntryActivity文件
  124. ret = copyEntryActivityCode(game, sdk, subChannel, config)
  125. if ret:
  126. return ret
  127. # 游戏脚本处理
  128. ret = doGamePostScript(game, sdk, config)
  129. if ret:
  130. return ret
  131. # 生成R文件
  132. '''ret = generateNewRFile(game, sdk, subChannel, config)
  133. if ret:
  134. return ret'''
  135. # 添加MultiDex支持
  136. if config['splitDex']:
  137. ret = splitDex(game, sdk, subChannel, config)
  138. if ret:
  139. return ret
  140. # 更改版本号
  141. ret = changeVersion(game, sdk, subChannel, config)
  142. if ret:
  143. return ret
  144. # 回编译
  145. ret = recomplie(game, sdk, subChannel, config)
  146. if ret:
  147. return ret
  148. # 对齐apk
  149. ret = alignApk(game, sdk, subChannel, config)
  150. if ret:
  151. return ret
  152. # 签名
  153. ret = apksignerApk(game, sdk, subChannel, config)
  154. if ret:
  155. return ret
  156. # 清理产生的中间文件
  157. if config['clearCache']:
  158. clearTemp(game, sdk, subChannel, config)
  159. return 0
  160. def decomplie(game, sdk, subChannel, config):
  161. '''
  162. 解包
  163. '''
  164. apktoolPath = file_utils.getApkToolPath()
  165. gamePath = file_utils.getFullGameApk(config,game)
  166. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  167. if os.path.exists(decompliePath):
  168. print('delete decomplie folder...')
  169. file_utils.deleteFolder(decompliePath)
  170. print('decomplie apk...')
  171. return file_utils.execJarCmd(apktoolPath, 'd -f "%s" -o "%s"' % (gamePath, decompliePath))
  172. def removeOldRes(game, sdk, subChannel, config):
  173. '''
  174. 删除旧资源
  175. '''
  176. print('delete res ...')
  177. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  178. for subPath in config['deleteList']:
  179. resPath = os.path.join(decompliePath, subPath)
  180. if os.path.exists(resPath):
  181. os.remove(resPath)
  182. print('delete ' + resPath)
  183. return 0
  184. def removeOldCode(game, sdk, subChannel, config):
  185. '''
  186. 删除旧代码
  187. '''
  188. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  189. codePath = os.path.join(decompliePath, 'smali', 'com', 'jmhy', 'lib', 'record')
  190. #file_utils.deleteFolder(codePath)
  191. allFiles = []
  192. allFiles = file_utils.list_files(codePath, allFiles)
  193. for f in allFiles:
  194. fpath, fname = os.path.split(f) #分离文件名和路径
  195. if fname == 'R.smali' or fname.startswith('R$'):
  196. continue
  197. os.remove(f)
  198. print('remove %s' % f)
  199. return 0
  200. def copyRes(game, sdk, subChannel, config):
  201. '''
  202. 复制res资源
  203. '''
  204. # 拷贝sdk资源
  205. print('copy res...')
  206. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  207. sdkPath = file_utils.getFullSDKPath(sdk)
  208. resPath = os.path.join(sdkPath, 'res')
  209. decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
  210. for d in os.listdir(resPath):
  211. copyResWithType(resPath, decomplieResPath, d)
  212. # 拷贝assets
  213. print('copy assets...')
  214. assetsPath = file_utils.getFullPath(sdkPath, 'assets')
  215. decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
  216. if os.path.exists(assetsPath):
  217. ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
  218. if ret:
  219. return ret
  220. # 拷贝jniLib
  221. print('copy jniLibs...')
  222. jniPath = file_utils.getFullPath(sdkPath, 'jniLibs')
  223. decomplieJniPath = file_utils.getFullPath(decompliePath, 'lib')
  224. abiFilters = []
  225. if os.path.exists(decomplieJniPath):
  226. for abi in os.listdir(decomplieJniPath):
  227. if abi == 'armeabi-v7a' or abi == 'armeabi':
  228. abiFilters.append(abi)
  229. else:
  230. abiFilters = ['armeabi-v7a']
  231. if os.path.exists(jniPath):
  232. ret = file_utils.copyFileAllDir(jniPath, decomplieJniPath, False, abiFilters)
  233. if ret:
  234. return ret
  235. return 0
  236. def mergeDrawableRes(game, sdk, subChannel, config):
  237. '''
  238. 合并Drawable-v4目录
  239. '''
  240. print('merge drawable path...')
  241. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  242. resPath = os.path.join(decompliePath, 'res')
  243. for path in os.listdir(resPath):
  244. print('res path %s' % path)
  245. if (path.startswith('drawable') or path.startswith('mipmap')) and path.endswith('-v4'):
  246. print('merge path %s' % path)
  247. v4DrawablePath = os.path.join(resPath, path)
  248. drawablePath = os.path.join(resPath, path[:-3])
  249. if os.path.exists(drawablePath):
  250. ret = file_utils.copyFileAllDir(v4DrawablePath, drawablePath, True)
  251. if ret:
  252. return ret
  253. else:
  254. os.rename(v4DrawablePath, drawablePath)
  255. return 0
  256. def removeSameRes(game, sdk, subChannel, config):
  257. '''
  258. 移除相同的资源
  259. '''
  260. # 读取sdk的资源
  261. print('remove same res...')
  262. sdkPath = file_utils.getFullSDKPath(sdk)
  263. sdkResPath = os.path.join(sdkPath, 'res')
  264. resList = []
  265. for path in os.listdir(sdkResPath):
  266. if not path.startswith('values'):
  267. continue
  268. absPath = os.path.join(sdkResPath, path)
  269. for resFile in os.listdir(absPath):
  270. '''if not resFile.startswith('jm_'):
  271. continue'''
  272. resList = xml_utils.readAllRes(os.path.join(absPath, resFile), resList)
  273. if len(resList) == 0:
  274. print('no same res found')
  275. return 0
  276. removeList = []
  277. # 移除相同的资源
  278. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  279. resPath = os.path.join(decompliePath, 'res')
  280. for path in os.listdir(resPath):
  281. if not path.startswith('values'):
  282. continue
  283. absPath = os.path.join(resPath, path)
  284. for resFile in os.listdir(absPath):
  285. print('resFile ==> ' + os.path.join(absPath, resFile))
  286. #xml_utils.removeSameRes(os.path.join(absPath, resFile), resList)
  287. removeList = xml_utils.removeSameRes2(os.path.join(absPath, resFile), resList, removeList)
  288. print('--------------')
  289. print(removeList)
  290. if len(removeList) == 0:
  291. print('no same res remove')
  292. return 0
  293. publicResPath = os.path.join(decompliePath, 'res/values/public.xml')
  294. print('publicResPath ---->' + publicResPath)
  295. xml_utils.removeIdFromPublic(publicResPath,removeList)
  296. return 0
  297. def mergeManifestRes(game, sdk, subChannel, config):
  298. '''
  299. 合并主文件
  300. '''
  301. print('merge AndroidManifest...')
  302. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  303. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  304. sdkPath = file_utils.getFullSDKPath(sdk)
  305. libManifest = file_utils.getFullPath(sdkPath, 'manifest.xml')
  306. return xml_utils.mergeManifestRes(manifest, libManifest)
  307. def copyAppRes(game, sdk, subChannel, config):
  308. '''
  309. 拷贝app的资源,比如app icon、启动图等
  310. '''
  311. channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
  312. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  313. # assets
  314. print('copy assets...')
  315. assetsPath = file_utils.getFullPath(channelPath, 'assets')
  316. decomplieAssetsPath = file_utils.getFullPath(decompliePath, 'assets')
  317. if os.path.exists(assetsPath):
  318. ret = file_utils.copyFileAllDir(assetsPath, decomplieAssetsPath)
  319. if ret:
  320. return ret
  321. # icon
  322. print('copy icon...')
  323. ret = copyAppResWithType(decompliePath, channelPath, 'icon')
  324. if ret:
  325. return ret
  326. # 启动图
  327. print('copy splash...')
  328. ret = copyAppResWithType(decompliePath, channelPath, 'splash')
  329. if ret:
  330. return ret
  331. # 其他图片
  332. print('copy image...')
  333. ret = copyAppResWithType(decompliePath, channelPath, 'image')
  334. if ret:
  335. return ret
  336. return 0
  337. def mergeLanguage(game, sdk, subChannel, config):
  338. '''
  339. 合并语言文件
  340. '''
  341. print('merge language...')
  342. channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
  343. mergePath = file_utils.getFullPath(channelPath, 'merge')
  344. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  345. if not os.path.exists(mergePath):
  346. print('%s not exists!' % mergePath)
  347. return 0
  348. if not os.path.isdir(mergePath):
  349. print('%s not a dir!' % mergePath)
  350. return 0
  351. for fileName in os.listdir(mergePath):
  352. mergeJson(mergePath, decompliePath, fileName)
  353. return 0
  354. def mergeJson(srcDir, changeDir, fileName):
  355. srcFile = os.path.join(srcDir, fileName)
  356. if os.path.isdir(srcFile):
  357. for fileName2 in os.listdir(srcFile):
  358. changeDir2 = os.path.join(changeDir, fileName)
  359. mergeJson(srcFile, changeDir2, fileName2)
  360. else:
  361. changeFile = os.path.join(changeDir, fileName)
  362. if not os.path.exists(changeFile):
  363. print('%s not exists!' % changeFile)
  364. return 0
  365. jsonText1 = file_utils.readFile(srcFile)
  366. jsonText2 = file_utils.readFile(changeFile)
  367. print('*************src config*************')
  368. print(jsonText1)
  369. print('************************************')
  370. print('*************target config*************')
  371. print(jsonText2)
  372. print('************************************')
  373. json1 = json.loads(jsonText1)
  374. json2 = json.loads(jsonText2)
  375. for item in json1:
  376. if item in json2:
  377. json2[item] = json1[item]
  378. jsonStr = json.dumps(json2, ensure_ascii=False)
  379. print('*************merge config*************')
  380. print(jsonStr)
  381. print('************************************')
  382. print('>> %s' % changeFile)
  383. file_utils.createFile(changeFile, jsonStr)
  384. return 0
  385. def copyAppResWithType(decompliePath, channelPath, typeName):
  386. decomplieResPath = os.path.join(decompliePath, 'res')
  387. iconPath = os.path.join(channelPath, typeName)
  388. if not os.path.exists(iconPath):
  389. print('dir "%s" not exists' % iconPath)
  390. return 0
  391. for d in os.listdir(iconPath):
  392. ret = copyResWithType(iconPath, decomplieResPath, d)
  393. if ret:
  394. return ret
  395. return 0
  396. def copyResWithType(resPath, decomplieResPath, typeName):
  397. # appt的打包目录会带-v4后缀
  398. resDir = os.path.join(resPath, typeName)
  399. target = os.path.join(decomplieResPath, typeName)
  400. targetV4 = os.path.join(decomplieResPath, typeName + '-v4')
  401. if not os.path.exists(target) and not os.path.exists(targetV4):
  402. os.makedirs(target)
  403. return file_utils.copyFileAllDir(resDir, target, False)
  404. elif not os.path.exists(target):
  405. return file_utils.copyFileAllDir(resDir, targetV4, False)
  406. else:
  407. return file_utils.copyFileAllDir(resDir, target, False)
  408. def removeNoSupportAttr(game, sdk, subChannel, config):
  409. '''
  410. 删除一些不支持的属性
  411. '''
  412. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  413. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  414. xml_utils.removeRootAttr(manifest, 'compileSdkVersion')
  415. xml_utils.removeRootAttr(manifest, 'compileSdkVersionCodename')
  416. return 0
  417. def fixUnSupportConfig(game, sdk, subChannel, config):
  418. '''
  419. 删除一些不支持的配置
  420. '''
  421. # 检查minSdkVersion
  422. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  423. yml = os.path.join(decompliePath, 'apktool.yml')
  424. minSdkVersion = 15
  425. file_utils.changeMinSdkVersion(yml, minSdkVersion)
  426. resPath = os.path.join(decompliePath, 'res')
  427. tag = '-v'
  428. for res in os.listdir(resPath):
  429. print('res = ' + res)
  430. if res.startswith('values') and tag in res:
  431. start = res.index(tag)
  432. version = res[start+len(tag):]
  433. if not version.isdigit():
  434. continue
  435. version = int(version)
  436. print('version = %d' % version)
  437. if version < minSdkVersion:
  438. unSopportPath = os.path.join(resPath, res)
  439. print('unSopportPath = ' + unSopportPath)
  440. file_utils.deleteFolder(unSopportPath)
  441. print('deleteFolder = ' + unSopportPath)
  442. return 0
  443. def changePackageName(game, sdk, subChannel, config):
  444. '''
  445. 更改包名
  446. '''
  447. # 全局替换AndroidManifest里面的包名
  448. newPackageName = config['packageName']
  449. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  450. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  451. packageName = xml_utils.getPackageName(manifest)
  452. xml_utils.changePackageName(manifest, newPackageName)
  453. print('change package name %s --> %s' % (packageName, newPackageName))
  454. return 0
  455. def getPackageName(game, sdk, subChannel, config):
  456. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  457. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  458. packageName = xml_utils.getPackageName(manifest)
  459. return packageName
  460. def changeAppName(game, sdk, subChannel, config):
  461. '''
  462. 更改app名
  463. '''
  464. # 生成string.xml文件
  465. name = config['name']
  466. resName = 'shanshen_sdk_name'
  467. if 'outName' in config:
  468. resName = resName + '_' + config['outName']
  469. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  470. stringFile = os.path.join(decompliePath, 'res', 'values', 'sdk_strings_temp.xml')
  471. content = '<?xml version="1.0" encoding="utf-8"?><resources><string name="%s">%s</string></resources>' % (resName, name)
  472. file_utils.createFile(stringFile, content)
  473. # 修改主文件的app名的值
  474. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  475. xml_utils.changeAppName(manifest, '@string/%s' % resName)
  476. print('change app name %s' % name)
  477. return 0
  478. def changeAppIcon(game, sdk, subChannel, config):
  479. '''
  480. 更改app icon
  481. '''
  482. print('change app icon...')
  483. resName = 'record_sdk_icon'
  484. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  485. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  486. xml_utils.changeAppIcon(manifest, '@mipmap/%s' % resName)
  487. return 0
  488. def addMetaData(game, sdk, subChannel, config):
  489. '''
  490. 添加meta-data
  491. '''
  492. if 'metaData' not in config:
  493. return 0
  494. print('add meta-data...')
  495. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  496. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  497. xml_utils.addMetaData(manifest, config['metaData'])
  498. return 0
  499. def addConfig(game, sdk, subChannel, config):
  500. '''
  501. 添加config.json
  502. '''
  503. if 'configData' not in config:
  504. print('configData is null')
  505. return 0
  506. print('add config.json...')
  507. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  508. configJson = os.path.join(decompliePath, 'assets', 'tool_config.json')
  509. jsonText = json.dumps(config['configData'], ensure_ascii=False)
  510. file_utils.createFile(configJson, jsonText)
  511. return 0
  512. def changePlaceholders(game, sdk, subChannel, config):
  513. '''
  514. 处理掉占位符
  515. '''
  516. if 'placeholders' not in config:
  517. return 0
  518. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  519. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  520. placeholders = config['placeholders']
  521. for placeholder in placeholders:
  522. oldText = '${%s}' % placeholder
  523. newText = placeholders[placeholder]
  524. print('change placeholder %s -> %s' % (oldText, newText))
  525. file_utils.replaceContent(manifest, oldText, newText)
  526. return 0
  527. def addLauncher(game, sdk, subChannel, config):
  528. '''
  529. 添加启动图
  530. '''
  531. channelPath = file_utils.getSubChannelPath(game, sdk, subChannel)
  532. splashPath = os.path.join(channelPath, 'splash')
  533. if len(os.listdir(splashPath)) == 0:
  534. print('dir splash is empty')
  535. return 0
  536. print('add launcher...')
  537. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  538. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  539. activity = xml_utils.getLauncherActivityName(manifest)
  540. if activity == 'com.shanshen.sdk.template.LauncherActivity':
  541. print('add launcher already exist...')
  542. return 1
  543. # 添加关联资源
  544. internalPath = os.path.join(file_utils.getCurrentPath(), 'internal_shanshen')
  545. ret = copyAppResWithType(decompliePath, internalPath, 'launcher_res')
  546. if ret:
  547. return ret
  548. # 拷贝代码
  549. print('copy launcher code...')
  550. codePath = os.path.join(internalPath, 'launcher_code', 'smali')
  551. smaliPath = file_utils.getFullPath(decompliePath, 'smali')
  552. ret = file_utils.copyFileAllDir(codePath, smaliPath)
  553. if ret:
  554. return ret
  555. # 修改主文件信息
  556. print('change launcher config...')
  557. orientation = xml_utils.getScreenOrientation(manifest)
  558. activity = xml_utils.removeLauncherActivity(manifest)
  559. xml_utils.addLauncherActivity(manifest, orientation, 'com.shanshen.sdk.template.LauncherActivity')
  560. # 修改跳转的
  561. launcherActivity = os.path.join(decompliePath, 'smali', 'com', 'shanshen', 'sdk', 'template', 'LauncherActivity.smali')
  562. file_utils.replaceContent(launcherActivity, '{class}', activity)
  563. print('change launcher %s to %s' % (activity, 'com.shanshen.sdk.template.LauncherActivity'))
  564. # config['oldLauncher'] = activity
  565. if 'launcherTime' in config:
  566. timeHex = formatHex(config['launcherTime'])
  567. file_utils.replaceContent(launcherActivity, '0x0BB8', timeHex)
  568. return 0
  569. def addMoreIcon(game, sdk, subChannel, config):
  570. '''
  571. 添加多个图标
  572. '''
  573. print('add more icon support...')
  574. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  575. icon = '@mipmap/common_sdk_icon'
  576. if not config['changeIcon']:
  577. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  578. icon = xml_utils.getApplicationAttr(manifest, 'icon')
  579. switchIcon = icon
  580. if config['switchIcon']:
  581. switchIcon = '@mipmap/common_sdk_icon2'
  582. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  583. return xml_utils.addMoreIcon(manifest, icon, switchIcon)
  584. def formatHex(millisecond):
  585. '''
  586. 将毫秒转为16进制,4位格式
  587. '''
  588. timeHex = str(hex(millisecond)).upper()
  589. timeHex = timeHex[2:]
  590. formatHex = ''
  591. if len(timeHex) == 3:
  592. formatHex = '0x0' + timeHex
  593. elif len(timeHex) == 4:
  594. formatHex = '0x' + timeHex
  595. else:
  596. formatHex = '0x0BB8'
  597. return formatHex
  598. def doSDKPostScript(game, sdk, config):
  599. '''
  600. 执行sdk相关特殊处理脚本
  601. '''
  602. sdkPath = file_utils.getFullSDKPath(sdk)
  603. scriptPath = os.path.join(sdkPath, 'script')
  604. targetScript = os.path.join(scriptPath, 'sdk_script.py')
  605. if not os.path.exists(targetScript):
  606. print('sdk_script no exists')
  607. return 0
  608. print('doSDKPostScript...')
  609. sys.path.append(scriptPath)
  610. module = importlib.import_module('sdk_script')
  611. ret = module.execute(game, sdk, config)
  612. sys.path.remove(scriptPath)
  613. return ret
  614. def doGamePostScript(game, sdk, config):
  615. '''
  616. 执行游戏相关特殊处理脚本
  617. '''
  618. channelPath = file_utils.getFullGamePath(game)
  619. scriptPath = os.path.join(channelPath, 'script')
  620. targetScript = os.path.join(scriptPath, 'game_script.py')
  621. if not os.path.exists(targetScript):
  622. print('game_script no exists')
  623. return 0
  624. print('doGamePostScript...')
  625. sys.path.append(scriptPath)
  626. module = importlib.import_module('game_script')
  627. ret = module.execute(game, sdk, config)
  628. sys.path.remove(scriptPath)
  629. return ret
  630. def generateNewRFile(game, sdk, subChannel, config):
  631. '''
  632. 生成新的R文件
  633. '''
  634. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  635. androidPlatforms = file_utils.getAndroidCompileToolPath()
  636. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  637. decomplieResPath = file_utils.getFullPath(decompliePath, 'res')
  638. compliePath = file_utils.getFullPath(decompliePath, 'gen')
  639. if not os.path.exists(compliePath):
  640. os.makedirs(compliePath)
  641. # 生成R文件
  642. print('create R.java ...')
  643. if config['aapt2disable']:
  644. aapt = file_utils.getAAPTPath()
  645. ret = file_utils.getExecPermission(aapt)
  646. if ret:
  647. return ret
  648. createRCmd = '"%s" p -f -m -J "%s" -S "%s" -I "%s" -M "%s"' % (aapt, compliePath, decomplieResPath, androidPlatforms, manifest)
  649. ret = file_utils.execFormatCmd(createRCmd)
  650. if ret:
  651. return ret
  652. else:
  653. # compile
  654. aapt = file_utils.getAAPT2Path()
  655. ret = file_utils.getExecPermission(aapt)
  656. if ret:
  657. return ret
  658. print('compiled res ...')
  659. complieResPath = os.path.join(compliePath, 'compiled')
  660. complieResCmd = '"%s" compile --dir "%s" -o "%s"' % (aapt, decomplieResPath, complieResPath)
  661. file_utils.execFormatCmd(complieResCmd)
  662. # unzip
  663. print('unzip compiled res ...')
  664. unzipResPath = os.path.join(compliePath, 'aapt2_res')
  665. with zipfile.ZipFile(complieResPath) as zf:
  666. zf.extractall(unzipResPath)
  667. print('create unzip %s' % unzipResPath)
  668. # link
  669. print('link res ...')
  670. outApk = os.path.join(compliePath, 'res.apk')
  671. linkResCmd = '"%s" link -o "%s" -I "%s" --manifest "%s" --java "%s" --auto-add-overlay' % (aapt, outApk, androidPlatforms, manifest, compliePath)
  672. for filename in os.listdir(unzipResPath):
  673. linkResCmd += ' %s' % filename
  674. print('link cmd len is %s' % len(linkResCmd))
  675. ret = file_utils.execFormatCmd(linkResCmd, unzipResPath)
  676. if ret:
  677. return ret
  678. # 编译R文件
  679. print('complie R.java ...')
  680. packageName = xml_utils.getPackageName(manifest)
  681. packagePath = file_utils.getPackagePath(compliePath, packageName)
  682. RSourceFile = os.path.join(packagePath, 'R.java')
  683. complieRCmd = 'javac -source 1.8 -target 1.8 -encoding UTF-8 "%s"' % RSourceFile
  684. ret = file_utils.execFormatCmd(complieRCmd)
  685. if ret:
  686. return ret
  687. # 生成dex
  688. print('dex R.class ...')
  689. dx = file_utils.getDxPath()
  690. outDex = os.path.join(compliePath, 'classes.dex')
  691. ret = file_utils.execJarCmd(dx, '--dex --output="%s" "%s"' % (outDex, compliePath))
  692. if ret:
  693. return ret
  694. # 反向dex生成smali
  695. # 存放在out目录
  696. print('baksmali classes.dex ...')
  697. baksmaliPath = file_utils.getBaksmaliPath()
  698. outPath = file_utils.getFullPath(decompliePath, 'out')
  699. ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
  700. if ret:
  701. return ret
  702. # 将生成的文件拷贝到目标目录
  703. print('copy R.smali ...')
  704. smaliPath = file_utils.getFullPath(decompliePath, 'smali')
  705. file_utils.copyFileAllDir(outPath, smaliPath)
  706. return 0
  707. def packJar(game, sdk, subChannel, config):
  708. '''
  709. 打包所有的jar
  710. '''
  711. splitDex = config['splitDex']
  712. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  713. outPath = file_utils.getFullPath(decompliePath, 'gen')
  714. if not os.path.exists(outPath):
  715. os.makedirs(outPath)
  716. if config['aapt2disable']:
  717. dx = file_utils.getDxPath()
  718. dexCmd = '--dex --multi-dex --no-warning --output="%s"' % outPath
  719. else:
  720. dx = file_utils.getD8Path()
  721. androidPlatforms = file_utils.getAndroidCompileToolPath()
  722. dexCmd = '--lib "%s" --output "%s"' % (androidPlatforms, outPath)
  723. # 找到所有lib依赖
  724. sdkPath = file_utils.getFullSDKPath(sdk)
  725. libs = os.path.join(sdkPath, 'libs')
  726. libConfig = os.path.join(libs, 'config.json')
  727. # 存在配置文件
  728. if os.path.exists(libConfig):
  729. jsonText = file_utils.readFile(libConfig)
  730. libConf = json.loads(jsonText)
  731. if 'libConfig' in config and config['libConfig'] in libConf:
  732. conf = config['libConfig']
  733. libList = libConf[conf]
  734. for jar in libList:
  735. dexCmd += ' ' + os.path.join(libs, jar)
  736. elif 'default' in libConf:
  737. libList = libConf['default']
  738. for jar in libList:
  739. dexCmd += ' ' + os.path.join(libs, jar)
  740. else:
  741. for jar in os.listdir(libs):
  742. if not jar.endswith('.jar'):
  743. continue
  744. dexCmd += ' ' + os.path.join(libs, jar)
  745. else:
  746. for jar in os.listdir(libs):
  747. if not jar.endswith('.jar'):
  748. continue
  749. dexCmd += ' ' + os.path.join(libs, jar)
  750. # multidex.jar
  751. if splitDex:
  752. dexCmd += ' ' + file_utils.getMultiDexPath()
  753. # sdk实现类
  754. print('packageing all jar ...')
  755. ret = file_utils.execJarCmd(dx, dexCmd)
  756. if ret:
  757. return ret
  758. # 反向dex生成smali
  759. # 存放在out目录
  760. print('baksmali classes.dex ...')
  761. outDex = os.path.join(outPath, 'classes.dex')
  762. baksmaliPath = file_utils.getBaksmaliPath()
  763. outPath = file_utils.getFullPath(decompliePath, 'out')
  764. ret = file_utils.execJarCmd(baksmaliPath, 'd "%s" -o "%s"' % (outDex, outPath))
  765. if ret:
  766. return ret
  767. # 将生成的文件拷贝到目标目录
  768. print('copy all smali ...')
  769. smaliPath = file_utils.getFullPath(decompliePath, 'smali')
  770. ret = file_utils.copyFileAllDir(outPath, smaliPath, True)
  771. if ret:
  772. return ret
  773. return 0
  774. def splitDex(game, sdk, subChannel, config):
  775. '''
  776. 分割dex
  777. '''
  778. # 判断是否已经存在application
  779. # 存在,则往原application添加内容
  780. # 不存在,则拷贝一个默认的android.support.multidex.MultiDexApplication
  781. print('add MultiDex support...')
  782. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  783. manifest = os.path.join(decompliePath, 'AndroidManifest.xml')
  784. application = xml_utils.getApplicationAttr(manifest, 'name')
  785. if application is None:
  786. ret = xml_utils.changeApplicationAttr(manifest, 'name', 'android.support.multidex.MultiDexApplication')
  787. if ret:
  788. return ret
  789. else:
  790. smaliPath = os.path.join(decompliePath, 'smali')
  791. applicationFile = file_utils.getPackagePath(smaliPath, application)
  792. applicationFile += '.smali'
  793. ret = changeApplicationDex(applicationFile)
  794. if ret:
  795. return ret
  796. return splitSmali(game, sdk, subChannel, config, application)
  797. def changeApplicationDex(file):
  798. '''
  799. 修改application的smali文件,增加MultiDex操作
  800. '''
  801. index = file_utils.getApplicationSmaliIndex(file)
  802. file_utils.insertApplicationSmali(file, index)
  803. return 0
  804. def splitSmali(game, sdk, subChannel, config, application):
  805. '''
  806. 如果函数上限超过限制,自动拆分smali,以便生成多个dex文件
  807. '''
  808. print('splitSmali...')
  809. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  810. smaliPath = os.path.join(decompliePath, 'smali')
  811. appPackage = None
  812. if application:
  813. appPackage = application[:application.rfind('.')]
  814. appPackage = appPackage.replace('.', '/')
  815. allFiles = []
  816. allFiles = file_utils.list_files(smaliPath, allFiles)
  817. #print('file count is %d' % len(allFiles))
  818. #maxFuncNum = 65535
  819. # 留一点空间,防止计算误差
  820. maxFuncNum = 64000
  821. currFucNum = 0
  822. totalFucNum = 0
  823. currDexIndex = 1
  824. allRefs = []
  825. #保证Application等类在第一个classex.dex文件中
  826. for f in allFiles:
  827. f = f.replace('\\', '/')
  828. if (appPackage and appPackage in f) or '/android/support/multidex' in f:
  829. currFucNum += smali_utils.get_smali_method_count(f, allRefs)
  830. totalFucNum = currFucNum
  831. for f in allFiles:
  832. f = f.replace('\\', '/')
  833. if not f.endswith('.smali'):
  834. continue
  835. if (appPackage and appPackage in f) or '/android/support/multidex' in f:
  836. continue
  837. thisFucNum = smali_utils.get_smali_method_count(f, allRefs)
  838. totalFucNum += thisFucNum
  839. #print('%d # %d ==> %s' % (thisFucNum, currDexIndex, f))
  840. #print('totalFucNum is %d' % totalFucNum)
  841. if currFucNum + thisFucNum >= maxFuncNum:
  842. currFucNum = thisFucNum
  843. currDexIndex += 1
  844. newDexPath = os.path.join(decompliePath, 'smali_classes%d' % currDexIndex)
  845. os.makedirs(newDexPath)
  846. else:
  847. currFucNum += thisFucNum
  848. if currDexIndex > 1:
  849. newDexPath = os.path.join(decompliePath, 'smali_classes%d' % currDexIndex)
  850. targetFile = newDexPath + f[len(smaliPath):]
  851. file_utils.copyFile(f, targetFile, True)
  852. return 0
  853. def changeVersion(game, sdk, subChannel, config):
  854. '''
  855. 更改版本号
  856. '''
  857. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  858. yml = os.path.join(decompliePath, 'apktool.yml')
  859. versionCode = None
  860. versionName = None
  861. targetSdkVersion = None
  862. if 'versionCode' in config:
  863. versionCode = config['versionCode']
  864. if 'versionName' in config:
  865. versionName = config['versionName']
  866. if 'targetSdkVersion' in config:
  867. targetSdkVersion = config['targetSdkVersion']
  868. return file_utils.changeVersion(yml, versionCode, versionName, targetSdkVersion)
  869. def recomplie(game, sdk, subChannel, config):
  870. '''
  871. 回编译
  872. '''
  873. print('recomplie apk...')
  874. apktoolPath = file_utils.getApkToolPath()
  875. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  876. outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
  877. useAppt2 = ' --use-aapt2'
  878. if config['aapt2disable']:
  879. useAppt2 = ''
  880. return file_utils.execJarCmd(apktoolPath, 'b -f "%s" -o "%s"%s' % (decompliePath, outApk, useAppt2))
  881. def alignApk(game, sdk, subChannel, config):
  882. '''
  883. 对齐apk
  884. '''
  885. print('align apk...')
  886. outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
  887. alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
  888. alignapkTool = file_utils.getAlignPath()
  889. if os.path.exists(alignApk):
  890. os.remove(alignApk)
  891. ret = file_utils.getExecPermission(alignapkTool)
  892. if ret:
  893. return ret
  894. # zipalign.exe -v -p 4 input.apk output.apk
  895. return file_utils.execFormatCmd('"%s" -f -p 4 "%s" "%s"' % (alignapkTool, outApk, alignApk))
  896. def apksignerApk(game, sdk, subChannel, config):
  897. '''
  898. 签名apk
  899. '''
  900. print('sign apk...')
  901. path = os.path.join(file_utils.getCurrentPath(), 'keystore', 'key.json')
  902. jsonText = file_utils.readFile(path)
  903. signConfig = json.loads(jsonText)
  904. keystore = {}
  905. if game in signConfig:
  906. if sdk in signConfig[game] and subChannel in signConfig[game][sdk]:
  907. keystore = signConfig[game][sdk][subChannel]
  908. else:
  909. keystore = signConfig['default']
  910. else:
  911. keystore = signConfig['default']
  912. print('storeFile is "%s"' % keystore['storeFile'])
  913. apksigner = file_utils.getApksignerPath()
  914. alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
  915. signedApk = file_utils.getSignApkPath(game, sdk, subChannel, config['cache'])
  916. storeFile = os.path.join(file_utils.getCurrentPath(), 'keystore', keystore['storeFile'])
  917. if 'outName' in config and 'outPath' in config:
  918. if not os.path.exists(config['outPath']):
  919. os.makedirs(config['outPath'])
  920. signedApk = os.path.join(config['outPath'], config['outName'] + '.apk')
  921. print('signedApk = ' + signedApk)
  922. elif 'outName' in config:
  923. signedApk = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
  924. print('signedApk = ' + signedApk)
  925. # java -jar apksigner.jar sign --ks key.jks --ks-key-alias releasekey --ks-pass pass:pp123456 --key-pass pass:pp123456 --out output.apk input.apk
  926. v2disable = ''
  927. if 'v2disable' in config and config['v2disable']:
  928. v2disable = ' --v2-signing-enabled=false'
  929. return file_utils.execJarCmd(apksigner, 'sign%s --ks "%s" --ks-key-alias %s --ks-pass pass:%s --key-pass pass:%s --out "%s" "%s"' % (v2disable, storeFile, keystore['keyAlias'], keystore['storePassword'], keystore['keyPassword'], signedApk, alignApk))
  930. def addChannel(game, sdk, subChannel, config):
  931. '''
  932. 添加渠道信息
  933. '''
  934. if 'v2disable' in config and config['v2disable']:
  935. return 0
  936. walle = file_utils.getWallePath()
  937. signedApk = file_utils.getSignApkPath(game, sdk, subChannel, config['cache'])
  938. if 'outName' in config and 'outPath' in config:
  939. signedApk = os.path.join(config['outPath'], config['outName'] + '.apk')
  940. elif 'outName' in config:
  941. signedApk = file_utils.getRenameApkPath(game, sdk, config['cache'], config['outName'])
  942. properties = config['properties']
  943. appid = ''
  944. appkey = ''
  945. if 'appid' in properties:
  946. appid = properties['appid']
  947. if 'appkey' in properties:
  948. appkey = properties['appkey']
  949. return file_utils.execJarCmd(walle, 'put -e version=%s,agent=%s,appid=%s,appkey=%s "%s" "%s"' % (config_utils_record.getDate(), properties['agent'], appid, appkey, signedApk, signedApk))
  950. def clearTemp(game, sdk, subChannel, config):
  951. '''
  952. 清空中间产生的文件
  953. '''
  954. print('clear temp...')
  955. alignApk = file_utils.getAlignApkPath(game, sdk, subChannel, config['cache'])
  956. outApk = file_utils.getOutApkPath(game, sdk, subChannel, config['cache'])
  957. if os.path.exists(alignApk):
  958. os.remove(alignApk)
  959. if os.path.exists(outApk):
  960. os.remove(outApk)
  961. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  962. file_utils.deleteFolder(decompliePath)
  963. print('clear temp end')
  964. def packConsoleInput():
  965. '''
  966. 控制台打包
  967. '''
  968. if len(sys.argv) < 3:
  969. print('argument is missing')
  970. return 1
  971. # 校验参数
  972. game = sys.argv[1]
  973. sdk = sys.argv[2]
  974. # 可选参数,没有则默认打全部渠道
  975. subChannel = None
  976. if len(sys.argv) > 3:
  977. subChannel = sys.argv[3]
  978. return packConsole(game, sdk, subChannel)
  979. def packConsole(game, sdk, subChannel):
  980. '''
  981. 控制台打包
  982. '''
  983. if not os.path.exists(file_utils.getFullGameApk(game)):
  984. print('game "%s" not exists' % game)
  985. return 1
  986. if not os.path.exists(file_utils.getFullSDKPath(sdk)):
  987. print('sdk "%s" not exists' % sdk)
  988. return 1
  989. # 读取配置
  990. channelPath = file_utils.getChannelPath(game, sdk)
  991. configPath = os.path.join(channelPath, 'config.json')
  992. if not os.path.exists(configPath):
  993. print('%s not exists' % configPath)
  994. return 1
  995. jsonText = file_utils.readFile(configPath)
  996. config = json.loads(jsonText)
  997. # 检查参数
  998. if not config_utils_record.checkConfig(config):
  999. return 1
  1000. # 处理参数
  1001. config_utils_record.replaceArgs(config)
  1002. successCount = 0
  1003. failureCount = 0
  1004. if type(config) == dict:
  1005. if subChannel is None or config['subChannel'] == subChannel:
  1006. ret = pack(game, sdk, config)
  1007. if ret:
  1008. failureCount += 1
  1009. else:
  1010. successCount += 1
  1011. else:
  1012. print('subChannel "%s" no found' % subChannel)
  1013. return 1
  1014. elif type(config) == list:
  1015. found = False
  1016. for itemConfig in config:
  1017. if subChannel is None or itemConfig['subChannel'] == subChannel:
  1018. found = True
  1019. ret = pack(game, sdk, itemConfig)
  1020. if ret:
  1021. failureCount += 1
  1022. else:
  1023. successCount += 1
  1024. if not found:
  1025. print('subChannel "%s" no found' % subChannel)
  1026. return 1
  1027. print('success %d, failure %d' % (successCount, failureCount))
  1028. return 0
  1029. def copyEntryActivityCode(game, sdk, subChannel, config):
  1030. '''
  1031. 拷贝代码
  1032. '''
  1033. print('copy EntryActivity.smali')
  1034. sdkPath = file_utils.getFullSDKPath(sdk)
  1035. EntryActivity = 'EntryActivity.smali'
  1036. entryFile = os.path.join(sdkPath, 'smali', EntryActivity)
  1037. decompliePath = file_utils.getDecompliePath(game, sdk, subChannel, config['cache'])
  1038. smaliPath = os.path.join(decompliePath, 'smali')
  1039. targetPath = file_utils.getPackagePath(smaliPath, config['packageName'])
  1040. targetFile = os.path.join(targetPath, EntryActivity)
  1041. ret = file_utils.copyFile(entryFile, targetFile)
  1042. if ret:
  1043. return ret
  1044. writeActivityToManifest(os.path.join(decompliePath, 'AndroidManifest.xml'),config)
  1045. oldText = 'com/jmhy/floatsdk/sample/EntryActivity'
  1046. newText = config['packageName'].replace('.', '/') + "/EntryActivity"
  1047. print("EntryActivity.smali change '{}' to '{}' ...".format(oldText,newText))
  1048. file_utils.replaceContent(targetFile, oldText, newText)
  1049. return 0
  1050. def writeActivityToManifest(targetManifest, config):
  1051. androidNS = 'http://schemas.android.com/apk/res/android'
  1052. ET.register_namespace('android', androidNS)
  1053. targetTree = ET.parse(targetManifest)
  1054. targetRoot = targetTree.getroot()
  1055. appNode = targetRoot.find('application')
  1056. activitys = appNode.findall('activity')
  1057. keyName = "{0}{1}{2}name".format("{",androidNS,"}")
  1058. theme = "{0}{1}{2}theme".format("{",androidNS,"}")
  1059. for activity in activitys:
  1060. activityName = activity.get(keyName)
  1061. if activityName.find('.EntryActivity')>=0:
  1062. oldName = activityName;
  1063. newName = config['packageName'] + ".EntryActivity"
  1064. activity.set(keyName,newName)
  1065. print("EntryActivity change '{}' to '{}' ...".format(oldName, newName))
  1066. if activityName.find('com.tool.floatsdk.ui.WebActivity')>=0:
  1067. if activity.get(theme) is not None or activity.get(theme) != "":
  1068. del activity.attrib[theme]
  1069. perNode = targetRoot.find('permissions')
  1070. #permissions = perNode.findall('uses-permission')
  1071. print(perNode)
  1072. print("------------")
  1073. targetTree.write(targetManifest, 'UTF-8')