#!/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)