package_utils_record.py 41 KB

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