首页 >> 大全

Unity + Jenkins自动打包 (二)构建Jenkins项目以及编写Py

2023-09-20 大全 30 作者:考证青年

现在打开浏览器,输入:8081,当然,需要改成你自己设置的端口号,然后就会出现一下界面

点击“新建Item”

输入一个名称,比如现在要构建一个自动打包项目,就叫,然后点击“ ”

构建一个自由风格的项目。

点击确定,就会生成一个空项目。

2、添加构建参数

在新建的项目界面中

勾选第一个“ old ”,它会帮你删除旧的构建记录。

而第二个“This is ”,意思是这是一个参数化构建的项目,勾选后就可以添加各种参数,如下图:

比如,我们在Unity打包时,项目上线时会构建一个整包Apk,在上线后,会经常构建热更包,那么就需要添加一个选择参数来区分,如下图:

然后点击“保存”

再点击"Build with ",就可以看到刚才添加的参数

再点击“配置”,来添加一个Bool 型参数

其中“Set by ”,勾选后这个参数会默认勾选上。

那么这个参数就可以用来选择是否构建,比如第一次出包的时候,肯定就要勾选上,而当我们出包后,测试发现一些配置上的Bug,那么这个时候只需要修改配置表,重新构建Apk即可,无需重新构建,那这时候就不用勾选这个参数。

当然,我们打包时一般来说都会有很多步骤,一般都是一些老前辈写好的静态工具方法,打包的同志按照步骤挨个点一遍,那当然也会出现像上面说到的情况,有时候只是改动一小部分东西,不用全部执行,那就可以添加各种参数来跳过不必要的操作。

3、添加命令、脚本

_打包java项目_java自动化打包

一般来说,用于打包的Unity工程都在一个专用来打包的主机上,而且一般有两个工程,在其中一个工程里构建AB,再拷贝到另一个不包含各种资源的工程里,然后构建Apk。

那么首先便要将用于构建AB的工程更新,找到“构建”,增加构建步骤,选择“ batch ”,增加命令行命令。

以SVN为例,如果是Git,查一下命令就行了

首先找到需要更新的项目目录:

然后添加命令:

后面的参数 -- -,这是用来解决冲突的,以服务器的版本为准。

更新完成后就可以启动Unity工程,等待Unity编译完成后,执行打包的各个步骤。

那么接下来就要编写Unity的静态方法供外部调用:

public class GameBuild {public static void StartBuild() {// 开始执行各个打包步骤// 。。。。。。。。。。。。// 。。。。。。。。。。。。}
}

那怎么判断Unity已经编译完成了,之后再调用我们写的打包方法呢?

public class GameBuild {public static void WaitCompilingToBuild() {EditorApplication.update += CanStartBuild;}static void CanStartBuild() {if ( !EditorApplication.isCompiling ) {EditorApplication.update -= CanStartBuild;Debug.Log( "=====编译完成=====" );EditorApplication.delayCall += StartBuild;}}static void StartBuild() {// 开始执行各个打包步骤// 。。。。。。。。。。。。// 。。。。。。。。。。。。}
}

现在我们只需要调用 .,就可以实现在Unity编译完成后调用我们的打包方法。

. +=

这一句的意思是:将其执行延迟到检视面板更新完成之后。每个函数在添加后仅执行一次。

现在,在里面添加命令

start C:\~1\Unity\\Unity.exe --- - D:\ - . --:%%

最后面的参数 --:%% ,就是用来将我们上面添加的Bool型参数传入Unity,那么Unity如何接收,请往下看

其中 /F /IM Unity.exe 是用来关闭Unity进程,因为Unity只能同时存在一个实例

其中start 后面跟Unity.exe的路径;

需要注意 :命令行在执行非CD命令时,无法识别空格,

而Unity一般安装在C:\ Files下,需要将路径写为:C:\~1

或者先执行 cd 命令进入Unity安装目录,再调用,如图:

假设打包步骤如我上面所说,在构建AB的工程执行完成后,再将各种资源都拷到构建Apk的工程,那么怎么判断调用的静态方法是否完成。因为调用Unity的方法,命令行不会一直持有Unity,在调用Unity方法后,不会等Unity的方法执行完后再执行下一句命令,所以需要用另外的脚本来判断。

_打包java项目_java自动化打包

我一般喜欢用脚本来判断,关于的安装请自行百度。

首先要在打包方法里面增加日志打印,完整代码为:

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;public class GameBuild {private static string logFilePath = "E:\\Log_Build.txt";private static bool Build_AB;public static void WaitCompilingToBuild() {// 接收外部传入的参数string[] args = System.Environment.GetCommandLineArgs();foreach ( var s in args ) {if ( s.Contains( "--Build_AB:" ) ) {Build_AB = s.Split( ':' )[ 1 ] == "true";}}EditorApplication.update += CanStartBuild;}static void CanStartBuild() {if ( !EditorApplication.isCompiling ) {EditorApplication.update -= CanStartBuild;Debug.Log( "=====编译完成=====" );EditorApplication.delayCall += StartBuild;}}static void StartBuild() {// 开始执行各个打包步骤if ( Build_AB ) {// 开始构建AssetBundle}else {// 跳过构建AssetBundle}WriteLog("Build AB finished");}public static void WriteLog( string Logstring ) {if ( !File.Exists( logFilePath ) ) {FileStream stream = File.Create( logFilePath );stream.Close();stream.Dispose();}using ( StreamWriter writer = new StreamWriter( logFilePath, true ) ) {writer.WriteLine( Logstring );writer.Close();}}
}

那么现在,就只需要监听 .txt,这个文件里面是否有日志“Build AB ”,如果检测到,那么就跳出循环,命令行就可以执行下一步命令。

你可能会问,我为什么不直接使用unity的Debug.log,因为在打包的时候会输出大量的日志,直接检测Unity的日志会消耗比较大。

接下加上脚本:

# -*- coding:gb18030 -*-
import os
import time
import sys# 实时监测unity的log, 参数target_log是我们要监测的目标log, 如果检测到了, 则跳出while循环
def Listen_Log(target_log):pos = 0while True:if os.path.exists(log_file):print("监测到日志文件,开始监测打包步骤")breakelse:print("未监测到日志文件,等待")time.sleep(20)while True:fd = open(log_file, 'r')if pos != 0:fd.seek(pos, 0)while True:line = fd.readline()pos = pos + len(line)if target_log in line:print('监测到unity输出了目标log: ' + target_log + '  继续执行下一步==========')fd.close()returnif line.strip():print(line)else:breakfd.close()if __name__ == '__main__':log_file = 'E:/Log_Build.txt'print("开始监测日志")Listen_Log("Build AB finished")

将脚本命名为.py,然后在里面添加命令

加下来将资源拷到构建Apk的工程里面,直接使用cmd命令:copy pathA pathB

将A文件,拷到B目录下

接下来在构建Apk的工程里面添加静态方法,同样也需要在Unity编译完成后开始构建Apk

那么,构建Apk就不必使用日志检测的方式判断是否完成,只需要检测目标Apk是否存在即可

那么就需要一个确定的Apk名字,而且外部需要能拿到,那么接下来就用额外参数的形式来调用unity的静态方法

也就是说,Apk的名字由脚本确定,然后传给Unity脚本

然后在Apk构建完成后,将Apk复制到大家都能访问到的共享文件夹里面,然后在QQ或者钉钉群里面通知所有人

如果使用QQ的话,打包的主机上需要登录QQ,并且将需要发送消息的QQ群窗口打开

脚本,.py如下

# -*- coding:gb18030 -*-
import os
import time
import win32gui
import win32con
import win32clipboard as wdef call_unity_static_func(func):cmd = 'start %s -disable-assembly-updater -projectPath %s -executeMethod %s --pathName:%s'% (unity_exe, project_path, func, timeStr)print('run cmd:  ' + cmd)os.system(cmd)print("开始调用打包方法,构建Apk")# 实时监测Apk是否存在
def Check_Unity_Apk():while True:if os.path.exists(Apk_file):print("监测到Apk,构建Apk成功,开始复制到共享文件夹")breakelse:print("未监测到Apk,等待一段时间")time.sleep(20)def CopyFile():if os.path.exists(targetPath):print(" ")else:print("路径不存在,创建路径: " + targetPath)os.mkdir(targetPath)while True:if os.path.exists(targetPath):print("路径存在,开始复制")breakelse:time.sleep(2)cmd = "copy {0} {1}".format(Apk_file, targetPath)os.system(cmd)time.sleep(5)while True:if os.path.exists(targetApkPath):print("复制到共享文件夹完成,开始通知QQ群")breakelse:time.sleep(5)def SendQQ():theTime = time.strftime('%Y-%m-%d %H:%M', time.localtime())# 发送的消息msg = theTime + "\n打包机器人: 构建Apk完成\n最新包位置:" + showApkPath# 窗口名字name = "XXX项目组"# 将测试消息复制到剪切板中w.OpenClipboard()w.EmptyClipboard()w.SetClipboardData(win32con.CF_UNICODETEXT, msg)w.CloseClipboard()# 获取窗口句柄handle = win32gui.FindWindow(None, name)# 填充消息win32gui.SendMessage(handle, 770, 0, 0)# 回车发送消息win32gui.SendMessage(handle, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)if __name__ == '__main__':unity_exe = r'C:\Progra~1\Unity\Editor\Unity.exe'project_path = 'D:\Build_Apk_Project'# 执行unity静态方法timeStr = time.strftime('%Y_%m_%d_%H_%M', time.localtime())Apk_file = "E:\\Apk\\" + timeStr + ".apk"targetTimeStr = time.strftime('%Y_%m_%d', time.localtime())targetPath = "共享文件:\\APK\\" + targetTimeStrtargetApkPath = targetPath + "\\" + timeStr + ".apk"showApkPath = "共享文件/APK/" + targetTimeStr + "/" + timeStr + ".apk"static_func = 'GameBuild.WaitCompilingToStartBuildApk'call_unity_static_func(static_func)print("开始监测日志")Check_Unity_Apk()time.sleep(2)CopyFile()time.sleep(2)SendQQ()time.sleep(2)print("构建 Apk 结束")

Unity脚本如下

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;public class BuildApk
{private static string PathName = "";public static void WaitCompilingToStartBuildApk() {// 接收外部传入的参数string[] args = System.Environment.GetCommandLineArgs();foreach ( var s in args ) {if ( s.Contains( "--pathName:" ) ) {PathName = s.Split( ':' )[ 1 ];Debug.LogError( "收到传进来的Apk名: " + PathName );}}EditorApplication.update += CanBuildApk;}public static void CanBuildApk() {if ( !EditorApplication.isCompiling ) {EditorApplication.update -= CanBuildApk;EditorApplication.delayCall += StartBuildApk;}}public static void StartBuildApk() {//版本号PlayerSettings.bundleVersion = "1.0.0";//API 兼容性等级PlayerSettings.SetApiCompatibilityLevel( BuildTargetGroup.Android, ApiCompatibilityLevel.NET_2_0_Subset );//最低版本PlayerSettings.Android.minSdkVersion = AndroidSdkVersions.AndroidApiLevel21;//目标版本PlayerSettings.Android.targetSdkVersion = AndroidSdkVersions.AndroidApiLevel26;//安装位置 自动 autoPlayerSettings.Android.preferredInstallLocation = AndroidPreferredInstallLocation.Auto;//使用Gradle进行构建EditorUserBuildSettings.androidBuildSystem = AndroidBuildSystem.Gradle;//设置包名PlayerSettings.applicationIdentifier = "com.公司名.游戏名";//产品名字PlayerSettings.productName = "啦啦啦";PlayerSettings.Android.keystoreName = @"D:\XXXXXXXX\XXX.keystore";PlayerSettings.Android.keystorePass = "xxxxxx";PlayerSettings.Android.keyaliasName = "android.keystore";PlayerSettings.Android.keyaliasPass = "xxxxxx";//定义符,添加宏PlayerSettings.SetScriptingDefineSymbolsForGroup( BuildTargetGroup.Android, "XXXXXXXXXXXXXX" );BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions();buildPlayerOptions.scenes = GetBuildScenes();buildPlayerOptions.locationPathName = "D:/Apk/" + PathName + ".apk";buildPlayerOptions.target = BuildTarget.Android;buildPlayerOptions.options = BuildOptions.None;//执行打包 场景名字,打包路径BuildPipeline.BuildPlayer( buildPlayerOptions );Debug.Log( "构建Apk完成" );}static string[] GetBuildScenes() {List<string> names = new List<string>();foreach ( EditorBuildSettingsScene e in EditorBuildSettings.scenes ) {if ( e == null )continue;if ( e.enabled )names.Add( e.path );}return names.ToArray();}
}

代码逻辑就是:由去调用Unity的静态方法,并且在调用时传入一个字符串参数作为Apk的名字,然后在脚本里面监测Apk是否存在,然后拷到共享文件夹内,然后通知QQ群。

接下来在里面添加命令

4、完结

那么关于Unity + 自动打包的东西就讲到这儿,有什么不对的地方欢迎各位大佬在评论区指出!

有什么问题也可以在CSDN上私信问我,博客名:水星程序店!

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了