unity之Jenkins自动化出包shell脚本
2021-01-28 01:13
标签:mic round find back 手游 提示 bat icons lse jenkins工具自动化出包,此功能不是我做的。 用到的shell脚本分享一下,以备将来研究之用。 Jenkins中构建: 命令为: shell脚本如下: 1. utils.py 2. package.py1 #!C:/Program Files/Git/bin/bash
2 python -u D:/buildApk_New/USA/sgmyPackge/package.py $Versions E:/WorkTool/Unity2017.4/Unity/Editor/Unity.exe $VersionIncrease $BuildFlavor $BigPackage
1 import hashlib
2 import subprocess
3 import platform
4 import shutil
5 import os
6
7 _FILE_SLIM = (100 * 1024 * 1024) # 100MB
8 cur_os = platform.system()
9
10 def subprocess_return(cmd):
11 print(cmd)
12 status = subprocess.call(cmd,shell = True)
13 return status
14
15 def subprocess_call(cmd):
16 print (cmd)
17 status = subprocess.call(cmd,shell = True)
18 if status != 0:
19 exit(status)
20
21 def CheckUnity():
22 cmd = "ps -ef|grep MacOS/Unity |grep -v CheckUnity |grep -v grep "
23 if cur_os == "Windows":
24 cmd = "tasklist | findstr Unity"
25 status = subprocess.call(cmd,shell = True)
26 if status == 0 :
27 print ("Unity is running!!")
28 return status
29
30 def killUnity():
31 cmd = "killall -9 Unity"
32 if cur_os == "Windows":
33 cmd = "taskkill /f /im Unity.exe"
34 status = subprocess.call(cmd,shell = True)
35 if status == 0 :
36 print ("no running Unity")
37 return status
38
39 def file_md5(filename):
40 calltimes = 0
41 hmd5 = hashlib.md5()
42 fp = open(filename,"rb")
43 f_size = os.stat(filename).st_size
44 if f_size>_FILE_SLIM:
45 while(f_size>_FILE_SLIM):
46 hmd5.update(fp.read(_FILE_SLIM))
47 f_size/=_FILE_SLIM
48 calltimes += 1 #delete
49 if(f_size>0) and (f_size_FILE_SLIM):
50 hmd5.update(fp.read())
51 else:
52 hmd5.update(fp.read())
53
54 return (hmd5.hexdigest(),calltimes)
55
56 def copyc(path, out):
57 for files in os.listdir(path):
58 name = os.path.join(path, files)
59 back_name = os.path.join(out, files)
60 if os.path.isfile(name):
61 shutil.copy(name, back_name)
62 else:
63 if not os.path.isdir(back_name):
64 os.makedirs(back_name)
65 copyc(name, back_name)
66
67 def copyd(path,out):
68 for files in os.listdir(path):
69 name = os.path.join(path,files)
70 back_name = os.path.join(out,files)
71 if os.path.exists(back_name):
72 pass
73 else:
74 if os.path.isfile(name):
75 shutil.copy(name, back_name)
76 else:
77 if not os.path.isdir(back_name):
78 os.makedirs(back_name)
79 copyd(name, back_name)
80 def buildpackage_unity(unity_bin, rootpath, printpath):
81 ###unity build by command line
82
83 cmd = "%s -batchmode 84 -quit -projectPath 85 %s/UnityClient 86 -executeMethod ProjectBuilder.BuildPlayerForASProject 87 Path=%s" % (unity_bin, rootpath, printpath)
88
89 status = subprocess_return(cmd)
90 return status
91
92 def buildBigPackage(unity_bin,rootpath):
93
94 cmd = "%s -batchmode 95 -quit -projectPath 96 %s/UnityClient 97 -executeMethod ReduceLocalAssetBundleTool.ReduseLocalAssets " % (unity_bin, rootpath)
98
99 status = subprocess_return(cmd)
100 return status
101
102 def buildBigPackageRe(unity_bin,rootpath):
103
104 cmd = "%s -batchmode 105 -quit -projectPath 106 %s/UnityClient 107 -executeMethod ReduceLocalAssetBundleTool.RevertReduseLocalAssets " % (unity_bin, rootpath)
108
109 status = subprocess_return(cmd)
110 return status
111 def showlastline(filepath, num):
112 text = []
113 f = open(filepath, ‘rb‘)
114
115 lines = f.readlines()
116 count = len(lines)
117 if count > 100:
118 num = 100
119 else:
120 num = count
121
122 for i in range(1, (num+1)):
123 if lines:
124 n = -i
125 lastline = lines[n].strip()
126 text.append(lastline)
127
128 f.close()
129 while text:
130 #print (text.pop())
131 pass
132
133 def showlog_buildfailed(unitylogfile):
134 print ("\n\nbuild failed!!!!\n\n\n###Editor.log############################################################################")
135 if os.path.exists(unitylogfile):
136 os.remove(unitylogfile)
137 file = open(unitylogfile,"w")
138 file.close()
139 showlastline(unitylogfile,100)
140 exit(1)
141 pass
142
143 def CheckXcode():
144 if cur_os == "Darwin" :
145 cmd = "ps -ef|grep Xcode |grep -v grep "
146 status = subprocess.call(cmd,shell = True)
147 if status == 0 :
148 print ("Xcode is running!!")
149 return status
150
151 def CheckiTunes():
152 if cur_os == "Darwin" :
153 cmd = "ps -ef|grep iTunes |grep -v grep "
154 status = subprocess.call(cmd,shell = True)
155 if status == 0 :
156 print ("iTunes is running!!")
157 return status
158
159 def killXcode():
160 if cur_os == "Darwin":
161 cmd = "killall -9 Xcode"
162 status = subprocess.call(cmd,shell = True)
163 if status == 0 :
164 print ("no running Xcode")
165 return status
166
167 def killiTunes():
168 if cur_os == "Darwin":
169 cmd = "killall -9 iTunes"
170 status = subprocess.call(cmd,shell = True)
171 if status == 0 :
172 print ("no running iTunes")
173 return status
174
175 def svn_cleanup(path):
176 cmd = ‘svn cleanup %s‘ %(path)
177 subprocess_call(cmd)
178
179 def svn_up(path):
180 cmd = "svn up %s --non-interactive" %(path)
181 subprocess_call(cmd)
182
183 def svn_add(path):
184 cmd = "svn add %s --force" %(path)
185 subprocess_call(cmd)
186
187 def svn_ci(path,desc):
188 cmd = "svn ci %s -m %s" %(path,desc)
189 subprocess_call(cmd)
190
191 def rw_vconfig_autoincrement(path,autoIncreament):
192 f = open(path,‘r‘)
193 configStr = f.read()
194 versionCodeStr = configStr.split("\n")[0].replace("versionCode=","")
195 versionNameStr = configStr.split("\n")[1].replace("versionName=","")
196 versionCode = int(versionCodeStr)
197 versionName = float(versionNameStr)
198 versionCode_add = versionCode +1
199 versionCodeName_add = round(versionName + 0.1, 1)
200 changedConfigStr = "versionCode=%s\nversionName=%s" % (versionCode_add, versionCodeName_add)
201 f.close()
202 if autoIncreament == "true":
203 f = open(path, ‘w‘)
204 f.write(changedConfigStr)
205 f.close()
206 return versionCode,versionName
207
208 # def os_popen_show(cmd):
209 # print (cmd)
210 # rs = os.popen(cmd).readlines()
211 # matched = len(rs)
212 # count = 0
213 # while count
214 # print (rs[count].replace(‘\n‘,‘‘))
215 # count = count + 1
216 # return matched
1 ###
2 ###python3
3 ###请在该py文件中配置手动配置svnPath变量的值及输出apk上传的本地svn路径,productName及Unity中PlyerSetting中ProductName
4 ###Unity日志输出路径为Unity项目下面Editor.log
5 ###
6
7 import shutil
8 import os
9 import time
10 import math
11 import sys
12 import json
13 import utils
14 import a360syb
15
16
17 print("-----------------starting build package--------------------")
18 time1 = time.time()
19
20
21 print()
22 print()
23 """
24 第一个参数为Untiy的路径
25 第二个参数为Unity项目的路径 如:E:\\Git\\UnityClient-vn
26 """
27
28 rootpath = "E:\\Versions\\"+sys.argv[1]+"\\UnityClient"
29 unity_bin = sys.argv[2]
30 auIncreVer = sys.argv[3]
31 packageFlavor = sys.argv[4]
32 bigPackage = sys.argv[5]
33
34 productName = "AU2 Mobile-EN"#
35 showName = "AU2Dance Idol";
36 svnPath = "D:\\ApkVersions\\SGMY"
37 targetGradle = "E:\\buildApk_New\\SGMY\\SuperIdolMobile\\"
38 targetproject = targetGradle +"app"
39 Unitylogfile = rootpath+"\\Editor.log"
40 asprojectfile = rootpath+"\\UnityClient\\androidstudio"
41 resRelativePath = "\\src\\main\\res"
42 libsRelativePath = "\\libs"
43 soRelativePath = "\\src\\main\\jniLibs"
44 assetsRelativePath = "\\src\\main\\assets"
45 #TODO
46 iconName = "app_icon.png"
47 versionConfig = "E:\\buildApk_New\\SGMY\\sgmyPackge\\versionConfig"
48
49 #unity判断什么的
50 while utils.CheckUnity() == 0:
51 print("Unity进程正在运行")
52 utils.killUnity()
53 time.sleep(2)
54
55 print("------- building as project from Unity--------")
56 print()
57
58 status=0
59 if bigPackage == "false":
60 status = utils.buildBigPackage(unity_bin,rootpath)
61 if status != 0:
62 utils.showlog_buildfailed(Unitylogfile)
63
64 if os.path.exists(asprojectfile):
65 shutil.rmtree(asprojectfile)
66
67 status = utils.buildpackage_unity(unity_bin,rootpath,asprojectfile)
68 if status != 0:
69 utils.showlog_buildfailed(Unitylogfile)
70 if not os.path.exists(asprojectfile):
71 print("未能正确打出As工程")
72 exit(1)
73 print()
74 print("------- build as project finish--------")
75
76 """
77 创建Unity打出的as工程内部资源和目标资源的路径
78 """
79 asprojectfile_libs = asprojectfile+"\\"+productName+libsRelativePath
80 targetProjectfile_libs = targetproject+libsRelativePath
81 asprojectfile_res = asprojectfile+"\\"+productName+resRelativePath
82 targetProjectfile_res = targetproject+resRelativePath
83 asprojectfile_assets = asprojectfile+"\\"+productName+assetsRelativePath
84 targetProjectfile_assets = targetproject+assetsRelativePath
85 asprojectfile_so = asprojectfile+"\\"+productName+soRelativePath
86 targetProjectfile_so = targetproject+soRelativePath
87
88 print("---------compareing libs--------------")
89 print()
90
91
92 if bigPackage == "false":
93 status = utils.buildBigPackageRe(unity_bin,rootpath)
94 if status != 0:
95 utils.showlog_buildfailed(Unitylogfile)
96 """
97 比对Libs文件夹,只比对。如果不匹配就提示
98 """
99 asLibsDict = {}
100 targetLibsDict = {}
101 for root,dirs,files in os.walk(asprojectfile_libs):
102 for name in dirs:
103 print("AAAAA",os.path.join(root,name))
104 for name in files:
105 asLibsDict[name] = utils.file_md5(os.path.join(root,name))[0]
106 #print (asLibsDict)
107
108 for root,dirs,files in os.walk(targetProjectfile_libs):
109 for name in dirs:
110 pass
111 # print("A",os.path.join(root,name))
112 for name in files:
113 targetLibsDict[name] = utils.file_md5(os.path.join(root,name))[0]
114 defalutTip = "NONE"
115 for key,value in asLibsDict.items():
116 tv = targetLibsDict.get(key,defalutTip)
117 if tv == defalutTip:
118 tv = "在targetLib中没有 " + key + " 文件,如需要请手动配置"
119 print(tv)
120 else :
121 if tv == value:
122 pass
123 else :
124 tv = "在targetLib中 "+key+" 文件与unity打出as工程中文件MD5值不一样,如需要请手动配置"
125 print(tv)
126
127 print()
128 print("---------compare libs finish--------------")
129
130 print("---------compareing icon and appName--------------")
131 print()
132
133 """
134 res下面的内容,1比对icon,2比对appName
135 """
136 asIconsDict = {}
137 targetIconsDict = {}
138 for root,dirs,files in os.walk(asprojectfile_res):
139 for name in dirs:
140 pass
141 for name in files:
142 fullpath = os.path.join(root, name)
143 arr = fullpath.split("\\")
144 if iconName == arr[len(arr) - 1]:
145 dirName = arr[len(arr) - 2]
146 dirName = dirName.replace("drawable","mipmap",1)
147 asIconsDict[dirName] = (utils.file_md5(os.path.join(root, name))[0],fullpath)
148 else :
149 pass
150 #print(asIconsDict)
151 #遍历目标文件的res文件
152 for root,dirs,files in os.walk(targetProjectfile_res):
153 for name in dirs:
154 pass
155 #print("A",os.path.join(root,name))
156 for name in files:
157 fullpath = os.path.join(root, name)
158 arr = fullpath.split("\\")
159 if iconName == arr[len(arr) - 1]:
160 # print(arr[len(arr) - 2])
161 dirName = arr[len(arr) - 2]
162 targetIconsDict[dirName] = (utils.file_md5(os.path.join(root, name))[0],fullpath)
163 else :
164 pass
165 #print(targetIconsDict)
166
167 #ValueError: too many values to unpack(expected 3) 没有加items()
168 defalutTip = "NONE"
169 for key,value in asIconsDict.items():
170 ti = targetIconsDict.get(key,defalutTip)
171 # as文件中有一个文件夹,目标工程中没有这个文件夹,提示,并拷贝
172 if ti == defalutTip:
173 aspath = value[1]
174 asarr = aspath.split("\\")
175 folderName = asarr[len(asarr)-2]
176 folderName = folderName.replace("drawable","mipmap",1)
177 # 第一种情况 没有mipmap-?hdp1文件
178 if not os.path.exists(targetProjectfile_res +"\\" +folderName):
179 os.mkdir(targetProjectfile_res +"\\" +folderName)
180 # 第二种情况 mipmap-?hdpi文件中没有改文件
181 print(value[1])
182 print(targetProjectfile_res +"\\" +folderName+"\\"+asarr[len(asarr)-1])
183 shutil.copyfile(value[1],targetProjectfile_res +"\\" +folderName+"\\"+asarr[len(asarr)-1] )
184 print("target文件夹中没有"+value[1]+"已经拷贝")
185 #有的话判断icon的MD5,看是不是同一张图片
186 else :
187 #如果是同一张图片,忽略
188 if value[0] == ti[0]:
189 pass
190 #如果不是同一张图片,提示并覆盖
191 else :
192 shutil.copyfile(value[1], ti[1])
193 ti = key,"中icon文件与不一致,已替换"
194 print(ti)
195
196 print()
197 print("---------compare icon and appName finish--------------")
198
199 print("----------collating jinLibs and assets file-------------")
200 print()
201
202 """
203 jniLibs下面的文件
204 """
205 for root, dirs, files in os.walk(asprojectfile_so):
206 for name in dirs:
207 if not os.path.exists(targetProjectfile_libs+"\\"+name):
208 os.mkdir(targetProjectfile_libs+"\\"+name)
209 for name in files:
210 fullpath = os.path.join(root, name)
211 libarr = fullpath.split("\\")
212 if utils.file_md5(os.path.join(root, name))[0] != utils.file_md5(targetProjectfile_so + "\\" + libarr[len(libarr) - 2] + "\\" + name)[0]:
213 shutil.copyfile(os.path.join(root, name),
214 targetProjectfile_so + "\\" + libarr[len(libarr) - 2] + "\\" + name)
215
216
217 """
218 assets下面的文件
219 """
220 ###
221 ###新马assets下面的保护文件 www, plugin_config.xml package_config.json globalizationLang.json
222 ###
223 #如果没有这个文件夹会报错
224 # shutil.rmtree(targetProjectfile_assets) # 递归删除文件夹
225 if not os.path.exists(targetProjectfile_assets):
226 os.makedirs(targetProjectfile_assets)
227 else :
228 for root, dirs, files in os.walk(targetProjectfile_assets):
229 for name in dirs:
230 filePath = os.path.join(root, name)
231 if not name == "www" :
232 if not "\\assets\\www\\" in filePath:
233 dirPath = os.path.join(root, name)
234 shutil.rmtree(dirPath)
235 for name in files:
236 if not name == "plugin_config.xml" and not name == "package_config.json" and not name == "globalizationLang.json":
237 filePath = os.path.join(root, name)
238 if not "\\assets\\www\\" in filePath:
239 os.remove(filePath)
240
241
242 utils.copyd(asprojectfile_assets,targetProjectfile_assets)
243
244 print()
245 print("-----------collate jinLibs and assets file finish--------------")
246
247
248 print("-----------building apk-----------")
249 print()
250
251 """
252 编译出apk
253 """
254 #gradlew assembleRelease
255
256 verList = utils.rw_vconfig_autoincrement(versionConfig,auIncreVer)
257 os.chdir(targetGradle)
258
259 if packageFlavor == "googleAll":
260 buildApkCmd = "gradlew assemblegoogle -PversionCode=%s -PversionName=%s" % (verList[0], verList[1])
261 elif packageFlavor == "googleRelease":
262 buildApkCmd = "gradlew assemblegoogleRelease -PversionCode=%s -PversionName=%s" % (verList[0], verList[1])
263 elif packageFlavor == "guanwangAll":
264 buildApkCmd = "gradlew assembleguanwang -PversionCode=%s -PversionName=%s" % (verList[0], verList[1])
265 elif packageFlavor == "guanwangRelease":
266 buildApkCmd = "gradlew assembleguanwangRelease -PversionCode=%s -PversionName=%s" % (verList[0], verList[1])
267 buildApkCmd = buildApkCmd + " --info"
268 statusEnd = utils.subprocess_return(buildApkCmd)
269 print(statusEnd)
270 if statusEnd != 0:
271 utils.showlog_buildfailed(Unitylogfile)
272
273 print()
274 print("-----------build apk over-----------")
275
276 print("------------begin 360 jiagu--------------")
277 print()
278
279 print()
280 print("------------360 jiagu finish--------------")
281
282
283
284
285
286 # shutil.copyfile(defaltOutputApk,outputName)
287 #加固
288 print("---------360jiagu start------------")
289 ###打出来4个包
290 #|--google
291 #|-----debug
292 #|-----release
293 #|--guanwang
294 #|-----debug
295 #|-----release
296 defaltOutputApk = targetproject+"\\build\\outputs\\apk\\"
297 nowTime = time.strftime("%m-%d_%H-%M", time.localtime())
298 outputName = svnPath+"\\"+nowTime+"_"+showName
299
300 print()
301 if packageFlavor == "googleAll":
302 apk1 = defaltOutputApk + "google\\debug\\app-google-debug.apk"
303 apk2 = defaltOutputApk + "google\\release\\app-google-release.apk"
304 defaltOutputApk = [apk1,apk2]
305 out1 = (outputName + "google-debug.apk").replace(" ","")
306 out2 = (outputName + "google-release.apk").replace(" ","")
307 outputName = [out1,out2];
308 elif packageFlavor == "googleRelease":
309 defaltOutputApk = defaltOutputApk + "google\\release\\app-google-release.apk"
310 outputName = (outputName + "google-release.apk").replace(" ", "")
311 elif packageFlavor == "guanwangAll":
312 apk1 = defaltOutputApk + "guanwang\\debug\\app-guanwang-debug.apk"
313 apk2 = defaltOutputApk + "guanwang\\release\\app-guanwang-release.apk"
314 defaltOutputApk = [apk1, apk2]
315 out1 = (outputName + "guanwang-debug.apk").replace(" ", "")
316 out2 = (outputName + "guanwang-release.apk").replace(" ", "")
317 outputName = [out1, out2];
318 elif packageFlavor == "guanwangRelease":
319 defaltOutputApk = defaltOutputApk + "guanwang\\release\\app-guanwang-release.apk"
320 outputName = (outputName + "guanwang-release.apk").replace(" ", "")
321
322
323
324 print(outputName)
325
326 if not type(defaltOutputApk) is list:
327 a360syb.begin(defaltOutputApk,outputName)
328 else:
329 for i in range(len(defaltOutputApk)) :
330 a360syb.begin(defaltOutputApk[i], outputName[i])
331
332
333 print()
文章标题:unity之Jenkins自动化出包shell脚本
文章链接:http://soscw.com/index.php/essay/47996.html