xml_utils.py 14 KB

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