xml_utils.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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 addMoreIcon(manifest, icon, switchIcon):
  118. '''
  119. 添加多图标
  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. if launcherActivity is None:
  127. return 1
  128. attrName = getNamespacesFormat('android:name', namespaces)
  129. activityName = launcherActivity.attrib[attrName]
  130. activityAlias = ET.Element('activity-alias', {'android:name' : 'com.jmhy.sdk.icon.normal',
  131. 'android:enabled' : 'false',
  132. 'android:icon' : icon,
  133. 'android:targetActivity' : activityName})
  134. activityAlias2 = ET.Element('activity-alias', {'android:name' : 'com.jmhy.sdk.icon.switch',
  135. 'android:enabled' : 'false',
  136. 'android:icon' : switchIcon,
  137. 'android:targetActivity' : activityName})
  138. for item in launcherActivity.getchildren():
  139. activityAlias.append(item)
  140. activityAlias2.append(item)
  141. application = root.find('application')
  142. application.append(activityAlias)
  143. application.append(activityAlias2)
  144. tree.write(manifest, encoding)
  145. return 0
  146. def removeLauncherAttr(manifest, attrType):
  147. '''
  148. 移除启动的activity的label
  149. '''
  150. for key in namespaces:
  151. ET.register_namespace(key, namespaces[key])
  152. tree = ET.parse(manifest)
  153. root = tree.getroot()
  154. launcherActivity = getLauncherActivity(root)
  155. if launcherActivity is None:
  156. return 1
  157. attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
  158. if attrName in launcherActivity.attrib:
  159. del launcherActivity.attrib[attrName]
  160. tree.write(manifest, encoding)
  161. return 0
  162. def changeLauncherAttr(manifest, attrType, attrValue):
  163. '''
  164. 更改启动的activity的属性
  165. '''
  166. for key in namespaces:
  167. ET.register_namespace(key, namespaces[key])
  168. tree = ET.parse(manifest)
  169. root = tree.getroot()
  170. launcherActivity = getLauncherActivity(root)
  171. if launcherActivity is None:
  172. return 1
  173. attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
  174. if attrName in launcherActivity.attrib:
  175. launcherActivity.attrib[attrName] = attrValue
  176. tree.write(manifest, encoding)
  177. return 0
  178. def changeAppIcon(manifest, iconRes):
  179. '''
  180. 更改app icon
  181. '''
  182. # 移除主activity的图标
  183. removeLauncherAttr(manifest, 'icon')
  184. return changeApplicationAttr(manifest, 'icon', iconRes)
  185. def changeApplicationAttr(manifest, attrType, attrValue):
  186. '''
  187. 更改Application的某个属性
  188. '''
  189. for key in namespaces:
  190. ET.register_namespace(key, namespaces[key])
  191. tree = ET.parse(manifest)
  192. root = tree.getroot()
  193. application = root.find('application')
  194. # Namespaces
  195. attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
  196. application.attrib[attrName] = attrValue
  197. tree.write(manifest, encoding)
  198. return 0
  199. def getApplicationAttr(manifest, attrType):
  200. '''
  201. 获取Application的某个属性
  202. '''
  203. for key in namespaces:
  204. ET.register_namespace(key, namespaces[key])
  205. tree = ET.parse(manifest)
  206. root = tree.getroot()
  207. application = root.find('application')
  208. attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
  209. if attrName in application.attrib:
  210. return application.attrib[attrName]
  211. return None
  212. def getNamespacesFormat(text, namespaces):
  213. '''
  214. 格式化带namespaces的属性
  215. '''
  216. for key in namespaces:
  217. text = text.replace('%s:' % key, '{%s}' % namespaces[key])
  218. return text
  219. def mergeManifestRes(appManifest, libManifest):
  220. '''
  221. 合并主文件
  222. '''
  223. if not os.path.exists(libManifest):
  224. print('file "%s" not exists' % libManifest)
  225. return 1
  226. if not os.path.exists(appManifest):
  227. print('file "%s" not exists' % appManifest)
  228. return 1
  229. libInfo = getLibManifestInfo(libManifest)
  230. appPermission = getManifestPermission(appManifest)
  231. diffPermission = mergeManifestPermission(appPermission, libInfo['permissionList'])
  232. mergeManifest(appManifest, diffPermission, libInfo['activityList'])
  233. return 0
  234. def getLibManifestInfo(libManifest):
  235. '''
  236. 获取框架的主文件参数
  237. '''
  238. for key in namespaces:
  239. ET.register_namespace(key, namespaces[key])
  240. tree = ET.parse(libManifest)
  241. root = tree.getroot()
  242. permissionList = root.findall('permissions/*')
  243. activityList = root.findall('application/*')
  244. info = {'permissionList' : permissionList, 'activityList' : activityList}
  245. return info
  246. def getManifestPermission(appManifest):
  247. '''
  248. 获取主文件参数
  249. '''
  250. for key in namespaces:
  251. ET.register_namespace(key, namespaces[key])
  252. tree = ET.parse(appManifest)
  253. root = tree.getroot()
  254. return root.findall('uses-permission')
  255. def mergeManifestPermission(appPermission, libPermission):
  256. '''
  257. 合并主文件参数
  258. '''
  259. newPermissionList = []
  260. for permission in libPermission:
  261. if contain(appPermission, permission):
  262. continue
  263. newPermissionList.append(permission)
  264. return newPermissionList
  265. def contain(nodeList, item):
  266. '''
  267. 是否存在
  268. '''
  269. attrName = getNamespacesFormat('android:name', namespaces)
  270. for node in nodeList:
  271. if node.attrib[attrName] == item.attrib[attrName]:
  272. return True
  273. return False
  274. def mergeManifest(appManifest, permissionList, activityList):
  275. '''
  276. 将权限和activity加入到主文件
  277. '''
  278. for key in namespaces:
  279. ET.register_namespace(key, namespaces[key])
  280. tree = ET.parse(appManifest)
  281. root = tree.getroot()
  282. # 权限
  283. for item in permissionList:
  284. root.insert(0, item)
  285. # activity
  286. application = root.find('application')
  287. # 删除不支持属性
  288. attrName = getNamespacesFormat('android:roundIcon', namespaces)
  289. if attrName in application.attrib:
  290. del application.attrib[attrName]
  291. # 删除不支持属性
  292. attrName = getNamespacesFormat('android:testOnly', namespaces)
  293. if attrName in application.attrib:
  294. del application.attrib[attrName]
  295. # 删除不支持属性
  296. attrName = getNamespacesFormat('android:debuggable', namespaces)
  297. if attrName in application.attrib:
  298. del application.attrib[attrName]
  299. # 覆盖
  300. # 移除相同的标签
  301. attrName = getNamespacesFormat('android:name', namespaces)
  302. for item in application.getchildren():
  303. if contain(activityList, item):
  304. application.remove(item)
  305. for item in activityList:
  306. application.insert(1, item)
  307. tree.write(appManifest, encoding)
  308. def addMetaData(manifest, meta):
  309. '''
  310. 添加meta-data
  311. '''
  312. for key in namespaces:
  313. ET.register_namespace(key, namespaces[key])
  314. tree = ET.parse(manifest)
  315. root = tree.getroot()
  316. application = root.find('application')
  317. for key in meta:
  318. val = meta[key]
  319. '''if type(val) == str and val.isdigit():
  320. element = ET.Element('meta-data', {'android:name' : key, 'android:value' : '\\ ' + val})
  321. else:
  322. element = ET.Element('meta-data', {'android:name' : key, 'android:value' : val})'''
  323. element = ET.Element('meta-data', {'android:name' : key, 'android:value' : val})
  324. application.append(element)
  325. tree.write(manifest, encoding)
  326. def readAllRes(resFile, resList):
  327. '''
  328. 读取资源文件
  329. '''
  330. tree = ET.parse(resFile)
  331. root = tree.getroot()
  332. resList += root.getchildren()
  333. return resList
  334. def removeSameRes(resFile, resList):
  335. '''
  336. 删除重复的资源
  337. '''
  338. tree = ET.parse(resFile)
  339. root = tree.getroot()
  340. same = False
  341. for node in root.getchildren():
  342. if containRes(node, resList):
  343. print('delete node : tag is %s, name is %s' % (node.tag, node.attrib['name']))
  344. root.remove(node)
  345. same = True
  346. if same:
  347. tree.write(resFile, encoding)
  348. def containRes(node, resList):
  349. '''
  350. 是否重复
  351. '''
  352. for item in resList:
  353. if item.tag == node.tag and item.attrib['name'] == node.attrib['name']:
  354. return True
  355. return False
  356. def removeRootAttr(manifest, attrType):
  357. for key in namespaces:
  358. ET.register_namespace(key, namespaces[key])
  359. tree = ET.parse(manifest)
  360. root = tree.getroot()
  361. attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
  362. if attrName in root.attrib:
  363. del root.attrib[attrName]
  364. tree.write(manifest, encoding)
  365. return 0