xml_utils.py 17 KB

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