123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697 |
- import os.path
- import sys
- import xml.etree.ElementTree as ET
- from print_log import printlog
- namespaces = {'android': 'http://schemas.android.com/apk/res/android'}
- encoding = 'UTF-8'
- def get_package_name(manifest):
- """
- 获取包名
- """
- tree = ET.parse(manifest)
- root = tree.getroot()
- return root.attrib['package']
- def change_package_name(manifest, package_name):
- """
- 更改包名
- """
- for key in namespaces:
- ET.register_namespace(key, namespaces[key])
- tree = ET.parse(manifest)
- root = tree.getroot()
- root.attrib['package'] = package_name
- tree.write(manifest, encoding)
- def remove_launcher_activity(manifest):
- """
- 删除启动的activity
- """
- for key in namespaces:
- ET.register_namespace(key, namespaces[key])
- tree = ET.parse(manifest)
- root = tree.getroot()
- attrName = get_namespaces_format('android:name', namespaces)
- for node in root.findall('application/activity'):
- if len(list(node)) <= 0:
- continue
- for sub in list(node):
- 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 remove_launcher_activity_by_name(manifest, name):
- """
- 删除启动的activity
- """
- for key in namespaces:
- ET.register_namespace(key, namespaces[key])
- tree = ET.parse(manifest)
- root = tree.getroot()
- attrName = get_namespaces_format('android:name', namespaces)
- for node in root.findall('application/activity'):
- print('node ----> ' + node.attrib[attrName])
- if node.attrib[attrName] != name:
- continue
- for sub in list(node):
- 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 get_screen_orientation(manifest):
- """
- 获取启动activity的方向
- """
- for key in namespaces:
- ET.register_namespace(key, namespaces[key])
- tree = ET.parse(manifest)
- root = tree.getroot()
- attrName = get_namespaces_format('android:name', namespaces)
- attrOrientation = get_namespaces_format('android:screenOrientation', namespaces)
- for node in root.findall('application/activity'):
- if len(list(node)) <= 0:
- continue
- for sub in list(node):
- 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 add_launcher_activity(manifest, screen_orientation, activity):
- """
- 添加启动的activity
- """
- for key in namespaces:
- ET.register_namespace(key, namespaces[key])
- tree = ET.parse(manifest)
- root = tree.getroot()
- # activity
- '''<activity android:name=".LauncherActivity"
- android:theme="@style/LauncherStyle">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </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': screen_orientation})
- 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 change_app_name(manifest, string_res):
- """
- 更改app名
- """
- # 移除主activity的label
- remove_launcher_attr(manifest, 'label')
- return change_application_attr(manifest, 'label', string_res)
- def get_launcher_activity(root):
- """
- 获取启动的activity
- """
- attrName = get_namespaces_format('android:name', namespaces)
- for node in root.findall('application/activity'):
- if sys.version_info < (3, 9):
- node_dict = node.getchildren()
- else:
- node_dict = list(node)
- if len(node_dict) <= 0:
- continue
- for sub in node_dict:
- if sys.version_info < (3, 9):
- sub_dict = sub.getchildren()
- else:
- sub_dict = list(sub)
- if sub.tag != 'intent-filter':
- continue
- for sub2 in sub_dict:
- if sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER':
- return node
- return None
- def get_launcher_activities(manifest):
- """
- 获取启动的activity
- """
- attrName = get_namespaces_format('android:name', namespaces)
- nodeList = []
- tree = ET.parse(manifest)
- root = tree.getroot()
- for node in root.findall('application/activity'):
- if len(list(node)) <= 0:
- continue
- for sub in list(node):
- 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 get_launcher_activity_name(manifest):
- """
- 获取启动的activity
- """
- for key in namespaces:
- ET.register_namespace(key, namespaces[key])
- tree = ET.parse(manifest)
- root = tree.getroot()
- launcherActivity = get_launcher_activity(root)
- attrName = get_namespaces_format('android:name', namespaces)
- activityName = launcherActivity.attrib[attrName]
- return activityName
- def add_more_icon(manifest, icon, switch_icon):
- """
- 添加多图标
- """
- for key in namespaces:
- ET.register_namespace(key, namespaces[key])
- tree = ET.parse(manifest)
- root = tree.getroot()
- launcherActivity = get_launcher_activity(root)
- if launcherActivity is None:
- return 1
- attrName = get_namespaces_format('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': switch_icon,
- '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 remove_launcher_attr(manifest, attr_type):
- """
- 移除启动的activity的label
- """
- for key in namespaces:
- ET.register_namespace(key, namespaces[key])
- tree = ET.parse(manifest)
- root = tree.getroot()
- launcherActivity = get_launcher_activity(root)
- if launcherActivity is None:
- return 1
- attrName = get_namespaces_format('android:%s' % attr_type, namespaces)
- if attrName in launcherActivity.attrib:
- del launcherActivity.attrib[attrName]
- tree.write(manifest, encoding)
- return 0
- def change_launcher_attr(manifest, attr_type, attr_value):
- """
- 更改启动的activity的属性
- """
- for key in namespaces:
- ET.register_namespace(key, namespaces[key])
- tree = ET.parse(manifest)
- root = tree.getroot()
- launcherActivity = get_launcher_activity(root)
- if launcherActivity is None:
- return 1
- attrName = get_namespaces_format('android:%s' % attr_type, namespaces)
- if attrName in launcherActivity.attrib:
- launcherActivity.attrib[attrName] = attr_value
- tree.write(manifest, encoding)
- return 0
- def change_app_icon(manifest, icon_res):
- """
- 更改app icon
- """
- # 移除主activity的图标
- remove_launcher_attr(manifest, 'icon')
- return change_application_attr(manifest, 'icon', icon_res)
- def change_application_attr(manifest, attr_type, attr_value):
- """
- 更改Application的某个属性
- """
- for key in namespaces:
- ET.register_namespace(key, namespaces[key])
- tree = ET.parse(manifest)
- root = tree.getroot()
- application = root.find('application')
- # Namespaces
- attrName = get_namespaces_format('android:%s' % attr_type, namespaces)
- application.attrib[attrName] = attr_value
- tree.write(manifest, encoding)
- return 0
- def add_application_attr(manifest, attr_type, attr_value):
- """
- 更改Application的某个属性
- """
- for key in namespaces:
- ET.register_namespace(key, namespaces[key])
- tree = ET.parse(manifest)
- root = tree.getroot()
- application = root.find('application')
- # Namespaces
- attrName = get_namespaces_format('android:%s' % attr_type, namespaces)
- application.set(attrName, attr_value)
- tree.write(manifest, encoding)
- return 0
- def get_application_attr(manifest, attr_type):
- """
- 获取Application的某个属性
- """
- for key in namespaces:
- ET.register_namespace(key, namespaces[key])
- tree = ET.parse(manifest)
- root = tree.getroot()
- application = root.find('application')
- attrName = get_namespaces_format('android:%s' % attr_type, namespaces)
- if attrName in application.attrib:
- return application.attrib[attrName]
- return None
- def get_namespaces_format(text, space):
- """
- 格式化带namespaces的属性
- """
- for key in space:
- text = text.replace('%s:' % key, '{%s}' % space[key])
- return text
- def merge_manifest_res(app_manifest, lib_manifest):
- """
- 合并主文件
- """
- if not os.path.exists(lib_manifest):
- print('file "%s" not exists' % lib_manifest)
- return 1
- if not os.path.exists(app_manifest):
- print('file "%s" not exists' % app_manifest)
- return 1
- libInfo = get_lib_manifest_info(lib_manifest)
- appPermission = get_manifest_permission(app_manifest)
- diffPermission = merge_manifest_permission(appPermission, libInfo['permissionList'])
- merge_manifest(app_manifest, diffPermission, libInfo['activityList'])
- return 0
- def get_lib_manifest_info(lib_manifest):
- """
- 获取框架的主文件参数
- """
- for key in namespaces:
- ET.register_namespace(key, namespaces[key])
- tree = ET.parse(lib_manifest)
- root = tree.getroot()
- permissionList = root.findall('permissions/*')
- activityList = root.findall('application/*')
- info = {'permissionList': permissionList, 'activityList': activityList}
- return info
- def get_manifest_permission(app_manifest):
- """
- 获取主文件参数
- """
- for key in namespaces:
- ET.register_namespace(key, namespaces[key])
- tree = ET.parse(app_manifest)
- root = tree.getroot()
- return root.findall('uses-permission')
- def merge_manifest_permission(app_permission, lib_permission):
- """
- 合并主文件参数
- """
- newPermissionList = []
- for permission in lib_permission:
- if contain(app_permission, permission):
- continue
- newPermissionList.append(permission)
- return newPermissionList
- def contain(node_list, item):
- """
- 是否存在
- """
- attrName = get_namespaces_format('android:name', namespaces)
- for node in node_list:
- if node.attrib[attrName] == item.attrib[attrName]:
- return True
- return False
- def merge_manifest(app_manifest, permission_list, activity_list):
- """
- 将权限和activity加入到主文件
- """
- for key in namespaces:
- ET.register_namespace(key, namespaces[key])
- tree = ET.parse(app_manifest)
- root = tree.getroot()
- # 权限
- for item in permission_list:
- root.insert(0, item)
- # activity
- application = root.find('application')
- # 删除不支持属性
- attrName = get_namespaces_format('android:roundIcon', namespaces)
- if attrName in application.attrib:
- del application.attrib[attrName]
- # 删除不支持属性
- attrName = get_namespaces_format('android:testOnly', namespaces)
- if attrName in application.attrib:
- del application.attrib[attrName]
- # 删除不支持属性
- attrName = get_namespaces_format('android:debuggable', namespaces)
- if attrName in application.attrib:
- del application.attrib[attrName]
- # 覆盖
- # 移除相同的标签
- attrName = get_namespaces_format('android:name', namespaces)
- if sys.version_info < (3, 9):
- children_dict = application.getchildren()
- else:
- children_dict = list(application)
- for item in children_dict:
- if contain(activity_list, item):
- application.remove(item)
- for item in activity_list:
- application.insert(1, item)
- tree.write(app_manifest, 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 read_all_res(res_file, res_list):
- """
- 读取资源文件
- """
- tree = ET.parse(res_file)
- root = tree.getroot()
- if sys.version_info < (3, 9):
- res_list += root.getchildren()
- else:
- res_list += list(root)
- return res_list
- def remove_id_from_public(pub_file, remove_list):
- """
- 删除重复的资源
- """
- tree = ET.parse(pub_file)
- root = tree.getroot()
- same = False
- for node in root.getchildren():
- if containPublic(node, remove_list):
- 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(pub_file, encoding)
- def remove_same_res2(res_file, res_list, remove_list):
- """
- 删除重复的资源
- """
- tree = ET.parse(res_file)
- root = tree.getroot()
- same = False
- for node in root.getchildren():
- if containRes(node, res_list):
- # print('delete node : tag is %s, name is %s' % (node.tag, node.attrib['name']))
- root.remove(node)
- remove_list.append(node)
- same = True
- if same:
- tree.write(res_file, encoding)
- return remove_list
- def remove_same_values_res(res_file, res_list):
- """
- 删除重复的资源
- """
- tree = ET.parse(res_file)
- root = tree.getroot()
- same = False
- if sys.version_info < (3, 9):
- children_dict = root.getchildren()
- else:
- children_dict = list(root)
- for node in children_dict:
- if containRes(node, res_list):
- printlog('[delete node]: tag is %s, name is %s' % (node.tag, node.attrib['name']))
- root.remove(node)
- same = True
- if same:
- tree.write(res_file, encoding)
- def containRes(node, res_list):
- """
- 是否重复
- """
- for item in res_list:
- if item.tag == node.tag and item.attrib['name'] == node.attrib['name']:
- return True
- return False
- def containPublic(node, remove_list):
- """
- 是否重复
- """
- for item in remove_list:
- if item.tag == node.attrib['type'] and item.attrib['name'] == node.attrib['name']:
- return True
- return False
- def remove_root_attr(manifest, attr_type):
- for key in namespaces:
- ET.register_namespace(key, namespaces[key])
- tree = ET.parse(manifest)
- root = tree.getroot()
- attrName = get_namespaces_format('android:%s' % attr_type, namespaces)
- if attrName in root.attrib:
- del root.attrib[attrName]
- tree.write(manifest, encoding)
- return 0
- def delete_activity_by_name(manifest, activity_name):
- """
- 删除activity
- """
- attrName = get_namespaces_format('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] == activity_name:
- print('delete ------------------> ' + activity_name)
- appNode.remove(activity)
- targetTree.write(manifest, encoding)
- break
- def get_activity_by_name(root, activity_name):
- """
- 获取activity
- """
- attrName = get_namespaces_format('android:name', namespaces)
- for node in root.findall('application/activity'):
- print('activity name = ' + node.attrib[attrName])
- if node.attrib[attrName] == activity_name:
- 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) # 对子元素进行递归操作
|