123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528 |
- # -*-coding:utf-8-*-
- import json
- import os, shutil, yaml
- import re
- import xml.etree.ElementTree as ET
- import ChannelReplace, contants
- from print_log import printlog
- androidNS = 'http://schemas.android.com/apk/res/android'
- namespace = '{' + androidNS + '}'
- def special_replace(sdk_name, prj_path, key, value):
- # 获取特殊替换
- replaceFun = ChannelReplace.getSpecilReplace(sdk_name)
- if replaceFun is None:
- printlog("no such channel: %s" % sdk_name)
- else:
- printlog("begin special replace: %s" % sdk_name)
- replaceFun(prj_path, key, value)
- pass
- def modifyRfileSmaliPath(channel, prj_path):
- printlog("start copy and modify R.smali-------")
- manifestRoot = ET.parse("%s/AndroidManifest.xml" % prj_path).getroot()
- pkgName = manifestRoot.attrib["package"]
- sdk_root_dir = contants.channel_sdk_path
- sdkRfilePath = "%s/%s/%s/extension/smali" % (sdk_root_dir, channel, channel)
- printlog("sdkRfilePath:%s" % sdkRfilePath)
- if os.path.exists(sdkRfilePath):
- printlog("begin copy R.smali to apkpath---------")
- apkPkgDir = ET.parse("%s/AndroidManifest.xml" % prj_path).getroot().attrib["package"].replace(".", "/")
- apkRfilePath = "%s/smali/%s" % (prj_path, apkPkgDir)
- if not os.path.exists(apkRfilePath):
- os.makedirs(apkRfilePath)
- os.system("/bin/cp -r %s/* %s" % (sdkRfilePath, apkRfilePath))
- for parent, dirnames, filenames in os.walk(apkRfilePath):
- printlog("replace apkRfile dirnames:%s" % dirnames)
- for filename in filenames:
- filepath = "'%s/%s'" % (apkRfilePath, filename)
- replacePkgShell = 'sed -i "s#%s#%s#g" %s' % ("package_path", apkPkgDir, filepath)
- os.system(replacePkgShell)
- replacePkgShell = 'sed -i "s#%s#%s#g" %s' % ("package_name", pkgName, filepath)
- os.system(replacePkgShell)
- printlog("end copy R.smali file -------------------------------")
- def createRFile2Sdk(pkgAbsoluteRpath, sdkAbsoluteRpath, pkgRpath, sdkRpath):
- if os.path.exists(sdkAbsoluteRpath):
- del_file(sdkAbsoluteRpath)
- else:
- os.mkdir(sdkAbsoluteRpath)
- copyAllFile(pkgAbsoluteRpath, sdkAbsoluteRpath)
- printlog("pkgRpath: -------------%s" % pkgRpath)
- printlog("sdkRpath: -------------%s" % sdkRpath)
- for root, dirs, files in os.walk(sdkAbsoluteRpath):
- for file in files:
- if "$" in file:
- file = file.split('$', 1)[0] + "\$" + file.split('$', 1)[1]
- replaceKeyword(pkgRpath, sdkRpath, os.path.join(root, file))
- def replaceKeyword(key, value, file):
- replaceShell = 'sed -i "s#%s#%s#g" %s' % (key, value, file)
- printlog("replaceShell:%s" % replaceShell)
- os.system(replaceShell)
- pass
- def mergeLibs(sdkPath, apkPath):
- printlog("--------------------------- start to merge lib --------------------------------")
- apkLib = "%s/lib" % apkPath
- sdkLib = "%s/lib" % sdkPath
- ret = 0
- if not os.path.exists(apkLib) and os.path.exists(sdkLib):
- shutil.copytree(sdkLib, apkLib)
- printlog("finished merging lib --------------------------------")
- return ret
- apkFiles = os.listdir(apkLib)
- sdkFiles = os.listdir(sdkLib)
- for cpFile in sdkFiles:
- if os.path.isfile(cpFile) == False and cpFile not in apkFiles:
- continue
- ret = ret | mergeFiles("%s/lib/%s" % (sdkPath, cpFile), "%s/lib/%s" % (apkPath, cpFile))
- printlog("--------------------------- finished merging lib --------------------------------")
- return ret
- def mergeFiles(fromDir, toDir):
- # 必须合并的列表
- mergeList = ["attrs.xml", "colors.xml", "dimens.xml", "drawables.xml", "ids.xml", "public.xml", "strings.xml",
- "style.xml"]
- printlog(">>>>>>>>>>>>>>>>>>>>>>>>fromDir:<<<<<<<<<<<<<<<<<<<<<<<<<< %s" % fromDir)
- if not os.path.exists(fromDir):
- 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 not os.path.exists(toFile):
- # 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
- def mergeDir(fromDir, toDir):
- if not os.path.exists(fromDir):
- 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.ignore_package_path) < 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 not os.path.exists(fromFile):
- printlog("file %s is not exists" % fromFile)
- return
- filePattern = re.compile(r".*\..*")
- toDir = toFile
- if filePattern.match(toFile):
- toDir = os.path.dirname(toFile)
- if not os.path.exists(toDir):
- os.makedirs(toDir)
- shutil.copy(fromFile, toFile)
- 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): # os.path.isfile判断是否为文件,如果是文件,就删除.如果是文件夹.递归给del_file.
- os.remove(file_data)
- else:
- del_file(file_data)
- def add_point_smali(sdkPath, apkPath):
- printlog("--------------------------- start to merge resources ---------------------------")
- ret = 0
- # merge res
- # sdk_root_dir = apk_utils.getCutSdkRootHome() + "/" + os.path.basename(sdkPath)
- ret = ret | mergeFiles("%s/res" % sdkPath, "%s/res" % apkPath)
- # copy lib and assets
- # 避免由于架构导致复制无用架构
- ret = ret | mergeLibs(sdkPath, apkPath)
- ret = ret | mergeFiles("%s/assets" % sdkPath, "%s/assets" % apkPath)
- ret = ret | mergeDir("%s/smali" % sdkPath, "%s/smali" % apkPath)
- def mergeYml(fromfile, tofile):
- if not os.path.exists(fromfile):
- return False, "origin yaml file is not exists"
- if not os.path.exists(tofile):
- return False, "destination yaml file is not exists"
- header = "!!brut.androlib.meta.MetaInfo\n"
- fromcontent = open(fromfile, "r").read()
- fromcontent = fromcontent.replace(header, "")
- tocontent = open(tofile, "r").read()
- tocontent = tocontent.replace(header, "")
- fromroot = yaml.safe_load(fromcontent)
- toroot = yaml.safe_load(tocontent)
- if fromroot is None:
- printlog("from root is empty")
- return False, "orgin yaml file cant not be parsed or empty"
- if toroot is None:
- printlog("to root is empty")
- return False, "destination yaml file cant not be parsed or is empty"
- donotcompresskey = "doNotCompress"
- if donotcompresskey in fromroot:
- arr = fromroot[donotcompresskey]
- if not donotcompresskey in toroot:
- toroot[donotcompresskey] = arr
- else:
- toarr = toroot[donotcompresskey]
- toroot[donotcompresskey] = list(set(toarr + arr))
- unknownfileskey = "unknownFiles"
- if unknownfileskey in fromroot:
- fromunknownfilesarr = fromroot[unknownfileskey]
- else:
- fromunknownfilesarr = {}
- tounknownfilesarr = toroot[unknownfileskey]
- toroot[unknownfileskey] = dict(fromunknownfilesarr.items()).update(tounknownfilesarr.items())
- desfile = open(tofile, "w")
- desfile.writelines(header)
- yaml.safe_dump(toroot, desfile, default_flow_style=False)
- return True, ""
- pass
- # sdk resources + apk resources
- def mergeResources(sdkPath, apkPath):
- printlog("--------------------------- start to merge resources ---------------------------")
- ret = 0
- # merge res
- # sdk_root_dir = apk_utils.getCutSdkRootHome() + "/" + os.path.basename(sdkPath)
- ret = ret | mergeFiles("%s/res" % sdkPath, "%s/res" % apkPath)
- # copy lib and assets
- # 避免由于架构导致复制无用架构
- ret = ret | mergeLibs(sdkPath, apkPath)
- ret = ret | mergeFiles("%s/assets" % sdkPath, "%s/assets" % apkPath)
- ret = ret | mergeDir("%s/smali" % sdkPath, "%s/smali" % apkPath)
- ret = ret | mergeDir("%s/smali_classes2" % sdkPath, "%s/smali_classes2" % apkPath)
- ret = ret | mergeDir("%s/smali_classes3" % sdkPath, "%s/smali_classes3" % apkPath)
- ret = ret | mergeDir("%s/smali_classes4" % sdkPath, "%s/smali_classes4" % apkPath)
- ret = ret | mergeDir("%s/smali_classes5" % sdkPath, "%s/smali_classes5" % apkPath)
- ret = ret | mergeDir("%s/smali_classes6" % sdkPath, "%s/smali_classes6" % apkPath)
- ret = ret | mergeDir("%s/unknown" % sdkPath, "%s/unknown" % apkPath)
- # 暂时的方案是用sdk的apktool.yml覆盖原包apktool.yml 后期需要做apktool.yml合并
- if os.path.exists("%s/apktool.yml" % sdkPath):
- mergeYml("%s/apktool.yml" % sdkPath, "%s/apktool.yml" % apkPath)
- # shutil.copy("%s/apktool.yml"%sdkPath, "%s/apktool.yml"%apkPath)
- # 修改微信支付
- # ret = ret | File.copyFiles("%s/smali"%sdkPath,"%s/smali"%apkPath)
- printlog("--------------------------- finished merging resources ---------------------------")
- return ret
- def get_lauch_activity_name(apk_decompile_tmp_dir):
- sdkAM = os.path.join(apk_decompile_tmp_dir, 'AndroidManifest.xml')
- ET.register_namespace('android', androidNS)
- tree = ET.parse(sdkAM)
- activitys = tree.getroot().find("application").findall("activity")
- for activity in activitys:
- filters = activity.findall('intent-filter')
- for filter in filters:
- categorys = filter.findall('category')
- for category in categorys:
- categoryname = category.attrib[namespace + "name"]
- if categoryname == "android.intent.category.LAUNCHER":
- actname = activity.attrib[namespace + "name"]
- return actname
- def get_lauch_activity_screen_orientation(apk_decompile_tmp_dir):
- sdkAM = os.path.join(apk_decompile_tmp_dir, 'AndroidManifest.xml')
- ET.register_namespace('android', androidNS)
- tree = ET.parse(sdkAM)
- activitys = tree.getroot().find("application").findall("activity")
- for activity in activitys:
- filters = activity.findall('intent-filter')
- for filter in filters:
- categorys = filter.findall('category')
- for category in categorys:
- categoryname = category.attrib[namespace + "name"]
- if categoryname == "android.intent.category.LAUNCHER":
- screenOrientation = activity.attrib[namespace + "screenOrientation"]
- return screenOrientation
- def modify_R_id_smali(prj_path, r_path):
- apkRfilePath = "%s%s" % (prj_path, r_path)
- publicXml = "%s/res/values/public.xml" % prj_path
- jarPath = "%s/MergeSamli.jar" % contants.tool_jar_home
- javaMerCm = 'java -jar %s %s %s' % (jarPath, publicXml, apkRfilePath)
- printlog("javaMerCm:%s" % javaMerCm)
- os.system(javaMerCm)
- pass
- def replace_manifest_allow_backup(am_path):
- lines = open(am_path).readlines()
- fp = open(am_path, "w")
- isReplaced = False
- for l in lines:
- if isReplaced == False and l.find("android:allowBackup=") >= 0:
- l = re.sub("android:allowBackup=\"true\"", "android:allowBackup=\"false\"", l)
- fp.write(l)
- fp.close()
- pass
- def replace_xml_value(xml_path, name, value):
- tree = ET.parse(xml_path)
- if tree is None:
- return
- for child in list(tree.getroot()):
- if child.attrib["name"] == name:
- child.text = value
- tree.write(xml_path, "utf-8", xml_declaration=True)
- pass
- def replace_game_launch_activity_attribute_to_default(splash_activity, manifest_path):
- ET.register_namespace('android', androidNS)
- tree = ET.parse(manifest_path)
- game_activity = ""
- activitys = tree.getroot().find("application").findall("activity")
- for activity in activitys:
- filters = activity.findall('intent-filter')
- for filter in filters:
- categorys = filter.findall('category')
- actions = filter.findall('action')
- for category in categorys:
- category_name = category.attrib[namespace + "name"]
- if category_name == "android.intent.category.LAUNCHER":
- action_name = activity.attrib[namespace + "name"]
- if action_name != splash_activity:
- game_activity = activity.attrib[namespace + "name"]
- printlog("delete :%s" % category_name)
- category.attrib[namespace + "name"] = "android.intent.category.DEFAULT"
- printlog("LAUNCHER replace DEFAULT :%s" % category.attrib[namespace + "name"])
- for action in actions:
- action_name = action.attrib[namespace + "name"]
- if action_name == "android.intent.action.MAIN":
- printlog("delete :%s" % action_name)
- filter.remove(action)
- tree.write(manifest_path, "UTF-8", xml_declaration=True, method='xml')
- return game_activity
- def replace_json_value(path, root, key, value):
- if root == "":
- with open(path, 'r') as fp:
- jsonData = json.load(fp)
- jsonData[key] = value
- newJsonData = jsonData
- fp.close()
- with open(path, 'w') as fp:
- json.dump(newJsonData, fp)
- fp.close()
- else:
- with open(path, 'r') as fp:
- jsonData = json.load(fp)
- jsonData[root][key] = value
- newJsonData = jsonData
- fp.close()
- with open(path, 'w') as fp:
- json.dump(newJsonData, fp)
- fp.close()
- pass
- if __name__ == "__main__":
- # replaceAM_Meta_data("/sdk/develop/921sdk_cut/sdk_config/P0000001/anzhi/P0000004/AndroidManifest.xml", "QHOPENSDK_APPKEY", "20151219")
- # replaceLP_AppVersion(sys.argv[1], sys.argv[2])
- # replaceAssets_Param("/var/root/shortcuts/921sdkcut/tools/param.cnf", "SECRET_KEY", "20151226")
- # special_replace("wdj", "/sdk/develop/tools/outputs/mxd/package/0.01.150608/360/test", "/", "APPKEY_ID", "20151228")
- pass
|