# -*- coding:utf-8 -*- import os import shutil import xml.etree.ElementTree as ET import re import platform from V1.PrintLog import printlog from V1 import Contants SEPARATOR = "" if platform.system() == "Windows": SEPARATOR = "\\" else: SEPARATOR = "/" def copyFiles(fromDir,toDir): #必须合并的列表 mergeList = ["attrs.xml","colors.xml","dimens.xml","drawables.xml","ids.xml","public.xml","strings.xml","style.xml"] printlog(">>>>>>>>>>>>>>>>>>>>>>>>fromDir:<<<<<<<<<<<<<<<<<<<<<<<<<< %s" % fromDir) if os.path.exists(fromDir) == False: printlog("fromDir or toDir is not exists!") return 1 #value文件夹下的xml如果有同名必须合并 valuePattern = re.compile(r".*/values.*") for parent, dirs,files in os.walk(fromDir): toFileParent = parent.replace(fromDir, toDir) for fileName in files: oriFile = "%s/%s"%(parent, fileName) toFile = "%s/%s"%(toFileParent, fileName) # PrintLog("oriFile: %s"%oriFile) # PrintLog("toFile: %s"%toFile) # PrintLog("parent:%s"%parent) #是value文件夹 and 渠道资源与包有相同的文件 if valuePattern.match(parent) and os.path.exists(toFile): # PrintLog("merge file %s to file %s-------------------------"%(oriFile, toFile)) mergeResFile(oriFile, toFile) #当包里没有与渠道相同的文件 elif os.path.exists(toFile) == False: # PrintLog("copy file %s to file %s--------------------------"%(oriFile, toFile)) os.system("mkdir -p %s"%(os.path.dirname(toFile))) shutil.copyfile(oriFile, toFile) pass return 0 def mergeResFile(fromFile,toFile): if not os.path.exists(fromFile): printlog("fromFile or toFile is not exists") return 1 # PrintLog("start to merge %s and %s "%(fromFile,toFile)) sourceTree = ET.parse(fromFile) desTree = ET.parse(toFile) # 临时打包目录 sourceRoot = sourceTree.getroot() desRoot = desTree.getroot() #SDK sourceChildren = list(sourceRoot) desChildren = list(desRoot) #获取原文件attrib,用于排重 desNames = [] publicDict = {} prefixDict = {} for child in desChildren: # PrintLog(child.attrib) desNames.append(child.attrib["name"]) #保存每个属性的最大id值 if fromFile.find("public.xml") > 0: if child.attrib["type"] not in publicDict.keys(): publicDict[child.attrib["type"]] = int(child.attrib["id"],16) if child.attrib["type"] not in prefixDict.keys(): prefixDict[child.attrib["type"]] = child.attrib["id"][0:6] # PrintLog("prefixDict ---- ") # PrintLog(prefixDict) else: newPublicId = int(child.attrib["id"],16) oldPublicId = publicDict[child.attrib["type"]] #publicDict[child.attrib["type"]] = newPublicId if newPublicId > oldPublicId else oldPublicId if newPublicId > oldPublicId: publicDict[child.attrib["type"]] = newPublicId # PrintLog("replace type:%s"%publicDict[child.attrib["type"]]) # PrintLog("replace oldPublicId:%d with newPublicId:%d"%(oldPublicId,newPublicId)) #打印测试信息 # PrintLog("print publicDict ----------------------------") # PrintLog(publicDict) # PrintLog("print publicDict ----------------------------") for child in sourceChildren: if child.attrib["name"] in desNames: #若有重复,使用原包里的的 index = desNames.index(child.attrib["name"]) # PrintLog("confilct child:%s"%desChildren[index].attrib["name"]) continue # PrintLog("append child name:%s"%child.attrib["name"]) #public.xml需要特殊合并 if fromFile.find("public.xml") > 0: if child.attrib["type"] in publicDict: # PrintLog("old id:%s --------------- type:%s"%(child.attrib["id"],child.attrib["type"])) publicDict[child.attrib["type"]] = publicDict[child.attrib["type"]] + 1 child.attrib["id"] = hex(publicDict[child.attrib["type"]]) # PrintLog("new id:%s ---------------"%child.attrib["id"]) #如果ID不存在,则直接清0 elif child.attrib["type"] not in publicDict: # PrintLog("reset id to 00") # PrintLog("old id:%s ---------------"%child.attrib["id"]) last_preffix = sorted(prefixDict.values())[-1] # PrintLog("last object:%s"%last_preffix[-2:]) preffixNum = hex(int(last_preffix[-2:],16)+1)[last_preffix.index("x")+1:] if len(preffixNum) < 2: preffixNum = "0"+preffixNum preffix = "0x7f"+preffixNum # PrintLog("preffix_suffix:%s"%preffix) prefixDict[child.attrib["type"]] = preffix publicDict[child.attrib["type"]] = int(preffix+"0000",16) # PrintLog("publicDict with type:%s and value:%s"%(child.attrib["type"],publicDict[child.attrib["type"]])) child.attrib["id"] = hex(publicDict[child.attrib["type"]]) # PrintLog("publicDict[child.attrib['type']:%s"%publicDict[child.attrib["type"]]) # PrintLog("new id:%s ---------------"%child.attrib["id"]) desRoot.append(child) #PrintLog("print prefixDict ----------------------------") #PrintLog(prefixDict) #PrintLog("print prefixDict ----------------------------") # if fromFile.find("public.xml") > 0: # desRoot.getchildren().sort() # PrintLog("start to write xml") desTree.write(toFile,"utf-8",xml_declaration=True) # PrintLog("finished writing xml") # PrintLog("merging files finished") return 0 #比较函数,用于etree排序 def cmp(x,y): if x.attrib["type"] > y.attrib["type"]: return 1 elif x.attrib["type"] < y.attrib["type"]: return -1 else: return 0 def mergeManifest(targetM,sdkConfig,debug = False): #注册命名空间 ET.register_namespace('android',"http://schemas.android.com/apk/res/android") printlog("targetM:%s" % targetM) printlog("sdkConfig:%s" % sdkConfig) if os.path.exists(targetM) == False or os.path.exists(sdkConfig) == False: printlog("targetM or sdkConfig is not exists!") return 1 sdkRoot = ET.parse(sdkConfig).getroot() if sdkRoot == None: printlog("cant parse sdkConfig!") return 1 targetTree = ET.parse(targetM) targetRoot = targetTree.getroot() if targetRoot == None: printlog("cant parse targetTree") return 1 targetApplicationRoot = targetRoot.find("application") #合并activity和service sdkActivities = sdkRoot.find("sdk_activity").iter("activity") sdkActivities_alicas = sdkRoot.find("sdk_activity").iter("activity-alias") sdkServices = sdkRoot.find("sdk_activity").iter("service") sdkReceiver = sdkRoot.find("sdk_activity").iter("receiver") sdkProvider = sdkRoot.find("sdk_activity").iter("provider") sdkQueries = sdkRoot.find("sdk_activity").iter("queries") for activity in sdkActivities: targetApplicationRoot.append(activity) for service in sdkServices: targetApplicationRoot.append(service) for receiver in sdkReceiver: targetApplicationRoot.append(receiver) for provider in sdkProvider: targetApplicationRoot.append(provider) for alicas in sdkActivities_alicas: targetApplicationRoot.append(alicas) for queries in sdkQueries: targetApplicationRoot.append(queries) printlog("merging activity and service completed!") #合并meta-data sdkMetas = sdkRoot.find("sdk_meta").iter("meta-data") for meta in sdkMetas: targetApplicationRoot.append(meta) printlog("merging meta-data completed!") #合并permission sdkPermissions = [] for per in sdkRoot.find("sdk_permission").findall("uses-permission"): sdkPermissions.append(list(per.attrib.values())[0]) targetPermissions = [] for per in targetRoot.findall("uses-permission"): targetPermissions.append(list(per.attrib.values())[0]) targetRoot.remove(per) #利用set排重 mergePermissions = list(set(sdkPermissions) | set(targetPermissions)) for per in mergePermissions: element = ET.Element("uses-permission") element.attrib = {"android:name":per} element.tail = "\n\t" targetRoot.append(element) printlog("merging permission completed!") if debug: targetTree.write("test.xml","utf-8",xml_declaration=True) else: targetTree.write("%s"%targetM,"utf-8",xml_declaration=True) printlog("writing AndroidManifest.xml completed!") return 0 #fromDir SDK toDir game def mergeDir(fromDir, toDir): if os.path.exists(fromDir) == False: return 1 compareFile(fromDir, toDir) return 0 pass def compareFile(cmpFile, oriFile): exceptList = [ ] for parent, dirName, fileNames in os.walk(cmpFile): oriParent = parent.replace(cmpFile, oriFile) shouldRewrite = parent.rfind("third/sdk") for fileName in fileNames: if shouldRewrite >= 0 or (os.path.exists("%s/%s"%(oriParent, fileName)) == False and parent.find(Contants.getIgnorePackagePath()) < 0): fromDir = "%s/%s"%(parent , fileName) # PrintLog("fromDir :%s"%fromDir) toDir = "%s/%s"%(oriParent, fileName) # PrintLog("toDir: %s"%toDir) copyFileForCompareFile(fromDir, toDir) pass def copyAllFile(fromFile,toFile): for parent, dirName, fileNames in os.walk(fromFile): oriParent = parent.replace(fromFile, toFile) for fileName in fileNames: fromDir = "%s/%s"%(parent , fileName) # PrintLog("fromDir :%s"%fromDir) toDir = "%s/%s"%(oriParent, fileName) # PrintLog("toDir: %s"%toDir) copyFileForCompareFile(fromDir, toDir) pass def copyFileForCompareFile(fromFile, toFile): if os.path.exists(fromFile) == False: printlog("file %s is not exists" % fromFile) return filePattern = re.compile(r".*\..*") toDir = toFile if filePattern.match(toFile): toDir = os.path.dirname(toFile) if os.path.exists(toDir) == False: os.makedirs(toDir) shutil.copy(fromFile, toFile) pass #文件修改时间比较 #file1 > file2 return 1 #file1 == file2 return 0 #file1 < file2 return -1 #任意一个文件不存在则返回None def compareFileModifyTime(file1, file2): result = 0 if not os.path.exists(file1): err = "file %s is not exists"%file1 printlog(err) return None if not os.path.exists(file2): err = "file %s is not exists"%file2 printlog(err) return None file1MTime = os.stat(file1).st_mtime file2MTime = os.stat(file2).st_mtime printlog("[file1MTime]: %s" % file1MTime) printlog("[file2MTime]: %s" % file2MTime) if file1MTime > file2MTime: return 1 elif file1MTime < file2MTime: return -1 else: return 0 pass #合并apktool.yml中的unkown内容 def mergeYmlContent(fromFilePath, toFilePath): printlog("----------------------start mergeYmlContent --------------") if os.path.exists(fromFilePath) == False: return 0 if os.path.exists(toFilePath) == False: shutil.copy(fromFile, toFilePath) return 1 unknownFiles = "unknownFiles:" toFileLines = open(toFilePath).readlines() toFile = open(toFilePath, "w") toFileHasUnknowFilesMark = False #目标文件是否存在unknownFiles属性 for line in toFileLines: if line.find(unknownFiles) >= 0: toFileHasUnknowFilesMark = True #当存在unknownFiles属性但为空时去掉{}重新写入 if line.find("{}") >= 0: line = line.replace("{}", "") toFile.write(line) writeYmlContent(fromFilePath, toFile) continue pass toFile.write(line) pass if toFileHasUnknowFilesMark == False: toFile.write(unknownFiles) toFile.write("\n") writeYmlContent(fromFilePath, toFile) return 1 pass def writeYmlContent(fromFilePath, toFile): unknownFiles = "unknownFiles:" lines = open(fromFilePath).readlines() unknowFilesMarkFound = False for line in lines: if unknowFilesMarkFound: if line.find(" ") == 0: toFile.write(line) else: break if line.find(unknownFiles) >= 0: if line.find("{}") >= 0: break else: unknowFilesMarkFound = True pass pass #文件安全删除 def safeFileDelete(filePath): if os.path.exists(filePath): if os.path.isdir(filePath): shutil.rmtree(filePath) printlog(">>>>>>>>>>>>>>>>>>>>>>>>delete isdir filePath:<<<<<<<<<<<<<<<<<<<<<<<<<< %s" % filePath) elif os.path.isfile(filePath): printlog(">>>>>>>>>>>>>>>>>>>>>>>>delete isfile filePath:<<<<<<<<<<<<<<<<<<<<<<<<<< %s" % filePath) os.remove(filePath) return #删除文件但不删除文件夹 def del_file(path_data): for i in os.listdir(path_data) :# os.listdir(path_data)#返回一个列表,里面是当前目录下面的所有东西的相对路径 file_data = path_data + "/" + i#当前文件夹的下面的所有东西的绝对路径 if os.path.isfile(file_data) == True:#os.path.isfile判断是否为文件,如果是文件,就删除.如果是文件夹.递归给del_file. os.remove(file_data) else: del_file(file_data) if __name__ == "__main__": #mergeManifest("AndroidManifest.xml","test_sdk_config.xml",True) #copyFiles("test","toDir") fromFile ="apktool.yml" toFile = "des_apktool.yml" mergeYmlContent(fromFile, toFile) pass