import xml.etree.ElementTree as ET import os.path namespaces = {'android' : 'http://schemas.android.com/apk/res/android'} encoding = 'UTF-8' def getPackageName(manifest): ''' 获取包名 ''' tree = ET.parse(manifest) root = tree.getroot() return root.attrib['package'] def changePackageName(manifest, packageName): ''' 更改包名 ''' for key in namespaces: ET.register_namespace(key, namespaces[key]) tree = ET.parse(manifest) root = tree.getroot() root.attrib['package'] = packageName tree.write(manifest, encoding) def removeLauncherActivity(manifest): ''' 删除启动的activity ''' for key in namespaces: ET.register_namespace(key, namespaces[key]) tree = ET.parse(manifest) root = tree.getroot() attrName = getNamespacesFormat('android:name', namespaces) for node in root.findall('application/activity'): if len(node.getchildren()) <= 0: continue for sub in node.getchildren(): if sub.tag != 'intent-filter': continue for sub2 in sub.getchildren(): if not (sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER'): continue node.remove(sub) tree.write(manifest, encoding) return node.attrib[attrName] return 0 def removeLauncherActivityByName(manifest,name): ''' 删除启动的activity ''' for key in namespaces: ET.register_namespace(key, namespaces[key]) tree = ET.parse(manifest) root = tree.getroot() attrName = getNamespacesFormat('android:name', namespaces) for node in root.findall('application/activity'): print('node ----> ' + node.attrib[attrName]) if node.attrib[attrName] != name: continue for sub in node.getchildren(): if sub.tag != 'intent-filter': continue for sub2 in sub.getchildren(): if not (sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER'): continue node.remove(sub) tree.write(manifest, encoding) return node.attrib[attrName] return 0 def getScreenOrientation(manifest): ''' 获取启动activity的方向 ''' for key in namespaces: ET.register_namespace(key, namespaces[key]) tree = ET.parse(manifest) root = tree.getroot() attrName = getNamespacesFormat('android:name', namespaces) attrOrientation = getNamespacesFormat('android:screenOrientation', namespaces) for node in root.findall('application/activity'): if len(node.getchildren()) <= 0: continue for sub in node.getchildren(): if sub.tag != 'intent-filter': continue for sub2 in sub.getchildren(): if not (sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER'): continue return node.attrib[attrOrientation] return 0 def addLauncherActivity(manifest, screenOrientation, activity): ''' 添加启动的activity ''' for key in namespaces: ET.register_namespace(key, namespaces[key]) tree = ET.parse(manifest) root = tree.getroot() # activity ''' ''' activity = ET.Element('activity', {'android:name' : activity, 'android:theme' : '@android:style/Theme.Holo.Light.NoActionBar.Fullscreen', 'android:launchMode' : 'singleTop', 'android:configChanges' : 'orientation|screenSize|keyboardHidden', 'android:screenOrientation' : screenOrientation}) intent = ET.Element('intent-filter') action = ET.Element('action', {'android:name' : 'android.intent.action.MAIN'}) category = ET.Element('category', {'android:name' : 'android.intent.category.LAUNCHER'}) intent.append(action) intent.append(category) activity.append(intent) application = root.find('application') application.insert(0, activity) tree.write(manifest, encoding) def changeAppName(manifest, stringRes): ''' 更改app名 ''' # 移除主activity的label removeLauncherAttr(manifest, 'label') return changeApplicationAttr(manifest, 'label', stringRes) def getLauncherActivity(root): ''' 获取启动的activity ''' attrName = getNamespacesFormat('android:name', namespaces) for node in root.findall('application/activity'): if len(node.getchildren()) <= 0: continue for sub in node.getchildren(): if sub.tag != 'intent-filter': continue for sub2 in sub.getchildren(): if sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER': return node return None def getLauncherActivitys(manifest): ''' 获取启动的activity ''' attrName = getNamespacesFormat('android:name', namespaces) nodeList = [] tree = ET.parse(manifest) root = tree.getroot() for node in root.findall('application/activity'): if len(node.getchildren()) <= 0: continue for sub in node.getchildren(): if sub.tag != 'intent-filter': continue for sub2 in sub.getchildren(): if sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER': nodeList.append(node) return nodeList def getLauncherActivityName(manifest): ''' 获取启动的activity ''' for key in namespaces: ET.register_namespace(key, namespaces[key]) tree = ET.parse(manifest) root = tree.getroot() launcherActivity = getLauncherActivity(root) attrName = getNamespacesFormat('android:name', namespaces) activityName = launcherActivity.attrib[attrName] return activityName def addMoreIcon(manifest, icon, switchIcon): ''' 添加多图标 ''' for key in namespaces: ET.register_namespace(key, namespaces[key]) tree = ET.parse(manifest) root = tree.getroot() launcherActivity = getLauncherActivity(root) if launcherActivity is None: return 1 attrName = getNamespacesFormat('android:name', namespaces) activityName = launcherActivity.attrib[attrName] activityAlias = ET.Element('activity-alias', {'android:name' : 'com.jmhy.sdk.icon.normal', 'android:enabled' : 'false', 'android:icon' : icon, 'android:targetActivity' : activityName}) activityAlias2 = ET.Element('activity-alias', {'android:name' : 'com.jmhy.sdk.icon.switch', 'android:enabled' : 'false', 'android:icon' : switchIcon, 'android:targetActivity' : activityName}) for item in launcherActivity.getchildren(): activityAlias.append(item) activityAlias2.append(item) application = root.find('application') application.append(activityAlias) application.append(activityAlias2) tree.write(manifest, encoding) return 0 def removeLauncherAttr(manifest, attrType): ''' 移除启动的activity的label ''' for key in namespaces: ET.register_namespace(key, namespaces[key]) tree = ET.parse(manifest) root = tree.getroot() launcherActivity = getLauncherActivity(root) if launcherActivity is None: return 1 attrName = getNamespacesFormat('android:%s' % attrType, namespaces) if attrName in launcherActivity.attrib: del launcherActivity.attrib[attrName] tree.write(manifest, encoding) return 0 def changeLauncherAttr(manifest, attrType, attrValue): ''' 更改启动的activity的属性 ''' for key in namespaces: ET.register_namespace(key, namespaces[key]) tree = ET.parse(manifest) root = tree.getroot() launcherActivity = getLauncherActivity(root) if launcherActivity is None: return 1 attrName = getNamespacesFormat('android:%s' % attrType, namespaces) if attrName in launcherActivity.attrib: launcherActivity.attrib[attrName] = attrValue tree.write(manifest, encoding) return 0 def changeAppIcon(manifest, iconRes): ''' 更改app icon ''' # 移除主activity的图标 removeLauncherAttr(manifest, 'icon') return changeApplicationAttr(manifest, 'icon', iconRes) def changeApplicationAttr(manifest, attrType, attrValue): ''' 更改Application的某个属性 ''' for key in namespaces: ET.register_namespace(key, namespaces[key]) tree = ET.parse(manifest) root = tree.getroot() application = root.find('application') # Namespaces attrName = getNamespacesFormat('android:%s' % attrType, namespaces) application.attrib[attrName] = attrValue tree.write(manifest, encoding) return 0 def addApplicationAttr(manifest, attrType, attrValue): ''' 更改Application的某个属性 ''' for key in namespaces: ET.register_namespace(key, namespaces[key]) tree = ET.parse(manifest) root = tree.getroot() application = root.find('application') # Namespaces attrName = getNamespacesFormat('android:%s' % attrType, namespaces) application.set(attrName,attrValue) tree.write(manifest, encoding) return 0 def getApplicationAttr(manifest, attrType): ''' 获取Application的某个属性 ''' for key in namespaces: ET.register_namespace(key, namespaces[key]) tree = ET.parse(manifest) root = tree.getroot() application = root.find('application') attrName = getNamespacesFormat('android:%s' % attrType, namespaces) if attrName in application.attrib: return application.attrib[attrName] return None def getNamespacesFormat(text, namespaces): ''' 格式化带namespaces的属性 ''' for key in namespaces: text = text.replace('%s:' % key, '{%s}' % namespaces[key]) return text def mergeManifestRes(appManifest, libManifest): ''' 合并主文件 ''' if not os.path.exists(libManifest): print('file "%s" not exists' % libManifest) return 1 if not os.path.exists(appManifest): print('file "%s" not exists' % appManifest) return 1 libInfo = getLibManifestInfo(libManifest) appPermission = getManifestPermission(appManifest) diffPermission = mergeManifestPermission(appPermission, libInfo['permissionList']) mergeManifest(appManifest, diffPermission, libInfo['activityList']) return 0 def getLibManifestInfo(libManifest): ''' 获取框架的主文件参数 ''' for key in namespaces: ET.register_namespace(key, namespaces[key]) tree = ET.parse(libManifest) root = tree.getroot() permissionList = root.findall('permissions/*') activityList = root.findall('application/*') info = {'permissionList' : permissionList, 'activityList' : activityList} return info def getManifestPermission(appManifest): ''' 获取主文件参数 ''' for key in namespaces: ET.register_namespace(key, namespaces[key]) tree = ET.parse(appManifest) root = tree.getroot() return root.findall('uses-permission') def mergeManifestPermission(appPermission, libPermission): ''' 合并主文件参数 ''' newPermissionList = [] for permission in libPermission: if contain(appPermission, permission): continue newPermissionList.append(permission) return newPermissionList def contain(nodeList, item): ''' 是否存在 ''' attrName = getNamespacesFormat('android:name', namespaces) for node in nodeList: if node.attrib[attrName] == item.attrib[attrName]: return True return False def mergeManifest(appManifest, permissionList, activityList): ''' 将权限和activity加入到主文件 ''' for key in namespaces: ET.register_namespace(key, namespaces[key]) tree = ET.parse(appManifest) root = tree.getroot() # 权限 for item in permissionList: root.insert(0, item) # activity application = root.find('application') # 删除不支持属性 attrName = getNamespacesFormat('android:roundIcon', namespaces) if attrName in application.attrib: del application.attrib[attrName] # 删除不支持属性 attrName = getNamespacesFormat('android:testOnly', namespaces) if attrName in application.attrib: del application.attrib[attrName] # 删除不支持属性 attrName = getNamespacesFormat('android:debuggable', namespaces) if attrName in application.attrib: del application.attrib[attrName] # 覆盖 # 移除相同的标签 attrName = getNamespacesFormat('android:name', namespaces) for item in application.getchildren(): if contain(activityList, item): application.remove(item) for item in activityList: application.insert(1, item) tree.write(appManifest, encoding) def addMetaData(manifest, meta): ''' 添加meta-data ''' for key in namespaces: ET.register_namespace(key, namespaces[key]) tree = ET.parse(manifest) root = tree.getroot() application = root.find('application') for key in meta: val = meta[key] '''if type(val) == str and val.isdigit(): element = ET.Element('meta-data', {'android:name' : key, 'android:value' : '\\ ' + val}) else: element = ET.Element('meta-data', {'android:name' : key, 'android:value' : val})''' element = ET.Element('meta-data', {'android:name' : key, 'android:value' : val}) application.append(element) tree.write(manifest, encoding) def readAllRes(resFile, resList): ''' 读取资源文件 ''' tree = ET.parse(resFile) root = tree.getroot() resList += root.getchildren() return resList def removeIdFromPublic(pubFile, removeList): ''' 删除重复的资源 ''' tree = ET.parse(pubFile) root = tree.getroot() same = False for node in root.getchildren(): if containPublic(node, removeList): print('delete public node : type is %s, name is %s' % (node.attrib['type'], node.attrib['name'])) root.remove(node) same = True if same: tree.write(pubFile, encoding) def removeSameRes2(resFile, resList, removeList): ''' 删除重复的资源 ''' tree = ET.parse(resFile) root = tree.getroot() same = False for node in root.getchildren(): if containRes(node, resList): #print('delete node : tag is %s, name is %s' % (node.tag, node.attrib['name'])) root.remove(node) removeList.append(node) same = True if same: tree.write(resFile, encoding) return removeList def removeSameRes(resFile, resList): ''' 删除重复的资源 ''' tree = ET.parse(resFile) root = tree.getroot() same = False for node in root.getchildren(): if containRes(node, resList): #print('delete node : tag is %s, name is %s' % (node.tag, node.attrib['name'])) root.remove(node) same = True if same: tree.write(resFile, encoding) def containRes(node, resList): ''' 是否重复 ''' for item in resList: if item.tag == node.tag and item.attrib['name'] == node.attrib['name']: return True return False def containPublic(node, removeList): ''' 是否重复 ''' for item in removeList: if item.tag == node.attrib['type'] and item.attrib['name'] == node.attrib['name']: return True return False def removeRootAttr(manifest, attrType): for key in namespaces: ET.register_namespace(key, namespaces[key]) tree = ET.parse(manifest) root = tree.getroot() attrName = getNamespacesFormat('android:%s' % attrType, namespaces) if attrName in root.attrib: del root.attrib[attrName] tree.write(manifest, encoding) return 0 def deleteActivityByName(manifest,activityName): ''' 删除activity ''' attrName = getNamespacesFormat('android:name', namespaces) for key in namespaces: ET.register_namespace(key, namespaces[key]) targetTree = ET.parse(manifest) targetRoot = targetTree.getroot() appNode = targetRoot.find('application') activitys = appNode.findall('activity') for activity in activitys: if activity.attrib[attrName] == activityName: print('delete ------------------> ' + activityName) appNode.remove(activity) targetTree.write(manifest, encoding) break def getActivityByName(root,activityName): ''' 获取activity ''' attrName = getNamespacesFormat('android:name', namespaces) for node in root.findall('application/activity'): print ('activity name = ' + node.attrib[attrName]) if node.attrib[attrName] == activityName: return node return None def formatXml(manifest): # elemnt为传进来的Elment类,参数indent用于缩进,newline用于换行 indent = '\t' newline = '\n' tree = ET.parse(manifest) root = tree.getroot() # 得到根元素,Element类 prettyXml(root, indent, newline, level=0) # 对子元素进行递归操作 ET.dump(root) return 0 def prettyXml(element, indent, newline, level = 0): # elemnt为传进来的Elment类,参数indent用于缩进,newline用于换行 if element: # 判断element是否有子元素 if element.text == None or element.text.isspace(): # 如果element的text没有内容 element.text = newline + indent * (level + 1) else: element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * (level + 1) #else: # 此处两行如果把注释去掉,Element的text也会另起一行 #element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * level temp = list(element) # 将elemnt转成list for subelement in temp: if temp.index(subelement) < (len(temp) - 1): # 如果不是list的最后一个元素,说明下一个行是同级别元素的起始,缩进应一致 subelement.tail = newline + indent * (level + 1) else: # 如果是list的最后一个元素, 说明下一行是母元素的结束,缩进应该少一个 subelement.tail = newline + indent * level prettyXml(subelement, indent, newline, level = level + 1) # 对子元素进行递归操作