游戏开发进阶教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)

Posted 林新发

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了游戏开发进阶教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)相关的知识,希望对你有一定的参考价值。

一、前言

嗨,大家好,我是新发。
前几天我写了一篇文章,【游戏开发进阶】教你自制离线Maven仓库,实现Unity离线环境使用Gradle打包(Unity | Android | 谷歌 | Gradle),里面我提到了Unity使用Jenkins实现自动化打包,
在这里插入图片描述
不过那篇文章中我只是一笔带过,没有细说具体操作流程。今天,我就专门写一篇关于Unity通过Jenkins实现自动化打包的教程吧~

特别说明:
我的电脑系统环境是Windows 10,所以下面的操作环境都是在Windows 10系统下的。

二、Jenkins简介

相信很多人都知道Jenkins,不过为了照顾萌新,我这里还是简单说下Jenkins是什么。

Jenkins官网:https://www.jenkins.io/

Jenkins是一个开源软件项目,是基于Java开发的一个持续集成工具(CI),具有友好的操作界面,主要用于持续、自动的构建/测试软件项目、监控外部任务的运行。它可以在Tomcat等流行的servlet容器中运行,也可独立运行。通常与版本管理工具(SCM)、构建工具结合使用。常用的版本控制工具有SVNGIT,构建工具有MavenAntGradle

注:
什么是集成?
代码由编译、发布和测试、直到上线的一个过程。
什么是持续集成?
高效的、持续性的不断迭代代码的集成工作。

这样讲好像也不是很直观,没关系,它就是一个工具,我们学会使用它就好,下面我来一步步教大家如何使用Jenkins

三、Jenkins的下载与安装

1、JDK下载与安装

因为Jenkins是基于Java开发的,要运行Jenkins需要Java环境,即JDK,所以我们需要先安装下JDK
JDK下载:https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html
根据你的系统环境选择对应的JDK下载,
在这里插入图片描述
下载下来后双击即可执行安装,安装过程没什么,这里就不啰嗦了。
安装完毕后,配置一下JDK环境变量
最后在命令行中输入java -version,如果能正常输出版本号,则说明JDK环境弄好了。
在这里插入图片描述

2、Jenkins下载

进入Jenkins官网:https://www.jenkins.io/
点击Download
在这里插入图片描述
根据你的系统和环境选择对应的安装包,因为我是Windows系统,所以我下载Windows版的安装包,
在这里插入图片描述
下载下来是一个msi文件,
在这里插入图片描述

3、Jenkins安装

双击jenkins.msi,执行安装,设置一下安装路径,
在这里插入图片描述
选择Run service as LocalSystem(即使用本地系统账号)
在这里插入图片描述
设置端口号,比如我设置为8075,然后点击Test Port按钮测试一下端口有没有被占用,
在这里插入图片描述
确认端口没被占用后,点击Next
在这里插入图片描述
设置JDK所在的路径,
在这里插入图片描述
继续Next
在这里插入图片描述
点击Install开始安装,
在这里插入图片描述
注意,安装过程中可能会弹出360提醒,选择允许即可。
完整完毕,
在这里插入图片描述

4、Jenkins初始化

上面安装完毕后会自动启动Jenkins服务,我们可以在任务管理器中看到一个Java的进程,它就是Jenkins的服务进程。
在这里插入图片描述
我们在浏览器中访问 http://localhost:8075,此时会显示需要解锁Jenkins,如下
在这里插入图片描述
我们找到这个initialAdminPassword文件,使用文本编辑器打开它,
在这里插入图片描述
可以看到里面是一串密码,我们复制它,
在这里插入图片描述
回到浏览器页面中,在管理员密码栏中粘贴刚刚的密码,然后点击继续,
在这里插入图片描述
接下来是插件安装界面,因为Jenkins插件的下载需要翻墙,所以如果你可以科学上网,则点击安装推荐的插件,当然也可以先不安装插件,后续有需要再安装对应的插件即可,
在这里插入图片描述
如果是离线环境(比如内网环境),则点击跳过插件安装(下文我会教如何在离线环境下安装插件),
在这里插入图片描述
接着创建管理员账号,
在这里插入图片描述
完成,进入Jenkins主页,
在这里插入图片描述

四、Jenkins的基本操作

1、关闭Jenkins

1.1、方式一:暴力杀进程(不推荐)

上面我们说到,在任务管理器中可以看到一个Java进程,它就是Jenkins的服务进程,
在这里插入图片描述
如果你直接暴力杀掉这个Java进程,那么Jenkins也就关闭了,不过不建议这么做。

1.2、方式二:以管理员身份执行 net stop jenkins

以管理员身份运行命令net stop jenkins,如下(我是使用管理员身份运行PowerShell来执行命令的)
在这里插入图片描述

注意,如果你不是以管理员身份执行上面的命令,则会提示发生系统错误 5
如下(普通账号权限下通过cmd执行命令)
在这里插入图片描述
如何以管理员身份运行cmd?
进入cmd所在目录:
C:\\Users\\linxinfa\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\System Tools
在这里插入图片描述
右键命令提示符,点击以管理员身份运行即可,
在这里插入图片描述
如果觉得麻烦的话,也可以直接在系统的开始菜单那里直接以管理员身份运行PowerShell
在这里插入图片描述

1.3、方式三:通过jenkins.exe来关闭,jenkins stop

进入Jenkins的安装目录,如下,
在这里插入图片描述
在地址栏输入cmd,然后执行jenkins stop,如下,与上面的效果是一样的,
在这里插入图片描述

2、启动Jenkins

2.1、方式一:以管理员身份执行 net start jenkins

以管理员身份执行命令net start jenkins,如下
在这里插入图片描述

2.2、方式二:通过jenkins.exe来启动,jenkins start

进入Jenkins的安装目录,
在这里插入图片描述
执行命令jenkins start,如下
在这里插入图片描述
如果想重启Jenkins,则执行jenkins restart,如下
在这里插入图片描述

3、修改端口号

先关闭Jenkins,进入Jenkins的安装目录,可以看到里面有一个jenkins.xml,使用文本编辑器打开它,
在这里插入图片描述
--httpPort的端口改为别的,比如我改成8076
在这里插入图片描述
重新启动Jenkins服务,在浏览器中使用新的端口进行测试,能够正常访问则说明端口修改成功了。
在这里插入图片描述

4、新建账号

Jenkins可能需要多人登录,我们可以新建一些账号供其他人登录。
Jenkins主页的左侧栏中点击Manage Jenkins
在这里插入图片描述
接着点击Manager Users
在这里插入图片描述
然后点击Create User
在这里插入图片描述
输入要创建的新账号的账号密码,点击创建即可,
在这里插入图片描述
创建成功,可以看到多了一个账号了,
在这里插入图片描述
我们可以退出当前账号,使用这个新账号登录,
在这里插入图片描述
登录成功,
在这里插入图片描述

5、修改密码

点击账号的齿轮按钮,
在这里插入图片描述
修改Password,点击Save即可,
在这里插入图片描述

6、安装插件

6.1、方式一:通过Manage Plugins安装(需要科学上网)

Manage Jenkins页面中,点击Manage Plugins
在这里插入图片描述
搜索需要的插件名称进行安装即可(需要能科学上网才行)
在这里插入图片描述

6.2、方式二:CLI命令行安装(需要科学上网)

Jenkins CLI就是Jenkins的命令行工具,类似于MacOS的终端。
我们可以在JenkinsManage Jenkins页面中看到Jenkins CLI,点击进入,
在这里插入图片描述
点击jenkins-cli.jar
在这里插入图片描述
把下载下来的jenkins-cli.jar放到Jenkins安装目录中,
在这里插入图片描述
接着我们就可以通过命令来操作Jenkins了,具体命令参数可以看Jenkins CLI页面,
在这里插入图片描述
我们可以看到安装插件的参数是install-plugin
在这里插入图片描述
点击去可以看到具体的使用方法,
在这里插入图片描述
我们进入jenkins-cli.jar所在的目录,通过下面的命令即可安装插件,(注意端口根据你的Jenkins的实际端口号而定)

java -jar jenkins-cli.jar -s http://localhost:8075/ 插件名

如果不清楚插件名可以上Jenkins的插件官网查看:https://plugins.jenkins.io/
在这里插入图片描述
Maven Integration插件为例,搜索Maven Integration,点击搜索到的插件,
在这里插入图片描述
点击Releases页面,即可看到,插件名就是maven-plugin:3.12
在这里插入图片描述
对应的插件安装命令就是:

java -jar jenkins-cli.jar -s http://localhost:8075/ maven-plugin:3.12

注意,你可能会提示

ERROR: anonymous is missing the Overall/Read permission

我们需要在Configure Global Security中勾选项目矩阵授权策略,给Anonymous添加Administer权限即可。
在这里插入图片描述

6.3、方式三:离线环境安装插件

上面两种方式都需要联网,而我们有可能需要把Jenkins部署在离线环境的电脑上(比如内网),这个时候就只能通过离线安装的方式了。
这个时候,我们需要先在有网络(能科学上网)的电脑上下载安装插件。
安装好的插件可以在这个目录中找到:
C:\\Windows\\System32\\config\\systemprofile\\AppData\\Local\\Jenkins\\.jenkins\\plugins
在这里插入图片描述
将其拷贝到内网机的相同路径中,然后重启Jenkins即可。

7、创建并执行任务:Hello World

我以创建一个HelloWorld任务为例来演示一下。
点击New Item
在这里插入图片描述
输入任务名,比如HelloWorld,点击Freesytyle project,点击OK
在这里插入图片描述
输入任务描述,
在这里插入图片描述
Build选项选择Execute Windows batch command(即批处理,也就是我们说的bat
在这里插入图片描述
然后在Command中编写我们要执行的bat命令,比如

echo "Hello World"

如下
在这里插入图片描述
最后点击保存,
在这里插入图片描述
这样我们的任务就创建成功了,我们可以点击Build Now来执行这个任务,
在这里插入图片描述
F5刷新一下浏览器,可以看到任务执行的进度,
在这里插入图片描述
执行完后我们可以查看对应的日志,
在这里插入图片描述
从日志中我们可以看到我们输出的Hello World
在这里插入图片描述

8、执行带参数的任务

有时候我们需要创建带参数的任务。
我们勾选This project is parameterized,然后点击Add Parameter,可以看到它提供了多种类型的参数,
在这里插入图片描述
我以选择项参数为例,
在这里插入图片描述
分别填写参数名、选项(每个选项一行)、描述,
在这里插入图片描述
编写bat命令,
在这里插入图片描述
点击Build with Parameters,然后设置好参数,
在这里插入图片描述
最后点击Build
在这里插入图片描述
执行完毕可以看到输出日志,结果正确,
在这里插入图片描述

9、执行python任务

我们看到任务Build中并没有Phython的选项,
在这里插入图片描述
但我们又想要让Jenkins可以执行Python,怎么办呢?很简单,在batcall python就好啦,
在这里插入图片描述
其中python代码如下:

print("Hello, I am python")

最后执行任务,输出日志如下,结果正确,
在这里插入图片描述

10、周期性触发执行任务

有时候我们需要周期性地执行任务,比如每天8点触发一次执行任务,或者每隔30分钟触发一次执行任务。
Build Triggers(触发器)中勾选Build periodically
在这里插入图片描述
然后在Schedule中编写规则。
格式:
MINUTE HOUR DOM MONTH DOW

字段说明取值范围
MINUTE分钟0~59
HOUR小时0~23
DOM一个月中的第几天1~31
MONTH1~12
DOW星期0~7(0和7代表的都是周日)

语法:
*:匹配范围内所有值,例:* * * * *
M-N:匹配M~N范围内所有值,例:10-30 * * * *
M-N/X:在指定M~N范围内每隔X构建一次,例:10-30/5 * * * *
*/X:整个有效区间内每隔X构建一次,例:*/30 * * * *
A,B,...,Z:匹配多个值,例:10,20,30 * * * *

关于符号H:
为了在系统中生成定时任务,符号H(代表Hash,后面用散列代替)应该用在可能用到的地方,例如:为十几个日常任务配置0 0 * * *将会在午夜产生较大峰值。相比之下,配置H H * * *仍将每天一次执行每个任务,不是都在同一时刻,可以更好的使用有限资源。

符号H可用于范围,例如,H H(0-7) * * *代表凌晨0:00到 上午7:59一段时间。

符号H在一定范围内可被认为是一个随机值,但实际上它是任务名称的一个散列而不是随机函数。

案例:
30分钟构建一次

H/30 * * * *

2小时构建一次

H H/2 * * *

每天早上8点构建一次

0 8 * * *

每天的8点12点22点,一天构建3

0 8,12,22 * * *

每前半小时中每隔10分钟构建一次

H(0-29)/10 * * * *

每个工作日从早上9点45分开始到下午4点45分结束这段时间内每间隔2小时45分钟那一刻构建一次

45 9-16/2 * * 1-5

每月(除了12月)从1号15号这段时间内某刻构建一次

H H 1,15 1-11 *

好了,案例就列举这么多了。

现在,为了演示,我设置为每隔1分钟执行一次,
在这里插入图片描述
命令如下,
在这里插入图片描述
可以看到它每分钟就触发执行一次任务,
在这里插入图片描述

在这里插入图片描述

五、实战:Unity + Jenkins

下面我演示一下通过Jenkins来调用Unity打包androidAPK
我先画个流程图,方便大家理解:
在这里插入图片描述

现在,我们开始吧。

1、Unity Demo工程

1.1、创建Demo工程

创建一个Unity工程,
在这里插入图片描述
简单弄点东西,
在这里插入图片描述

1.2、切换Android平台

点击 File / Build Settings菜单,切换成Android平台,
在这里插入图片描述

1.3、设置JDK、Android SDK、Gradle

点击Edit / Preferences,在External Tools中设置好JDKAndroid SDKGradle
在这里插入图片描述

1.4、设置包名

Player Settings中设置一下包名,比如com.linxinfa.test
在这里插入图片描述

1.5、测试打包

添加要打包的场景,手动点击Build,测试一下是否能正常打出APK
在这里插入图片描述
可以正常打出APK,说明打包环境设置都正确,
在这里插入图片描述

2、编写Editor打包工具

2.1、Editor打包工具代码

新建一个Editor文件夹,
在这里插入图片描述
Editor文件夹中新建一个BuildTools脚本,
在这里插入图片描述
BuildTools.cs脚本代码如下:

using UnityEngine;
using UnityEditor;

public class BuildTools 
{
    [MenuItem("Build/Build APK")]
    public static void BuildApk()
    {
        BuildPlayerOptions opt = new BuildPlayerOptions();
        opt.scenes = new string[] { "Assets/Scenes/SampleScene.unity" };
        opt.locationPathName = Application.dataPath + "/../Bin/test.apk";
        opt.target = BuildTarget.Android;
        opt.options = BuildOptions.None;

        BuildPipeline.BuildPlayer(opt);

        Debug.Log("Build App Done!");
    }
}
2.2、执行Editor打包工具菜单

点击菜单Build / Build Apk
在这里插入图片描述
可以正常打出APK
在这里插入图片描述

3、命令行调用Unity静态函数:打包函数

3.1、Unity命令行模式

Unity提供了命令行模式给开发者,我们可以写bat脚本来调用Unity中的静态函数,比如我们的打包函数。
格式:
Unity程序 -参数 -projectPath 工程地址 -executeMethod 静态函数
例:

"D:\\software\\Unity\\2021.1.7f1c1\\Editor\\Unity.exe" ^
-quit ^
-batchmode ^
-projectPath "E:\\UnityProject\\UnityDemo" ^
-executeMethod BuildTools.BuildApk  ^
-logFile "E:\\UnityProject\\UnityDemo\\output.log"

注:为了阅读方便,命令我写成多行,在bat中连接多行的符号是^

我们可以在Unity官方手册看到具体的命令参数说明:https://docs.unity3d.com/Manual/CommandLineArguments.html
在这里插入图片描述

3.2、命令参数解释

-batchmode
在 批处理模式下运行Unity,它不会弹出窗口。当脚本代码在执行过程中发生异常或其他操作失败时Unity将立即退出,并返回代码为1

-quit
命令执行完毕后将退出Unity编辑器。请注意,这可能会导致错误消息被隐藏(但他们将显示在Editor.log文件)

-buildWindowsPlayer <pathname>
构建一个32位Windows平台的exe(例如:-buildWindowsPlayer path/to/your/build.exe

-buildWindows64Player <pathname>
构建一个64位Windows平台的exe(例如:-buildWindows64Player path/to/your/build.exe

-importPackage <pathname>
导入一个的package,不会显示导入对话框

-createProject <pathname>
根据提供的路径建立一个空项目

-projectPath <pathname>
打开指定路径的项目

-logFile <pathname>
指定输出的日志文件

-nographics
当运行在批处理模式,不会初始化显卡设备,不需要GPU参与;但如果你需要执行光照烘焙等操作,则不能使用这个参数,因为它需要GPU运算。

-executeMethod <ClassName.MethodName>
Unity启动的同时会执行静态方法。也就是说,使用executeMethod我们需要在编辑文件夹有一个脚本并且类里有一个静态函数。

-single-instance
在同一时间只允许一个游戏实例运行。如果另一个实例已在运行,然后再次通过-single-instance启动它的话会调节到现有的这个实例。

-nolog
不产生输出日志。 通常output_log.txt被写在游戏输出目录下的*_Data文件夹中。

3.3、批处理脚本

我们知道,一个Unity工程只能打开一个实例,所以如果我们已经手动用Unity打开了工程,此时执行下面这个命令是会报错的,

"D:\\software\\Unity\\2021.1.7f1c1\\Editor\\Unity.exe" ^
-quit ^
-batchmode ^
-projectPath "E:\\UnityProject\\UnityDemo" ^
-executeMethod BuildTools.BuildApk ^

报错如下:

Aborting batchmode due to fatal error:
It looks like another Unity instance is running with this project open.
Multiple Unity instances cannot open the same project.

我们需要先判断Unity是否在运行中,如果是,则先将旧的Unity实例进程杀掉,对应的bat代码如下:

::判断Unity是否运行中
TASKLIST /V /S localhost /U %username%>tmp_process_list.txt
TYPE tmp_process_list.txt |FIND "Unity.exe"
 
IF ERRORLEVEL 0 (GOTO UNITY_IS_RUNNING)
ELSE (GOTO START_UNITY)
 
:UNITY_IS_RUNNING
::杀掉Unity
TASKKILL /F /IM Unity.exe
::停1秒
PING 127.0.0.1 -n 1 >NUL
GOTO START_UNITY

:START_UNITY
:: 此处执行Unity打包

另外,我们想要在执行打包时传入一些参数,比如APP名字版本号等,可以在命令中加上,格式可以自定义,我们只需在后面的C#代码中进行相应的解析即可,例:

--productName:%1 --version:%2

其中%1表示参数1%2表示参数2
完整命令如下:

"D:\\software\\Unity\\2021.1.7f1c1\\Editor\\Unity.exe" ^
-quit ^
-batchmode ^
-projectPath "E:\\UnityProject\\UnityDemo" ^
-executeMethod BuildTools.BuildApk ^
--productName:%1 ^
--version:%2

整合上面的Unity进程判断,最终完整的bat代码如下:

::判断Unity是否运行中
TASKLIST /V /S localhost /U %username%>tmp_process_list.txt
TYPE tmp_process_list.txt |FIND "Unity.exe"
 
IF ERRORLEVEL 0 (GOTO UNITY_IS_RUNNING)
ELSE (GOTO START_UNITY)
 
:UNITY_IS_RUNNING
::杀掉Unity
TASKKILL /F /IM Unity.exe
::停1秒
PING 127.0.0.1 -n 1 >NUL
GOTO START_UNITY

:START_UNITY
:: 此处执行Unity打包
"D:\\software\\Unity\\2021.1.7f1c1\\Editor\\Unity.exe" ^
-quit ^
-batchmode ^
-projectPath "E:\\UnityProject\\UnityDemo" ^
-executeMethod BuildTools.BuildApk ^
-logFile "E:\\UnityProject\\UnityDemo\\output.log" ^
--productName:%1 ^
--version:%2

将上面的bat代码保存为build_app.bat,我们通过命令行去执行这个build_app.bat,如下:
在这里插入图片描述
可以看到此时能打出APK
在这里插入图片描述
在输出的日志文件中我们也可以看到我们Debug.Log输出的日志,
在这里插入图片描述

3.4、Unity打包工具接收命令行参数

虽然我们上面的bat脚本传递了包名和版本号两个参数,但是我们在Unity的打包工具中并没有对这两个参数进行解析,现在,我们补上解析参数的逻辑吧。

// 解析命令行参数
string[] args = System.Environment.GetCommandLineArgs();
foreach (var s in args)
{
    if (s.Contains("--productName:"))
    {
        string productName= s.Split(':')[1];
        // 设置app名字
        PlayerSettings.productName = productName;
    }

    if (s.Contains("--version:"))
    {
        string version = s.Split(':')[1];
        // 设置版本号
        PlayerSettings.bundleVersion = version;
    }
}

打包工具完整代码如下:

// BuildTools.cs
using UnityEngine;
using UnityEditor;

public class BuildTools
{
    [MenuItem("Build/Build APK")]
    public static void BuildApk()
    {
        // 解析命令行参数
        string[] args = System.Environment.GetCommandLineArgs();
        foreach (var s in args)
        {
            if (s.Contains("--productName:"))
            {
                string productName= s.Split(':')[1];
                // 设置app名字
                PlayerSettings.productName = productName;
            }

            if (s.Contains("--version:"))
            以上是关于游戏开发进阶教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)的主要内容,如果未能解决你的问题,请参考以下文章

游戏开发进阶教你自制离线Maven仓库,实现Unity离线环境使用Gradle打包(Unity | Android | 谷歌 | Gradle)

游戏开发进阶教你自制离线Maven仓库,实现Unity离线环境使用Gradle打包(Unity | Android | 谷歌 | Gradle)

游戏开发进阶篇教你在Windows平台编译tolua runtime的各个平台库(Unity | 热更新 | tolua | 交叉编译)

游戏开发进阶篇教你在Windows平台编译tolua runtime的各个平台库(Unity | 热更新 | tolua | 交叉编译)

演讲实录 | 手把手教你Jenkins开发进阶,加速DevOps落地

unity游戏自定义分辨率 教你如何自定义