| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- #!/usr/bin/python
- # -*- coding: utf-8 -*-
- from logging import debug, root
- from struct import pack
- from Common import Setting, Debug, PathConvert, StringFormat
- Setting.SetDefaultencodingUTF8()
- import zipfile, sys, os, traceback
- import shutil
- import platform
- import subprocess
- import ConfigParser
- CUR_PLATFORM_NAME = platform.system()
- CUR_PATH = os.path.abspath(sys.path[0])
- APK_TOOLS_PATH = os.path.abspath(CUR_PATH + '/../APKTools')
- APK_TOOL_JAR_PATH = os.path.abspath(APK_TOOLS_PATH + '/apktool.jar')
- APK_SIGNER_JAR_PATH = os.path.abspath(APK_TOOLS_PATH + '/apksigner.jar')
- if CUR_PLATFORM_NAME == 'Windows':
- ZIP_ALIGN_PATH = os.path.abspath(APK_TOOLS_PATH + '/zipalign.exe')
- elif CUR_PLATFORM_NAME == 'Linux':
- ZIP_ALIGN_PATH = os.path.abspath(APK_TOOLS_PATH + '/zipalign.exe')
- elif CUR_PLATFORM_NAME == 'Darwin':
- ZIP_ALIGN_PATH = os.path.abspath(APK_TOOLS_PATH + '/zipalign_mac')
- else:
- ZIP_ALIGN_PATH = os.path.abspath(APK_TOOLS_PATH + '/zipalign.exe')
- VALID_CMD_ARGV = {"-help", "-checkSign", "-checkSignVer",
- "-sign", "-signWithIni", "-outPath", "-inPath", "-iniPath",
- "-keyStorePath", "-keyAlias", "-keyStorePwd", "-keyAliasPwd",
- "-keySignVer"}
- def PrintHelp():
- Debug.Log('')
- Debug.Log('')
- Debug.Log('命令参数说明')
- Debug.Log('')
- Debug.Log('-help 查看帮助')
- Debug.Log('')
- Debug.Log('')
- Debug.Log('-checkSign 查看签名')
- Debug.Log(' -inPath 原始apk路径')
- Debug.Log('')
- Debug.Log('')
- Debug.Log('-checkSignVer 查看签名版本')
- Debug.Log(' -inPath 原始apk路径')
- Debug.Log('')
- Debug.Log('')
- Debug.Log('-signWithIni 使用证书配置来签名')
- Debug.Log(' -inPath 原始apk路径')
- Debug.Log(' -outPath 目标apk路径')
- Debug.Log(' -iniPath 签名配置')
- Debug.Log('')
- Debug.Log('')
- Debug.Log('-sign 重新签名')
- Debug.Log(' -inPath 原始apk路径')
- Debug.Log(' -outPath 目标apk路径')
- Debug.Log(' -keyStorePath 签名证书路径')
- Debug.Log(' -keyAlias 签名证书alias')
- Debug.Log(' -keyStorePwd 签名证书密码')
- Debug.Log(' -keyAliasPwd 签名证书alias密码')
- Debug.Log(' -keySignVer (可选)签名版本, 默认为v1')
- Debug.Log('')
- Debug.Log('')
- Debug.Log('')
- def ValidJava():
- try:
- cmds = ["java", "-version"]
- sp = subprocess.Popen(cmds, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- contents = sp.communicate()
- sp.wait()
- version = None
- for content in contents:
- lines = content.split("\n")
- for i in range(len(lines)):
- line = lines[i].strip()
- if line.startswith("java version "):
- version = line.replace("java version ", "")
- version = version.replace("\"", "")
- if not version:
- Debug.LogError("无法检测JDK版本 ")
- return False
- else:
- if version.startswith("1.8"):
- return True
- else:
- Debug.LogError("JDK版本不符,需要使用1.8版本 当前版本 " + version)
- return False
- except Exception as exc:
- Debug.LogError(exc)
- Debug.Log("")
- Debug.LogError("无法找到有效JDK, 请检查环境 !!! ")
- return False
- return True
- def ToolsChmodEXE():
- if CUR_PLATFORM_NAME != 'Linux' or CUR_PLATFORM_NAME != 'Darwin':
- return
- Debug.LogSuccess("赋予%s目录可执行权限开始" % APK_TOOLS_PATH)
- import stat
- for root, dirs, files in os.walk(APK_TOOLS_PATH):
- for file in files:
- os.chmod(file, os.stat(file).st_mode | stat.S_IEXEC)
- Debug.LogSuccess("赋予%s目录可执行权限成功" % APK_TOOLS_PATH)
- def ExecCheckSign(inputPath):
- if not os.path.exists(StringFormat.FormatStringPlatform(inputPath)):
- Debug.LogError(inputPath + "不存在")
- Debug.Log("")
- return False
- try:
- cmds = ["keytool", "-list",
- "-printcert",
- "-jarfile",
- StringFormat.FormatStringPlatform(inputPath)]
- res = subprocess.check_output(cmds, shell=False)
- res = StringFormat.FormatStdinString(res)
- Debug.Log(res)
- except Exception as exc:
- Debug.LogError(exc)
- Debug.Log("")
- return False
- return True
- def ExecCheckSignVer(inputPath):
- if not os.path.exists(StringFormat.FormatStringPlatform(inputPath)):
- Debug.LogError(inputPath + "不存在")
- Debug.Log("")
- return False
- try:
- cmds = ["java", "-jar", APK_SIGNER_JAR_PATH,
- "verify",
- "--verbose",
- StringFormat.FormatStringPlatform(inputPath)]
- res = subprocess.check_output(cmds, shell=False)
- res = StringFormat.FormatStdinString(res)
- Debug.Log(res)
- except Exception as exc:
- Debug.LogError(exc)
- Debug.Log("")
- return False
- return True
- def ExecSignWithIni(inputPath, outPath, iniPath):
- if not os.path.exists(StringFormat.FormatStringPlatform(iniPath)):
- Debug.LogError(iniPath + "不存在")
- Debug.Log("")
- return
- config = ConfigParser.ConfigParser()
- config.read(StringFormat.FormatStringPlatform(iniPath))
- keyAliasD = config.get('signinfodefault', 'keyAlias')
- keyStorePwdD = config.get('signinfodefault', 'keyStorePwd')
- keyAliasPwdD = config.get('signinfodefault', 'keyAliasPwd')
- keySignVerD = config.get('signinfodefault', 'keySignVer')
- keyStorePathD = config.get('signinfodefault', 'keyStorePath')
- if not os.path.exists(StringFormat.FormatStringPlatform(keyStorePathD)):
- if '../' in keyStorePathD:
- keyStorePathDTemp = os.path.abspath(os.path.dirname(iniPath) + "/" + keyStorePathD)
- if os.path.exists(StringFormat.FormatStringPlatform(keyStorePathDTemp)):
- keyStorePathD = keyStorePathDTemp
- ExecSign(inputPath, outPath,
- keyStorePathD, keyAliasD, keyStorePwdD, keyAliasPwdD,
- keySignVerD)
- def ExecSign(inputPath, outPath,
- keyStorePath, keyAlias, keyStorePwd, keyAliasPwd,
- keySignVer):
- if not os.path.exists(StringFormat.FormatStringPlatform(inputPath)):
- Debug.LogError(inputPath + "不存在")
- Debug.Log("")
- return False
- if not outPath or outPath == "":
- Debug.LogError(outPath + "目标目录无效")
- Debug.Log("")
- return False
- if not os.path.exists(StringFormat.FormatStringPlatform(keyStorePath)):
- Debug.LogError(keyStorePath + "不存在")
- Debug.Log("")
- return False
- outTempPath = outPath + "_temp.apk"
- ExecSignInternal(inputPath, outPath,
- keyStorePath, keyAlias, keyStorePwd, keyAliasPwd,
- keySignVer, outTempPath)
- if os.path.exists(StringFormat.FormatStringPlatform(outTempPath)):
- os.remove(StringFormat.FormatStringPlatform(outTempPath))
- if os.path.exists(StringFormat.FormatStringPlatform(outPath + ".idsig")):
- os.remove(StringFormat.FormatStringPlatform(outPath + ".idsig"))
- def ExecSignInternal(inputPath, outPath,
- keyStorePath, keyAlias, keyStorePwd, keyAliasPwd,
- keySignVer, outTempPath):
- if keySignVer:
- if isinstance(keySignVer, str):
- if len(keySignVer) > 1:
- if (keySignVer[:1] == 'v' or keySignVer == 'V'):
- keySignVer = keySignVer[1:]
- keySignVer = int(keySignVer)
- else:
- keySignVer = 1
- try:
- #删除当前包的证书
- with zipfile.ZipFile(StringFormat.FormatStringPlatform(inputPath)) as inFile:
- with zipfile.ZipFile(StringFormat.FormatStringPlatform(outTempPath), 'w') as outFile:
- for data in inFile.infolist():
- if not data.filename.startswith("META-INF"):
- outFile.writestr(data, inFile.read(data.filename))
- # zip对齐apk
- Debug.Log("zip对齐apk")
- Debug.Log("")
- cmds = [StringFormat.FormatStringPlatform(ZIP_ALIGN_PATH),
- "-p", "-f", "4",
- StringFormat.FormatStringPlatform(outTempPath),
- StringFormat.FormatStringPlatform(outPath)]
- res = subprocess.Popen(cmds, shell=False, stdout=subprocess.PIPE)
- res.wait()
- if res.returncode != 0:
- Debug.LogError("无法zip对齐APK " + outPath)
- return False
-
- # 签名apk
- Debug.Log("签名apk")
- Debug.Log("")
- cmds = ["java", "-jar", StringFormat.FormatStringPlatform(APK_SIGNER_JAR_PATH), "sign",
- "--ks", StringFormat.FormatStringPlatform(keyStorePath), "--ks-key-alias", keyAlias,
- "--ks-pass", "pass:" + keyStorePwd, "--key-pass", "pass:" + keyAliasPwd]
- cmds.append('--v4-signing-enabled')
- if keySignVer >= 4:
- cmds.append('true')
- else:
- cmds.append('false')
- cmds.append('--v3-signing-enabled')
- if keySignVer >= 3:
- cmds.append('true')
- else:
- cmds.append('false')
- cmds.append('--v2-signing-enabled')
- if keySignVer >= 2:
- cmds.append('true')
- else:
- cmds.append('false')
- cmds.append('--v1-signing-enabled')
- cmds.append('true')
- cmds.append(StringFormat.FormatStringPlatform(outPath))
- res = subprocess.Popen(cmds, shell=False, stdout=subprocess.PIPE)
- res.wait()
- if res.returncode != 0:
- Debug.LogError("无法签名APK " + outPath)
- return False
- Debug.LogSuccess("执行成功" + inputPath + " -> " + outPath)
- Debug.Log("")
- Debug.Log("")
- return True
- except Exception as exc:
- Debug.LogError(exc)
- Debug.Log("")
- return False
- def CMDArgvIsNull(dic, keyName):
- if (not (keyName in dic)):
- PrintHelp()
- Debug.Log('')
- Debug.Log('')
- Debug.LogError(keyName + ' 不能为空')
- Debug.Log('')
- Debug.Log('')
- return True
- return False
- def Main():
- args = sys.argv[1:]
- dic = {}
- num = len(args)
- for i in range(num):
- arg = StringFormat.FormatStdinString(args[i])
- if arg.startswith('-'):
- if not arg in VALID_CMD_ARGV:
- Debug.LogError(arg + " 不是有效的参数")
- PrintHelp()
- return
- if i + 1 >= num:
- Debug.LogSuccess(arg)
- dic[arg] = ''
- else:
- nextArg = StringFormat.FormatStdinString(args[i + 1])
- if nextArg.startswith('-'):
- Debug.LogSuccess(arg)
- dic[arg] = ''
- else:
- Debug.LogSuccess(arg + " " + nextArg)
- dic[arg] = nextArg
- if len(dic) <= 0:
- PrintHelp()
- return
- if ('-help' in dic):
- PrintHelp()
- return
- if not ValidJava():
- return
- ToolsChmodEXE()
- if (CMDArgvIsNull(dic, '-inPath')):
- return
- if ('-checkSign' in dic):
- ExecCheckSign(dic['-inPath'])
- return
- if ('-checkSignVer' in dic):
- ExecCheckSignVer(dic['-inPath'])
- return
- if (CMDArgvIsNull(dic, '-outPath')):
- return
- if ('-signWithIni' in dic):
- if (CMDArgvIsNull(dic, '-iniPath')):
- return
- ExecSignWithIni(dic['-inPath'], dic['-outPath'], dic['-iniPath'])
- return
- return
- if (CMDArgvIsNull(dic, '-keyStorePath')):
- return
- if (CMDArgvIsNull(dic, '-keyAlias')):
- return
- if (CMDArgvIsNull(dic, '-keyStorePwd')):
- return
- if (CMDArgvIsNull(dic, '-keyAliasPwd')):
- return
- Debug.Log('')
- Debug.Log('')
- keySignVer = None
- if ('-keySignVer' in dic):
- keySignVer = dic['-keySignVer']
- ExecSign(dic['-inPath'], dic['-outPath'],
- dic['-keyStorePath'], dic['-keyAlias'], dic['-keyStorePwd'], dic['-keyAliasPwd'],
- keySignVer)
-
- if __name__ == '__main__':
- try:
- Main()
- except Exception as e:
- Debug.LogError(e)
- Debug.LogError(traceback.format_exc(), True)
- sys.exit(1)
|