xml_utils.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. import xml.etree.ElementTree as ET
  2. import os.path
  3. namespaces = {'android' : 'http://schemas.android.com/apk/res/android'}
  4. encoding = 'UTF-8'
  5. def getPackageName(manifest):
  6. '''
  7. 获取包名
  8. '''
  9. tree = ET.parse(manifest)
  10. root = tree.getroot()
  11. return root.attrib['package']
  12. def changePackageName(manifest, packageName):
  13. '''
  14. 更改包名
  15. '''
  16. for key in namespaces:
  17. ET.register_namespace(key, namespaces[key])
  18. tree = ET.parse(manifest)
  19. root = tree.getroot()
  20. root.attrib['package'] = packageName
  21. tree.write(manifest, encoding)
  22. def removeLauncherActivity(manifest):
  23. '''
  24. 删除启动的activity
  25. '''
  26. for key in namespaces:
  27. ET.register_namespace(key, namespaces[key])
  28. tree = ET.parse(manifest)
  29. root = tree.getroot()
  30. attrName = getNamespacesFormat('android:name', namespaces)
  31. for node in root.findall('application/activity'):
  32. if len(node.getchildren()) <= 0:
  33. continue
  34. for sub in node.getchildren():
  35. if sub.tag != 'intent-filter':
  36. continue
  37. for sub2 in sub.getchildren():
  38. if not (sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER'):
  39. continue
  40. node.remove(sub)
  41. tree.write(manifest, encoding)
  42. return node.attrib[attrName]
  43. return 0
  44. def removeLauncherActivityByName(manifest,name):
  45. '''
  46. 删除启动的activity
  47. '''
  48. for key in namespaces:
  49. ET.register_namespace(key, namespaces[key])
  50. tree = ET.parse(manifest)
  51. root = tree.getroot()
  52. attrName = getNamespacesFormat('android:name', namespaces)
  53. for node in root.findall('application/activity'):
  54. print('node ----> ' + node.attrib[attrName])
  55. if node.attrib[attrName] != name:
  56. continue
  57. for sub in node.getchildren():
  58. if sub.tag != 'intent-filter':
  59. continue
  60. for sub2 in sub.getchildren():
  61. if not (sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER'):
  62. continue
  63. node.remove(sub)
  64. tree.write(manifest, encoding)
  65. return node.attrib[attrName]
  66. return 0
  67. def getScreenOrientation(manifest):
  68. '''
  69. 获取启动activity的方向
  70. '''
  71. for key in namespaces:
  72. ET.register_namespace(key, namespaces[key])
  73. tree = ET.parse(manifest)
  74. root = tree.getroot()
  75. attrName = getNamespacesFormat('android:name', namespaces)
  76. attrOrientation = getNamespacesFormat('android:screenOrientation', namespaces)
  77. for node in root.findall('application/activity'):
  78. if len(node.getchildren()) <= 0:
  79. continue
  80. for sub in node.getchildren():
  81. if sub.tag != 'intent-filter':
  82. continue
  83. for sub2 in sub.getchildren():
  84. if not (sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER'):
  85. continue
  86. return node.attrib[attrOrientation]
  87. return 0
  88. def addLauncherActivity(manifest, screenOrientation, activity):
  89. '''
  90. 添加启动的activity
  91. '''
  92. for key in namespaces:
  93. ET.register_namespace(key, namespaces[key])
  94. tree = ET.parse(manifest)
  95. root = tree.getroot()
  96. # activity
  97. '''<activity android:name=".LauncherActivity"
  98. android:theme="@style/LauncherStyle">
  99. <intent-filter>
  100. <action android:name="android.intent.action.MAIN" />
  101. <category android:name="android.intent.category.LAUNCHER" />
  102. </intent-filter>
  103. </activity>'''
  104. activity = ET.Element('activity', {'android:name' : activity,
  105. 'android:theme' : '@android:style/Theme.Holo.Light.NoActionBar.Fullscreen',
  106. 'android:launchMode' : 'singleTop',
  107. 'android:configChanges' : 'orientation|screenSize|keyboardHidden',
  108. 'android:screenOrientation' : screenOrientation})
  109. intent = ET.Element('intent-filter')
  110. action = ET.Element('action', {'android:name' : 'android.intent.action.MAIN'})
  111. category = ET.Element('category', {'android:name' : 'android.intent.category.LAUNCHER'})
  112. intent.append(action)
  113. intent.append(category)
  114. activity.append(intent)
  115. application = root.find('application')
  116. application.insert(0, activity)
  117. tree.write(manifest, encoding)
  118. def changeAppName(manifest, stringRes):
  119. '''
  120. 更改app名
  121. '''
  122. # 移除主activity的label
  123. removeLauncherAttr(manifest, 'label')
  124. return changeApplicationAttr(manifest, 'label', stringRes)
  125. def getLauncherActivity(root):
  126. '''
  127. 获取启动的activity
  128. '''
  129. attrName = getNamespacesFormat('android:name', namespaces)
  130. for node in root.findall('application/activity'):
  131. if len(node.getchildren()) <= 0:
  132. continue
  133. for sub in node.getchildren():
  134. if sub.tag != 'intent-filter':
  135. continue
  136. for sub2 in sub.getchildren():
  137. if sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER':
  138. return node
  139. return None
  140. def getLauncherActivitys(manifest):
  141. '''
  142. 获取启动的activity
  143. '''
  144. attrName = getNamespacesFormat('android:name', namespaces)
  145. nodeList = []
  146. tree = ET.parse(manifest)
  147. root = tree.getroot()
  148. for node in root.findall('application/activity'):
  149. if len(node.getchildren()) <= 0:
  150. continue
  151. for sub in node.getchildren():
  152. if sub.tag != 'intent-filter':
  153. continue
  154. for sub2 in sub.getchildren():
  155. if sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER':
  156. nodeList.append(node)
  157. return nodeList
  158. def getLauncherActivityName(manifest):
  159. '''
  160. 获取启动的activity
  161. '''
  162. for key in namespaces:
  163. ET.register_namespace(key, namespaces[key])
  164. tree = ET.parse(manifest)
  165. root = tree.getroot()
  166. launcherActivity = getLauncherActivity(root)
  167. attrName = getNamespacesFormat('android:name', namespaces)
  168. activityName = launcherActivity.attrib[attrName]
  169. return activityName
  170. def addMoreIcon(manifest, icon, switchIcon):
  171. '''
  172. 添加多图标
  173. '''
  174. for key in namespaces:
  175. ET.register_namespace(key, namespaces[key])
  176. tree = ET.parse(manifest)
  177. root = tree.getroot()
  178. launcherActivity = getLauncherActivity(root)
  179. if launcherActivity is None:
  180. return 1
  181. attrName = getNamespacesFormat('android:name', namespaces)
  182. activityName = launcherActivity.attrib[attrName]
  183. activityAlias = ET.Element('activity-alias', {'android:name' : 'com.jmhy.sdk.icon.normal',
  184. 'android:enabled' : 'false',
  185. 'android:icon' : icon,
  186. 'android:targetActivity' : activityName})
  187. activityAlias2 = ET.Element('activity-alias', {'android:name' : 'com.jmhy.sdk.icon.switch',
  188. 'android:enabled' : 'false',
  189. 'android:icon' : switchIcon,
  190. 'android:targetActivity' : activityName})
  191. for item in launcherActivity.getchildren():
  192. activityAlias.append(item)
  193. activityAlias2.append(item)
  194. application = root.find('application')
  195. application.append(activityAlias)
  196. application.append(activityAlias2)
  197. tree.write(manifest, encoding)
  198. return 0
  199. def removeLauncherAttr(manifest, attrType):
  200. '''
  201. 移除启动的activity的label
  202. '''
  203. for key in namespaces:
  204. ET.register_namespace(key, namespaces[key])
  205. tree = ET.parse(manifest)
  206. root = tree.getroot()
  207. launcherActivity = getLauncherActivity(root)
  208. if launcherActivity is None:
  209. return 1
  210. attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
  211. if attrName in launcherActivity.attrib:
  212. del launcherActivity.attrib[attrName]
  213. tree.write(manifest, encoding)
  214. return 0
  215. def changeLauncherAttr(manifest, attrType, attrValue):
  216. '''
  217. 更改启动的activity的属性
  218. '''
  219. for key in namespaces:
  220. ET.register_namespace(key, namespaces[key])
  221. tree = ET.parse(manifest)
  222. root = tree.getroot()
  223. launcherActivity = getLauncherActivity(root)
  224. if launcherActivity is None:
  225. return 1
  226. attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
  227. if attrName in launcherActivity.attrib:
  228. launcherActivity.attrib[attrName] = attrValue
  229. tree.write(manifest, encoding)
  230. return 0
  231. def changeAppIcon(manifest, iconRes):
  232. '''
  233. 更改app icon
  234. '''
  235. # 移除主activity的图标
  236. removeLauncherAttr(manifest, 'icon')
  237. return changeApplicationAttr(manifest, 'icon', iconRes)
  238. def changeApplicationAttr(manifest, attrType, attrValue):
  239. '''
  240. 更改Application的某个属性
  241. '''
  242. for key in namespaces:
  243. ET.register_namespace(key, namespaces[key])
  244. tree = ET.parse(manifest)
  245. root = tree.getroot()
  246. application = root.find('application')
  247. # Namespaces
  248. attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
  249. application.attrib[attrName] = attrValue
  250. tree.write(manifest, encoding)
  251. return 0
  252. def getApplicationAttr(manifest, attrType):
  253. '''
  254. 获取Application的某个属性
  255. '''
  256. for key in namespaces:
  257. ET.register_namespace(key, namespaces[key])
  258. tree = ET.parse(manifest)
  259. root = tree.getroot()
  260. application = root.find('application')
  261. attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
  262. if attrName in application.attrib:
  263. return application.attrib[attrName]
  264. return None
  265. def getNamespacesFormat(text, namespaces):
  266. '''
  267. 格式化带namespaces的属性
  268. '''
  269. for key in namespaces:
  270. text = text.replace('%s:' % key, '{%s}' % namespaces[key])
  271. return text
  272. def mergeManifestRes(appManifest, libManifest):
  273. '''
  274. 合并主文件
  275. '''
  276. if not os.path.exists(libManifest):
  277. print('file "%s" not exists' % libManifest)
  278. return 1
  279. if not os.path.exists(appManifest):
  280. print('file "%s" not exists' % appManifest)
  281. return 1
  282. libInfo = getLibManifestInfo(libManifest)
  283. appPermission = getManifestPermission(appManifest)
  284. diffPermission = mergeManifestPermission(appPermission, libInfo['permissionList'])
  285. mergeManifest(appManifest, diffPermission, libInfo['activityList'])
  286. return 0
  287. def getLibManifestInfo(libManifest):
  288. '''
  289. 获取框架的主文件参数
  290. '''
  291. for key in namespaces:
  292. ET.register_namespace(key, namespaces[key])
  293. tree = ET.parse(libManifest)
  294. root = tree.getroot()
  295. permissionList = root.findall('permissions/*')
  296. activityList = root.findall('application/*')
  297. info = {'permissionList' : permissionList, 'activityList' : activityList}
  298. return info
  299. def getManifestPermission(appManifest):
  300. '''
  301. 获取主文件参数
  302. '''
  303. for key in namespaces:
  304. ET.register_namespace(key, namespaces[key])
  305. tree = ET.parse(appManifest)
  306. root = tree.getroot()
  307. return root.findall('uses-permission')
  308. def mergeManifestPermission(appPermission, libPermission):
  309. '''
  310. 合并主文件参数
  311. '''
  312. newPermissionList = []
  313. for permission in libPermission:
  314. if contain(appPermission, permission):
  315. continue
  316. newPermissionList.append(permission)
  317. return newPermissionList
  318. def contain(nodeList, item):
  319. '''
  320. 是否存在
  321. '''
  322. attrName = getNamespacesFormat('android:name', namespaces)
  323. for node in nodeList:
  324. if node.attrib[attrName] == item.attrib[attrName]:
  325. return True
  326. return False
  327. def mergeManifest(appManifest, permissionList, activityList):
  328. '''
  329. 将权限和activity加入到主文件
  330. '''
  331. for key in namespaces:
  332. ET.register_namespace(key, namespaces[key])
  333. tree = ET.parse(appManifest)
  334. root = tree.getroot()
  335. # 权限
  336. for item in permissionList:
  337. root.insert(0, item)
  338. # activity
  339. application = root.find('application')
  340. # 删除不支持属性
  341. attrName = getNamespacesFormat('android:roundIcon', namespaces)
  342. if attrName in application.attrib:
  343. del application.attrib[attrName]
  344. # 删除不支持属性
  345. attrName = getNamespacesFormat('android:testOnly', namespaces)
  346. if attrName in application.attrib:
  347. del application.attrib[attrName]
  348. # 删除不支持属性
  349. attrName = getNamespacesFormat('android:debuggable', namespaces)
  350. if attrName in application.attrib:
  351. del application.attrib[attrName]
  352. # 覆盖
  353. # 移除相同的标签
  354. attrName = getNamespacesFormat('android:name', namespaces)
  355. for item in application.getchildren():
  356. if contain(activityList, item):
  357. application.remove(item)
  358. for item in activityList:
  359. application.insert(1, item)
  360. tree.write(appManifest, encoding)
  361. def addMetaData(manifest, meta):
  362. '''
  363. 添加meta-data
  364. '''
  365. for key in namespaces:
  366. ET.register_namespace(key, namespaces[key])
  367. tree = ET.parse(manifest)
  368. root = tree.getroot()
  369. application = root.find('application')
  370. for key in meta:
  371. val = meta[key]
  372. '''if type(val) == str and val.isdigit():
  373. element = ET.Element('meta-data', {'android:name' : key, 'android:value' : '\\ ' + val})
  374. else:
  375. element = ET.Element('meta-data', {'android:name' : key, 'android:value' : val})'''
  376. element = ET.Element('meta-data', {'android:name' : key, 'android:value' : val})
  377. application.append(element)
  378. tree.write(manifest, encoding)
  379. def readAllRes(resFile, resList):
  380. '''
  381. 读取资源文件
  382. '''
  383. tree = ET.parse(resFile)
  384. root = tree.getroot()
  385. resList += root.getchildren()
  386. return resList
  387. def removeIdFromPublic(pubFile, removeList):
  388. '''
  389. 删除重复的资源
  390. '''
  391. tree = ET.parse(pubFile)
  392. root = tree.getroot()
  393. same = False
  394. for node in root.getchildren():
  395. if containPublic(node, removeList):
  396. print('delete public node : type is %s, name is %s' % (node.attrib['type'], node.attrib['name']))
  397. root.remove(node)
  398. same = True
  399. if same:
  400. tree.write(pubFile, encoding)
  401. def removeSameRes2(resFile, resList, removeList):
  402. '''
  403. 删除重复的资源
  404. '''
  405. tree = ET.parse(resFile)
  406. root = tree.getroot()
  407. same = False
  408. for node in root.getchildren():
  409. if containRes(node, resList):
  410. #print('delete node : tag is %s, name is %s' % (node.tag, node.attrib['name']))
  411. root.remove(node)
  412. removeList.append(node)
  413. same = True
  414. if same:
  415. tree.write(resFile, encoding)
  416. return removeList
  417. def removeSameRes(resFile, resList):
  418. '''
  419. 删除重复的资源
  420. '''
  421. tree = ET.parse(resFile)
  422. root = tree.getroot()
  423. same = False
  424. for node in root.getchildren():
  425. if containRes(node, resList):
  426. #print('delete node : tag is %s, name is %s' % (node.tag, node.attrib['name']))
  427. root.remove(node)
  428. same = True
  429. if same:
  430. tree.write(resFile, encoding)
  431. def containRes(node, resList):
  432. '''
  433. 是否重复
  434. '''
  435. for item in resList:
  436. if item.tag == node.tag and item.attrib['name'] == node.attrib['name']:
  437. return True
  438. return False
  439. def containPublic(node, removeList):
  440. '''
  441. 是否重复
  442. '''
  443. for item in removeList:
  444. if item.tag == node.attrib['type'] and item.attrib['name'] == node.attrib['name']:
  445. return True
  446. return False
  447. def removeRootAttr(manifest, attrType):
  448. for key in namespaces:
  449. ET.register_namespace(key, namespaces[key])
  450. tree = ET.parse(manifest)
  451. root = tree.getroot()
  452. attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
  453. if attrName in root.attrib:
  454. del root.attrib[attrName]
  455. tree.write(manifest, encoding)
  456. return 0
  457. def deleteActivityByName(manifest,activityName):
  458. '''
  459. 获取启动的activity
  460. '''
  461. attrName = getNamespacesFormat('android:name', namespaces)
  462. for key in namespaces:
  463. ET.register_namespace(key, namespaces[key])
  464. targetTree = ET.parse(manifest)
  465. targetRoot = targetTree.getroot()
  466. appNode = targetRoot.find('application')
  467. activitys = appNode.findall('activity')
  468. for activity in activitys:
  469. print ('activity name ======= ' + activity.attrib[attrName])
  470. if activity.attrib[attrName] == activityName:
  471. print('delete ------------------> ' + activityName)
  472. appNode.remove(activity)
  473. targetTree.write(manifest, encoding)
  474. break
  475. def getActivityByName(root,activityName):
  476. '''
  477. 获取activity
  478. '''
  479. attrName = getNamespacesFormat('android:name', namespaces)
  480. for node in root.findall('application/activity'):
  481. print ('activity name = ' + node.attrib[attrName])
  482. if node.attrib[attrName] == activityName:
  483. return node
  484. return None