#!/usr/bin/python # -*- coding: utf-8 -*- import platform import os import shutil import sys import getopt import json import subprocess import traceback import re from Common import Setting, Debug, PathConvert, StringFormat Setting.SetDefaultencodingUTF8() def StrAlign(s, n, c=' '): if n == 0: return s slen = len(s) re = s if isinstance(s, str): placeholder = ' ' else: placeholder =u' ' while slen < n: re += placeholder slen += 1 return re UNITY_VERSION_STR = "Unity 2018.4.1f1" UNITY_VERSION = "Unity2018.4.1f1" CUR_PATH = os.path.abspath(sys.path[0]) PROJECT_PATH = os.path.abspath(CUR_PATH + '/../../..') BUILD_LOG_PATH = os.path.abspath(CUR_PATH + '/../logs') BUILD_CONFIG_PATH = os.path.abspath( CUR_PATH + '/../../BuildDependenceResource/PackConfig.json') FAIR_GUARD_PATH = os.path.abspath(CUR_PATH + '/../FairGuard') FAIR_GUARD_ANDROID_PATH = os.path.abspath(FAIR_GUARD_PATH + '/Android') FAIR_GUARD_ANDROID_JAR_PATH = os.path.abspath(FAIR_GUARD_ANDROID_PATH + '/FairGuard.jar') FAIR_GUARD_ANDROID_CONFIG_PATH = os.path.abspath( FAIR_GUARD_ANDROID_PATH + '/config.ini') FAIR_GUARD_ANDROID_MODULES_PATH = os.path.abspath(FAIR_GUARD_ANDROID_PATH + '/modules') FAIR_GUARD_iOS_PATH = os.path.abspath(FAIR_GUARD_PATH + '/iOS') FAIR_GUARD_iOS_BUILD_PATH = os.path.abspath(FAIR_GUARD_iOS_PATH + '/fairguardbuild') CUR_PLATFORM_NAME = platform.system() if CUR_PLATFORM_NAME == 'Windows': from _winreg import * VALID_CMD_ARGV = {"-help", "-unitypath", "-config", "-buildAB", "-buildApp", "-nogit", "-clrerr" } PlatformMap = { 'Android' : ['androids', 'weiDuanAndroids'], 'iOS' : ['iOSs'], 'PC' : ['pCs'] } ConfigPlatformMap = {} for key in PlatformMap: for tag in PlatformMap[key]: ConfigPlatformMap[tag] = key UnityLogLevelTagMap = { 'debug' : ['[PACK_RUN START]', '[PACK_RUN END]'], 'waring' : ['[PACK_RUN WARING START]', '[PACK_RUN WARING END]'], 'error' : ['[PACK_RUN ERROR START]', '[PACK_RUN ERROR END]'], 'exception' : ['[PACK_RUN EXCEPTION START]', '[PACK_RUN EXCEPTION END]'] } UnityLogLevelMethod = { 'debug' : Debug.Log, 'waring' : Debug.LogWaring, 'error' : Debug.LogError, 'exception' : Debug.LogException } UnityLogStartMap = {} UnityLogEndMap = {} UnityTagLogLevelMap = {} for key in UnityLogLevelTagMap: tags = UnityLogLevelTagMap[key] UnityLogStartMap[tags[0]] = key UnityLogEndMap[tags[1]] = key UnityTagLogLevelMap[tags[0]] = key UnityTagLogLevelMap[tags[1]] = key UNITY_TAG_ResOutPath = "[ResOutPath]" UNITY_TAG_AppOutPath = "[AppOutPath]" UNITY_TAG_ICON_PATH = "[ICON_PATH]" TAG_KEYSTORE_PATH = "[KEYSTORE_PATH]" TAG_OTHER_BUILD_PROJECT_PATH = "[OTHER_BUILD_PROJECT_PATH]" UNITY_TAG_ANDROID_JAVA_ROOT = "[ANDROID_JAVA_ROOT]" UNITY_TAG_ANDROID_SDK_ROOT = "[ANDROID_SDK_ROOT]" UNITY_TAG_ANDROID_NDK_ROOT = "[ANDROID_NDK_ROOT]" def PrintHelp(): Debug.Log('') Debug.Log('') Debug.Log('命令参数说明') Debug.Log('-help 查看帮助') Debug.Log('-unitypath Unity安装文件路径') Debug.Log('-config 查看可编译的平台') Debug.Log(' 参数为空,则显示可编译目标平台') Debug.Log(' 参数不为空,如参数为Android 则显示android渠道的编译目标') Debug.Log('-nogit 关闭执行Git, 默认会执行git') Debug.Log(' 主要执行命令 git checkout . & git pull') Debug.Log('') Debug.Log('') Debug.Log('编译命令说明') Debug.Log(' -buildApp 编译并生成App') Debug.Log(' 编译多个时请使用英文符号\":\"隔开') Debug.Log(' -clrerr 解决项目编译错误') 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 ValidUnityPath(path): if path: if os.path.exists(path): with open(path, 'rb') as file_obj: content = file_obj.read() if UNITY_VERSION_STR in content: return True Debug.LogError( path + " 不是" + UNITY_VERSION_STR + "版本,请使用-unitypath来设置路径") return False else: Debug.LogError( path + " Unity安装路径是不存在的,请使用-unitypath来设置路径") return False Debug.LogError("Unity安装路径是不存在的,请使用-unitypath来设置路径") return False def ExecGit(): try: os.chdir(PROJECT_PATH) cmds = ["git", "checkout", "."] res = subprocess.check_output(cmds, shell=False) res = StringFormat.FormatStdinString(res) Debug.Log(res) cmds = ["git", "pull"] res = subprocess.check_output(cmds, shell=False) res = StringFormat.FormatStdinString(res) Debug.Log(res) except Exception as exc: Debug.LogError(exc) Debug.Log("") Debug.LogError("git 执行失败, 请检查环境 !!! ") return False return True def GetConfigs(): with open(BUILD_CONFIG_PATH) as file_obj: content = '\n'.join(file_obj.readlines()) packPlatforms = json.loads(content) return packPlatforms def GetPackInfo(packId): packPlatforms = GetConfigs() for key in ConfigPlatformMap: if not packPlatforms.has_key(key): continue datas = packPlatforms[key] for idx in range(len(datas)): data = datas[idx] if data["channelUniqueId"] == packId: return data, key, ConfigPlatformMap[key] return None, None def GetPackName(packInfo): return packInfo['channelName'] + "/" + packInfo['appName'] + "/" + packInfo['distributeName'] def GetVersionCode(versionCode): return (versionCode['major'] * 1000000 + versionCode['minor'] * 10000 + versionCode['release'] * 100 + versionCode['patch']) def GetVersionName(versionCode): return str(versionCode['major']) + "." + str(versionCode['minor']) + "." + str(versionCode['release']) + "." + str(versionCode['patch']) def ChannelUniqueIdSort(elem): return int(elem['data']['channelUniqueId']) def PrintConfig(platform): packPlatforms = GetConfigs() if not platform or platform == '': Debug.Log("") Debug.Log("") Debug.Log("可编译所有平台") Debug.Log(" all") Debug.Log("") Debug.Log("可编译平台") for key in PlatformMap: Debug.Log(" " + key) Debug.Log("") Debug.LogWaring("上述命令都忽略大小写", True) Debug.Log("") Debug.Log("") else: platform = platform.lower() datas = [] for key in PlatformMap: if platform == key.lower(): ls = PlatformMap[key] for i in range(len(ls)): cfgDatas = packPlatforms[ls[i]] for j in range(len(cfgDatas)): datas.append({'data' : cfgDatas[j], 'name' : key}) if not datas or len(datas) <= 0: if platform == 'all': datas = [] for key in ConfigPlatformMap: cfgDatas = packPlatforms[key] for j in range(len(cfgDatas)): datas.append({'data' : cfgDatas[j], 'name' : ConfigPlatformMap[key]}) # datas.extend(packPlatforms[key]) else: PrintConfig(None) return Debug.Log("") Debug.Log("") lastId = None datas.sort(key=ChannelUniqueIdSort) for i in range(len(datas)): data = datas[i]['data'] curId = int(data['channelUniqueId']) if lastId and abs(curId - lastId) > 1: Debug.Log('') lastId = curId log = '{}\t{}\t{}\t{}'.format(StrAlign(data['channelUniqueId'], 8), StrAlign("(" + GetVersionName(data['gameVersionCode']) + "),(" + GetVersionName(data['resVersionCode']) + ")", 30), StrAlign(datas[i]['name'], 8), GetPackName(data)) Debug.Log(log) Debug.Log("") Debug.Log("") def GetUnityPath(path): if path: return path if CUR_PLATFORM_NAME == 'Windows': key = OpenKey(HKEY_CLASSES_ROOT, 'com.unity3d.kharma\DefaultIcon') if key: value, type = QueryValueEx(key, '') return value elif CUR_PLATFORM_NAME == 'Darwin': return "//Applications/" + UNITY_VERSION + "/"+ UNITY_VERSION + ".app/Contents/MacOS/Unity" return None def ParseUnityLog(logPath): if not os.path.exists(logPath): raise Exception(logPath + "不存在") logTagLines = {} params = {} with open(logPath) as file_obj: lines = file_obj.readlines() curLogTag = None logTags = [] validLines = {} for i in range(len(lines)): line = lines[i].strip() if UnityLogEndMap.has_key(line): if not curLogTag or curLogTag != UnityLogEndMap[line]: raise Exception(logPath + '解析错误') if len(validLines) > 0: if logTagLines.has_key(curLogTag): loglines = logTagLines[curLogTag] else: loglines = {} logTagLines[curLogTag] = loglines loglines.update(validLines) curLogTag = None logTags.pop() if curLogTag is not None: validLines[i] = line if line.startswith('['): idx = line.find(']') if idx >= 0: key = line[0:idx+1] value = line[idx+1:len(line)] if key and value: params[key] = value if UnityLogStartMap.has_key(line): curLogTag = UnityLogStartMap[line] logTags.append(curLogTag) return logTagLines, params def PrintUnityLog(logPath, tags = ['debug', 'waring', 'error', 'exception']): try: logTagLines,_ = ParseUnityLog(logPath) lineIds = [] if tags: for i in range(len(tags)): if logTagLines.has_key(tags[i]): keys = logTagLines[tags[i]].keys() lineIds.extend(keys) lineIds.sort() for i in range(len(lineIds)): for j in range(len(tags)): tag = tags[j] if logTagLines.has_key(tag) and logTagLines[tag].has_key(lineIds[i]) : UnityLogLevelMethod[tag](logTagLines[tag][lineIds[i]], True) break except Exception, exc: Debug.LogError(exc) def DeleteUnityLog(logPath): if os.path.exists(logPath): with open(logPath, 'w') as file_obj: file_obj.write("") def UnityPack(unityPath, packId, logPath): Debug.LogSuccess("Unity3d打包开始") if not os.path.exists(logPath): if not os.path.exists(os.path.dirname(logPath)): os.mkdir(os.path.dirname(logPath)) cmds = [unityPath, "-quit", "-batchmode", "-projectPath", PROJECT_PATH, "-logFile", logPath, "-executeMethod", "Pack.PackRun.CommandLineBuildApp"] # if method == 1: # cmds.append("-buildAB") # cmds.append(packId) # elif method == 2: cmds.append("-buildApp") cmds.append(packId) # else: # cmds.append("-h") try: res = subprocess.check_output(cmds, shell=False) except Exception as exc: PrintUnityLog(logPath) Debug.LogError(exc) Debug.Log("") Debug.LogError("Unity3d打包失败") return False Debug.LogSuccess("Unity3d打包成功") return True def FairGuardiOS(appPath): if CUR_PLATFORM_NAME == 'Darwin': Debug.LogError("当前不在Mac OS系统环境中,无法加固") return False if not appPath or appPath == "" or not os.path.exists(StringFormat.FormatStringPlatform(appPath)): Debug.LogError(appPath + " 无法找到上次打包的App, FairGuard加固失败") return False if not os.path.exists(FAIR_GUARD_iOS_PATH): Debug.LogError(FAIR_GUARD_iOS_PATH + " 无法找到加固工具, FairGuard加固失败") return False os.chdir(FAIR_GUARD_iOS_PATH) Debug.LogSuccess("FairGuard加固开始 赋予fairguardbuild可执行权限") import stat file = FAIR_GUARD_iOS_BUILD_PATH os.chmod(file, os.stat(file).st_mode | stat.S_IEXEC) Debug.LogSuccess("FairGuard加固完成 赋予fairguardbuild可执行权限") if not os.path.exists(FAIR_GUARD_iOS_BUILD_PATH): Debug.LogError(FAIR_GUARD_iOS_BUILD_PATH + " 无法找到加固工具, FairGuard加固失败") return False Debug.LogSuccess("FairGuard加固开始 " + appPath) try: cmds = ["/base/sh", FAIR_GUARD_iOS_BUILD_PATH, "-p", StringFormat.FormatStringPlatform(appPath) + "/Unity-iPhone.xcodeproj", "-W"] res = subprocess.check_output(cmds, shell=False, stderr=STDOUT) res = StringFormat.FormatStdinString(res) success = False Debug.Log(res) # lines = res.split("\n") # for i in range(len(lines)): # line = lines[i].strip() # if line.endswith("game protect suceess!"): # success = True if not success: Debug.Log(res) Debug.LogError("") Debug.LogError("FairGuard加固失败 " + appPath) return False except Exception as exc: Debug.LogError(exc) Debug.Log("") Debug.LogError("FairGuard加固失败 " + appPath) return False Debug.LogSuccess("FairGuard加固完成 " + appPath) return True def FairGuardAndroid(appPath): if not appPath or appPath == "" or not os.path.exists(StringFormat.FormatStringPlatform(appPath)): Debug.LogError(appPath + " 无法找到上次打包的App, FairGuard加固失败") return False if not os.path.exists(FAIR_GUARD_ANDROID_MODULES_PATH): Debug.LogError(FAIR_GUARD_ANDROID_MODULES_PATH + " 无法找到加固工具, FairGuard加固失败") return False os.chdir(FAIR_GUARD_ANDROID_MODULES_PATH) if CUR_PLATFORM_NAME == 'Linux' or CUR_PLATFORM_NAME == 'Darwin': Debug.LogSuccess("FairGuard加固开始 赋予modules目录可执行权限") import stat for root, dirs, files in os.walk("."): for file in files: os.chmod(file, os.stat(file).st_mode | stat.S_IEXEC) Debug.LogSuccess("FairGuard加固完成 赋予modules目录可执行权限") if not os.path.exists(FAIR_GUARD_ANDROID_PATH): Debug.LogError(FAIR_GUARD_ANDROID_PATH + " 无法找到加固工具, FairGuard加固失败") return False os.chdir(FAIR_GUARD_ANDROID_PATH) if not os.path.exists(FAIR_GUARD_ANDROID_CONFIG_PATH): Debug.LogError(FAIR_GUARD_ANDROID_CONFIG_PATH + " 无法找到加固用的证书, FairGuard加固失败") return False certPath = None if not os.path.exists(FAIR_GUARD_ANDROID_JAR_PATH): Debug.LogError(FAIR_GUARD_ANDROID_JAR_PATH + " 无法找到加固工具, FairGuard加固失败") return False with open(FAIR_GUARD_ANDROID_CONFIG_PATH) as file: lines = file.readlines() for i in range(len(lines)): line = lines[i].strip() if line.startswith("keystore-path="): certPath = line.replace("keystore-path=", "") if not certPath or not os.path.exists(os.path.abspath(certPath)): Debug.LogError(FAIR_GUARD_ANDROID_CONFIG_PATH + " 无法找到加固用的证书, FairGuard加固失败") return False Debug.LogSuccess("FairGuard加固开始 " + appPath) try: cmds = ["java", "-jar", FAIR_GUARD_ANDROID_JAR_PATH, "-autoconfig", "-signapk", "-inputfile", StringFormat.FormatStringPlatform(appPath)] res = subprocess.check_output(cmds, shell=False, stderr=STDOUT) res = StringFormat.FormatStdinString(res) success = False lines = res.split("\n") for i in range(len(lines)): line = lines[i].strip() if line.endswith("game protect suceess!"): success = True if not success: Debug.Log(res) Debug.LogError("") Debug.LogError("FairGuard加固失败 " + appPath) return False except Exception as exc: Debug.LogError(exc) Debug.Log("") Debug.LogError("FairGuard加固失败 " + appPath) return False Debug.LogSuccess("FairGuard加固完成 " + appPath) return True def ZipCompress(appPath): appPath = os.path.abspath(appPath + "/../") if not appPath or appPath == "" or not os.path.exists(StringFormat.FormatStringPlatform(appPath)): Debug.LogError(appPath + " 无法找到上次打包的App, Zip压缩失败") return False fileName = os.path.basename(appPath) dirPath = os.path.dirname(appPath) os.chdir(dirPath) if os.path.exists(fileName + ".zip"): os.remove(fileName + ".zip") Debug.LogSuccess("Zip压缩开始 " + appPath) try: cmds = ["zip", "-q", "-r", StringFormat.FormatStringPlatform(fileName + ".zip"), StringFormat.FormatStringPlatform(fileName)] res = subprocess.check_output(cmds, shell=False) except Exception as exc: Debug.LogError(exc) Debug.Log("") Debug.LogError("Zip压缩失败 " + appPath) return False Debug.LogSuccess("Zip压缩完成 " + appPath) return True def SettingAndroidStudio(packInfo, params): if not packInfo: Debug.LogError("设置AndroidStudio时 packInfo 为空") return False if not params: Debug.LogError("设置AndroidStudio时 params 为空") return False if not params.has_key(UNITY_TAG_AppOutPath): Debug.LogError("设置AndroidStudio时 params 不能找到 " + UNITY_TAG_AppOutPath) return if not params.has_key(TAG_OTHER_BUILD_PROJECT_PATH): Debug.LogError("设置AndroidStudio时 params 不能找到 " + TAG_OTHER_BUILD_PROJECT_PATH) return False if not params.has_key(UNITY_TAG_ANDROID_SDK_ROOT): Debug.LogError("设置AndroidStudio时 params 不能找到 " + UNITY_TAG_ANDROID_SDK_ROOT) return False if not params.has_key(UNITY_TAG_ANDROID_NDK_ROOT): Debug.LogError("设置AndroidStudio时 params 不能找到 " + UNITY_TAG_ANDROID_NDK_ROOT) return False if not params.has_key(TAG_KEYSTORE_PATH): Debug.LogError("设置AndroidStudio时 params 不能找到 " + TAG_KEYSTORE_PATH) return False if not params.has_key(UNITY_TAG_ICON_PATH): Debug.LogError("设置AndroidStudio时 params 不能找到 " + UNITY_TAG_ICON_PATH) return False appPath = params[UNITY_TAG_AppOutPath].replace('\\', '/') androidStudioPath = params[TAG_OTHER_BUILD_PROJECT_PATH].replace('\\', '/') sdkPath = params[UNITY_TAG_ANDROID_SDK_ROOT].replace('\\', '/') ndkPath = params[UNITY_TAG_ANDROID_NDK_ROOT].replace('\\', '/') keyStorePath = params[TAG_KEYSTORE_PATH].replace('\\', '/') iconPath = params[UNITY_TAG_ICON_PATH].replace('\\', '/') if not os.path.exists(StringFormat.FormatStringPlatform(androidStudioPath)): Debug.LogError(androidStudioPath + " 无法找到") return False if not os.path.exists(StringFormat.FormatStringPlatform(sdkPath)): Debug.LogError(sdkPath + " 无法找到") return False if not os.path.exists(StringFormat.FormatStringPlatform(ndkPath)): Debug.LogError(ndkPath + " 无法找到") return False if not os.path.exists(StringFormat.FormatStringPlatform(keyStorePath)): Debug.LogError(keyStorePath + " 无法找到") return False if not os.path.exists(StringFormat.FormatStringPlatform(iconPath)): Debug.LogError(iconPath + " 无法找到") return False Debug.LogSuccess("设置AndroidStudio 开始 " + androidStudioPath) localpropPath = androidStudioPath + "/" + "local.properties" paramMap = {"sdk.dir": sdkPath, "ndk.dir": ndkPath} if not ChangeFileLineContent(localpropPath, localpropPath, paramMap): return False lebianlocalpropPath = androidStudioPath + "/lebian/" + "local.properties" if not ChangeFileLineContent(lebianlocalpropPath, lebianlocalpropPath, paramMap): return False build_custPath = androidStudioPath + "/" + "build_cust.gradle" idx = appPath.rfind('/') apkDir = appPath[:idx] apkName = appPath[idx+1:] paramMap = { "appName": '\'' + packInfo['appName'] + '\'', "applicationId": '\'' + packInfo['bundleId'] + '\'', "versionCode": str(GetVersionCode(packInfo['gameVersionCode'])), "versionName": '\'' + GetVersionName(packInfo['gameVersionCode']) + '\'', "keyFile": '\'' + keyStorePath + '\'', "keyAlias": '\'' + packInfo['keyaliasName'] + '\'', "keyPassword": '\'' + packInfo['keyaliasPass'] + '\'', "storePassword": '\'' + packInfo['keystorePass'] + '\'', "apkDir": '\'' + apkDir + '\'', "apkName": '\'' + apkName + '\'' } if not ChangeFileLineContent(build_custPath, build_custPath, paramMap): return False lebian_custPath = androidStudioPath + "/lebian/" + "lebian_cust.gradle" paramMap = { "meta_MainChId": '\'' + packInfo['leBian_MainChId'] + '\'', "meta_ClientChId": '\'' + packInfo['leBian_ClientChId'] + '\'', "meta_LEBIAN_SECID": '\'' + packInfo['leBian_SECID'] + '\'', "meta_LBCloudId": '\'' + packInfo['leBian_LBCloudID'] + '\'' } if not ChangeFileLineContent(lebian_custPath, lebian_custPath, paramMap): return False appNameXmlPath = androidStudioPath + '/app/src/main/res/values/strings.xml' paramMap = { "(.*)": "" + packInfo['appName'] + "" } if not ChangeFileMatchContent(appNameXmlPath, appNameXmlPath, paramMap): return False iconCopyPaths = { "/app/src/main/res/mipmap-hdpi/app_icon.png" : "/72.png", "/app/src/main/res/mipmap-hdpi/app_icon_round.png" : "/72.png", "/app/src/main/res/mipmap-mdpi/app_icon.png" : "/48.png", "/app/src/main/res/mipmap-mdpi/app_icon_round.png" : "/48.png", "/app/src/main/res/mipmap-xhdpi/app_icon.png" : "/96.png", "/app/src/main/res/mipmap-xhdpi/app_icon_round.png" : "/96.png", "/app/src/main/res/mipmap-xxhdpi/app_icon.png" : "/144.png", "/app/src/main/res/mipmap-xxhdpi/app_icon_round.png" : "/144.png", "/app/src/main/res/mipmap-xxxhdpi/app_icon.png" : "/192.png", "/app/src/main/res/mipmap-xxxhdpi/app_icon_round.png" : "/192.png", } for k in iconCopyPaths: if not CopyFile(iconPath + iconCopyPaths[k], androidStudioPath + k): return False ls = GetFilesByFileName(androidStudioPath, ['WXEntryActivity.java']) if ls and len(ls) > 0: srcPath = ls[0] dirPath = GetWXEntryActivityDirPath(srcPath) if not dirPath: Debug.LogError(androidStudioPath + " 不存在 WXEntryActivity.java") return False destPath = srcPath[:-(len(dirPath) + len('/WXEntryActivity.java'))] + packInfo['bundleId'].replace(".", "/") + "/wxapi/WXEntryActivity.java" if srcPath != destPath: paramMap = { "package (.*);" : "package "+ packInfo['bundleId'] + ".wxapi;" } if not ChangeFileMatchContent(srcPath, destPath, paramMap): return False for i in range(len(ls)): if ls[i] != destPath: PathConvert.DeletePathUtilIsNone(srcPath) Debug.LogSuccess("设置AndroidStudio 完成 " + androidStudioPath) return True def GetWXEntryActivityDirPath(srcPath): try: if not os.path.exists(srcPath): Debug.LogError(srcPath + " 不存在") return None with open(srcPath, 'r') as file_obj: lines = file_obj.readlines() for i in range(len(lines)): line = lines[i].strip() if line.startswith("package"): idx = line.find(';') return line[7:idx].strip() except Exception as exc: Debug.LogError(exc) Debug.Log("") return None return None def CopyFile(srcPath, destPath, ingoreCheckDest = False): try: if not os.path.exists(srcPath): Debug.LogError(srcPath + " 不存在") return False if not ingoreCheckDest and not os.path.exists(destPath): Debug.LogError(destPath + " 不存在") return False shutil.copyfile(srcPath, destPath) except Exception as exc: Debug.LogError(exc) Debug.Log("") Debug.LogError(srcPath + " -> " + destPath) return False return True def GetFilesByFileName(path, fileNames = None): ls = [] if not fileNames: pass elif not os.path.exists(path): pass elif os.path.isfile(path): if os.path.basename(path) in fileNames: ls.append(path.replace("\\", "/")) elif os.path.isdir(path): for childPath in os.listdir(path): children = GetFilesByFileName(os.path.join( path, childPath), fileNames) ls.extend(children) return ls def ChangeFileMatchContent(srcPath, destPath, paramMap): try: if not os.path.exists(StringFormat.FormatStringPlatform(srcPath)): Debug.LogError(srcPath + " 无法找到") return False content = None with open(srcPath, 'r') as file_obj: content = file_obj.read() for k in paramMap: content = re.sub(k, paramMap[k], content) if content: if not os.path.exists(StringFormat.FormatStringPlatform(destPath)): dirPath = os.path.dirname(StringFormat.FormatStringPlatform(destPath)) if not os.path.exists(dirPath): os.makedirs(dirPath) with open(destPath, 'w') as file_obj: file_obj.write(content) except Exception as exc: Debug.LogError(exc) Debug.Log("") Debug.LogError(srcPath + " -> " + destPath) return False return True def ChangeFileLineContent(srcPath, destPath, paramMap, match = '='): try: if not os.path.exists(StringFormat.FormatStringPlatform(srcPath)): Debug.LogError(srcPath + " 无法找到") return False newLines = [] with open(srcPath, 'r') as file_obj: lines = file_obj.readlines() for i in range(len(lines)): line = lines[i] stripLine = line.lstrip() for k in paramMap: if stripLine.startswith(k): stripLine = stripLine[len(k):].lstrip() if stripLine[0] == match: stripLine = stripLine[1:].lstrip() idx = line.rfind(stripLine) line = line[0:idx] + paramMap[k] + '\n' break newLines.append(line) if not os.path.exists(StringFormat.FormatStringPlatform(destPath)): dirPath = os.path.dirname(StringFormat.FormatStringPlatform(destPath)) if not os.path.exists(dirPath): os.mkdir(dirPath) with open(destPath, 'w') as file_obj: file_obj.write(''.join(newLines)) except Exception as exc: Debug.LogError(exc) Debug.Log("") Debug.LogError(srcPath + " -> " + destPath) return False return True def PackAndroidStudio(packInfo, params): if not packInfo: Debug.LogError("打包AndroidStudio时 packInfo 为空") return False if not params: Debug.LogError("打包AndroidStudio时 params 为空") return False if not params.has_key(TAG_OTHER_BUILD_PROJECT_PATH): Debug.LogError("打包AndroidStudio时 params 不能找到 " + TAG_OTHER_BUILD_PROJECT_PATH) return False androidStudioPath = params[TAG_OTHER_BUILD_PROJECT_PATH].replace('\\', '/') if not os.path.exists(StringFormat.FormatStringPlatform(androidStudioPath)): Debug.LogError(androidStudioPath + " 无法找到") return False Debug.LogSuccess("打包AndroidStudio 开始 " + androidStudioPath) os.chdir(androidStudioPath) try: # MAC(OSX)升到 11.0.1 bigsur 后 gradle 无法直接找到 tools.jar env = os.environ.copy() if CUR_PLATFORM_NAME == 'Darwin': cmds = ['/usr/libexec/java_home', '-V'] sp = subprocess.Popen(cmds, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, env=env) contents = sp.communicate() sp.wait() for content in contents: lines = content.split('\n') for i in range(len(lines)): line = lines[i].strip() if line != '': path = None if os.path.exists(line): path = line + '/lib/tools.jar' else: paths = line.split(' ') for j in range(len(paths)): if path: path = path + ' ' + paths[j] elif os.path.exists(paths[j]): path = paths[j] if path and os.path.exists(path): env['JAVA_HOME'] = path if CUR_PLATFORM_NAME == 'Windows': cmds = ['gradlew.bat', "assembleRelease"] res = subprocess.check_output(cmds, shell=False, env=env) else: cmds = ['sh', 'gradlew', "assembleRelease"] res = subprocess.check_output(cmds, shell=False, env=env) res = StringFormat.FormatStdinString(res) success = False lines = res.split("\n") for i in range(len(lines)): line = lines[i].strip() if line.startswith("BUILD SUCCESSFUL"): success = True if not success: Debug.LogError(res) Debug.Log('') Debug.LogError("gradlew assembleRelease Fail ") return False except Exception, exc: Debug.LogError(exc) Debug.Log("") Debug.LogError("打包AndroidStudio 失败 " + androidStudioPath) return False Debug.LogSuccess("打包AndroidStudio 成功 " + androidStudioPath) return True def PackRunOne(unityPath, packId): os.chdir(PROJECT_PATH) packInfo, platformCfgName, platformName = GetPackInfo(packId) if not packInfo or not platformCfgName or not platformName: Debug.LogError("不是有效的打包平台Id " + packId) return False, " 不是有效的打包平台Id " Debug.Log("") Debug.LogSuccess("开始打包 " + GetPackName(packInfo)) Debug.Log("") logPath = os.path.abspath(BUILD_LOG_PATH + ("/build_%s.log" % packId)) DeleteUnityLog(logPath) if not UnityPack(unityPath, packId, logPath): return False, GetPackName(packInfo) + " Unity打包失败" _, params = ParseUnityLog(logPath) appPath = None if params.has_key(UNITY_TAG_AppOutPath): appPath = params[UNITY_TAG_AppOutPath] if platformCfgName == 'weiDuanAndroids': if not SettingAndroidStudio(packInfo, params): return False, GetPackName(packInfo) + " 设置AndroidStudio项目失败" if not PackAndroidStudio(packInfo, params): return False, GetPackName(packInfo) + " 打包AndroidStudio项目失败" else: if "FairGuard" in packInfo["plugins"]: if platformName.lower() == "android": if not FairGuardAndroid(appPath): return False, GetPackName(packInfo) + " FairGuard加固失败" elif platformName.lower() == "ios": if not FairGuardiOS(appPath): return False, GetPackName(packInfo) + " FairGuard加固失败" if platformName.lower() == "ios": if not ZipCompress(appPath): return False, GetPackName(packInfo) + " Zip压缩失败" Debug.Log("") Debug.LogSuccess("完成打包 " + GetPackName(packInfo)) Debug.Log("") return True, GetPackName(packInfo) def PackRun(unityPath, packIdStr): packIds = packIdStr.split(':') errors = [] success = [] for i in range(len(packIds)): packId = packIds[i] if packId and not (packId == ""): res, error = PackRunOne(unityPath, packId) if not res: errors.append(packId + "\t" + error) else: success.append(packId + "\t" + error) successNum = len(success) if successNum > 0: Debug.Log("") Debug.Log("") Debug.Log("") Debug.LogSuccess("打包成功的有:") for i in range(successNum): Debug.LogSuccess(success[i]) else: Debug.Log("") Debug.Log("") errorNum = len(errors) if errorNum > 0: Debug.Log("") Debug.LogError("打包失败的有:", True) for i in range(errorNum): Debug.LogError(errors[i], True) Debug.Log("") Debug.Log("") sys.exit(2) else: Debug.Log("") Debug.Log("") def CleanBuildError(): try: os.chdir(PROJECT_PATH) cmds = ["git", "checkout", "./ProjectSettings/ProjectSettings.asset"] res = subprocess.check_output(cmds, shell=False) res = StringFormat.FormatStdinString(res) Debug.Log(res) PathConvert.DeletePathAll("./Assets/Plugins/Android") PathConvert.DeletePathUtilIsNoneOnUnityProject("./Assets/Plugins/Android") PathConvert.DeletePathAll("./Assets/Plugins/iOS") PathConvert.DeletePathUtilIsNoneOnUnityProject("./Assets/Plugins/iOS") PathConvert.DeletePathAll("./Assets/Plugins/SDKBridge") PathConvert.DeletePathUtilIsNoneOnUnityProject("./Assets/Plugins/SDKBridge") except Exception as exc: Debug.LogError(exc) Debug.Log("") Debug.LogError("解决编译错误失败,请通知程序 ") def Main(): try: args = sys.argv[1:] dic = {} num = len(args) for i in range(num): arg = 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: if args[i + 1].startswith('-'): Debug.LogSuccess(arg) dic[arg] = '' else: Debug.LogSuccess(arg + " " + args[i + 1]) dic[arg] = args[i + 1] except Exception as e: Debug.LogError(e) PrintHelp() return if len(dic) <= 0: PrintHelp() return if ('-help' in dic): PrintHelp() return if ('-config' in dic): PrintConfig(dic['-config']) return if (not '-nogit' in dic): if not ExecGit(): return unityPath = None if ('-unitypath' in dic): unityPath = dic['-unitypath'] unityPath = GetUnityPath(unityPath) if not ValidUnityPath(unityPath): return if not ValidJava(): return if ('-clrerr' in dic): CleanBuildError() packId = None if ('-buildApp' in dic): packId = dic['-buildApp'] PackRun(unityPath, packId) return if __name__ == '__main__': try: Main() except Exception as e: Debug.LogError(e) Debug.LogError(traceback.format_exc(), True) sys.exit(1)