文章目录

  • 一、前言
  • 二、Jenkins简介
  • 三、Jenkins的下载与安装
  • 1、JDK下载与安装
  • 2、Jenkins下载
  • 3、Jenkins安装
  • 4、Jenkins初始化
  • 四、Jenkins的基本操作
  • 1、关闭Jenkins
  • 1.1、方式一:暴力杀进程(不推荐)
  • 1.2、方式二:以管理员身份执行 net stop jenkins
  • 1.3、方式三:通过jenkins.exe来关闭,jenkins stop
  • 2、启动Jenkins
  • 2.1、方式一:以管理员身份执行 net start jenkins
  • 2.2、方式二:通过jenkins.exe来启动,jenkins start
  • 3、修改端口号
  • 4、新建账号
  • 5、修改密码
  • 6、安装插件
  • 6.1、方式一:通过Manage Plugins安装(需要科学上网)
  • 6.2、方式二:CLI命令行安装(需要科学上网)
  • 6.3、方式三:离线环境安装插件
  • 7、创建并执行任务:Hello World
  • 8、执行带参数的任务
  • 9、执行python任务
  • 10、周期性触发执行任务
  • 五、实战:Unity + Jenkins
  • 1、Unity Demo工程
  • 1.1、创建Demo工程
  • 1.2、切换Android平台
  • 1.3、设置JDK、Android SDK、Gradle
  • 1.4、设置包名
  • 1.5、测试打包
  • 2、编写Editor打包工具
  • 2.1、Editor打包工具代码
  • 2.2、执行Editor打包工具菜单
  • 3、命令行调用Unity静态函数:打包函数
  • 3.1、Unity命令行模式
  • 3.2、命令参数解释
  • 3.3、批处理脚本
  • 3.4、Unity打包工具接收命令行参数
  • 4、Jenkins调用bat脚本
  • 5、拓展:python加强版脚本
  • 六、完毕


一、前言

嗨,大家好,我是新发。

前几天我写了一篇文章,【游戏开发进阶】教你自制离线Maven仓库,实现Unity离线环境使用Gradle打包(Unity | Android | 谷歌 | Gradle),里面我提到了Unity使用Jenkins实现自动化打包,

unity Windows 自动构建 ios unity 自动化_unity


不过那篇文章中我只是一笔带过,没有细说具体操作流程。今天,我就专门写一篇关于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下载,

unity Windows 自动构建 ios unity 自动化_python_02


下载下来后双击即可执行安装,安装过程没什么,这里就不啰嗦了。

安装完毕后,配置一下JDK环境变量

最后在命令行中输入java -version,如果能正常输出版本号,则说明JDK环境弄好了。

unity Windows 自动构建 ios unity 自动化_jenkins_03

2、Jenkins下载

进入Jenkins官网:https://www.jenkins.io/ 点击Download

unity Windows 自动构建 ios unity 自动化_自动化_04


根据你的系统和环境选择对应的安装包,因为我是Windows系统,所以我下载Windows版的安装包,

unity Windows 自动构建 ios unity 自动化_unity_05


下载下来是一个msi文件,

unity Windows 自动构建 ios unity 自动化_jenkins_06

3、Jenkins安装

双击jenkins.msi,执行安装,设置一下安装路径,

unity Windows 自动构建 ios unity 自动化_jenkins_07


选择Run service as LocalSystem(即使用本地系统账号)

unity Windows 自动构建 ios unity 自动化_unity_08


设置端口号,比如我设置为8075,然后点击Test Port按钮测试一下端口有没有被占用,

unity Windows 自动构建 ios unity 自动化_python_09


确认端口没被占用后,点击Next

unity Windows 自动构建 ios unity 自动化_自动化_10


设置JDK所在的路径,

unity Windows 自动构建 ios unity 自动化_自动化_11


继续Next

unity Windows 自动构建 ios unity 自动化_unity_12


点击Install开始安装,

unity Windows 自动构建 ios unity 自动化_jenkins_13


注意,安装过程中可能会弹出360提醒,选择允许即可。

完整完毕,

unity Windows 自动构建 ios unity 自动化_python_14

4、Jenkins初始化

上面安装完毕后会自动启动Jenkins服务,我们可以在任务管理器中看到一个Java的进程,它就是Jenkins的服务进程。

unity Windows 自动构建 ios unity 自动化_打包_15


我们在浏览器中访问 http://localhost:8075,此时会显示需要解锁Jenkins,如下

unity Windows 自动构建 ios unity 自动化_unity_16


我们找到这个initialAdminPassword文件,使用文本编辑器打开它,

unity Windows 自动构建 ios unity 自动化_jenkins_17


可以看到里面是一串密码,我们复制它,

unity Windows 自动构建 ios unity 自动化_python_18


回到浏览器页面中,在管理员密码栏中粘贴刚刚的密码,然后点击继续,

unity Windows 自动构建 ios unity 自动化_python_19


接下来是插件安装界面,因为Jenkins插件的下载需要翻墙,所以如果你可以科学上网,则点击安装推荐的插件,当然也可以先不安装插件,后续有需要再安装对应的插件即可,

unity Windows 自动构建 ios unity 自动化_unity_20


如果是离线环境(比如内网环境),则点击跳过插件安装(下文我会教如何在离线环境下安装插件),

unity Windows 自动构建 ios unity 自动化_python_21


接着创建管理员账号,

unity Windows 自动构建 ios unity 自动化_打包_22


完成,进入Jenkins主页,

unity Windows 自动构建 ios unity 自动化_jenkins_23

四、Jenkins的基本操作

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

上面我们说到,在任务管理器中可以看到一个Java进程,它就是Jenkins的服务进程,

unity Windows 自动构建 ios unity 自动化_打包_15


如果你直接暴力杀掉这个Java进程,那么Jenkins也就关闭了,不过不建议这么做。

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

以管理员身份运行命令net stop jenkins,如下(我是使用管理员身份运行PowerShell来执行命令的)

unity Windows 自动构建 ios unity 自动化_python_25

注意,如果你不是以管理员身份执行上面的命令,则会提示发生系统错误 5 如下(普通账号权限下通过cmd执行命令)

unity Windows 自动构建 ios unity 自动化_unity_26

如何以管理员身份运行cmd?

进入

cmd

所在目录:

C:\Users\linxinfa\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\System Tools

unity Windows 自动构建 ios unity 自动化_jenkins_27


右键

命令提示符

,点击

以管理员身份运行

即可,


unity Windows 自动构建 ios unity 自动化_python_28


如果觉得麻烦的话,也可以直接在系统的开始菜单那里直接以管理员身份运行

PowerShell


unity Windows 自动构建 ios unity 自动化_自动化_29

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

进入Jenkins的安装目录,如下,

unity Windows 自动构建 ios unity 自动化_unity_30


在地址栏输入cmd,然后执行jenkins stop,如下,与上面的效果是一样的,

unity Windows 自动构建 ios unity 自动化_python_31

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

以管理员身份执行命令net start jenkins,如下

unity Windows 自动构建 ios unity 自动化_unity_32

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

进入Jenkins的安装目录,

unity Windows 自动构建 ios unity 自动化_unity_30


执行命令jenkins start,如下

unity Windows 自动构建 ios unity 自动化_自动化_34


如果想重启Jenkins,则执行jenkins restart,如下

unity Windows 自动构建 ios unity 自动化_jenkins_35

3、修改端口号

先关闭Jenkins,进入Jenkins的安装目录,可以看到里面有一个jenkins.xml,使用文本编辑器打开它,

unity Windows 自动构建 ios unity 自动化_jenkins_36


--httpPort的端口改为别的,比如我改成8076

unity Windows 自动构建 ios unity 自动化_python_37


重新启动Jenkins服务,在浏览器中使用新的端口进行测试,能够正常访问则说明端口修改成功了。

unity Windows 自动构建 ios unity 自动化_python_38

4、新建账号

Jenkins可能需要多人登录,我们可以新建一些账号供其他人登录。

Jenkins主页的左侧栏中点击Manage Jenkins

unity Windows 自动构建 ios unity 自动化_打包_39


接着点击Manager Users

unity Windows 自动构建 ios unity 自动化_unity_40


然后点击Create User

unity Windows 自动构建 ios unity 自动化_python_41


输入要创建的新账号的账号密码,点击创建即可,

unity Windows 自动构建 ios unity 自动化_unity_42


创建成功,可以看到多了一个账号了,

unity Windows 自动构建 ios unity 自动化_打包_43


我们可以退出当前账号,使用这个新账号登录,

unity Windows 自动构建 ios unity 自动化_jenkins_44


登录成功,

unity Windows 自动构建 ios unity 自动化_打包_45

5、修改密码

点击账号的齿轮按钮,

unity Windows 自动构建 ios unity 自动化_unity_46


修改Password,点击Save即可,

unity Windows 自动构建 ios unity 自动化_自动化_47

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

Manage Jenkins页面中,点击Manage Plugins

unity Windows 自动构建 ios unity 自动化_unity_48


搜索需要的插件名称进行安装即可(需要能科学上网才行)

unity Windows 自动构建 ios unity 自动化_python_49

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

Jenkins CLI就是Jenkins的命令行工具,类似于MacOS的终端。

我们可以在JenkinsManage Jenkins页面中看到Jenkins CLI,点击进入,

unity Windows 自动构建 ios unity 自动化_自动化_50


点击jenkins-cli.jar

unity Windows 自动构建 ios unity 自动化_自动化_51


把下载下来的jenkins-cli.jar放到Jenkins安装目录中,

unity Windows 自动构建 ios unity 自动化_自动化_52


接着我们就可以通过命令来操作Jenkins了,具体命令参数可以看Jenkins CLI页面,

unity Windows 自动构建 ios unity 自动化_python_53


我们可以看到安装插件的参数是install-plugin

unity Windows 自动构建 ios unity 自动化_自动化_54


点击去可以看到具体的使用方法,

unity Windows 自动构建 ios unity 自动化_unity_55


我们进入jenkins-cli.jar所在的目录,通过下面的命令即可安装插件,(注意端口根据你的Jenkins的实际端口号而定)

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

如果不清楚插件名可以上Jenkins的插件官网查看:https://plugins.jenkins.io/

unity Windows 自动构建 ios unity 自动化_python_56


Maven Integration插件为例,搜索Maven Integration,点击搜索到的插件,

unity Windows 自动构建 ios unity 自动化_python_57


点击Releases页面,即可看到,插件名就是maven-plugin:3.12

unity Windows 自动构建 ios unity 自动化_python_58


对应的插件安装命令就是:

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权限即可。

unity Windows 自动构建 ios unity 自动化_unity_59

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

上面两种方式都需要联网,而我们有可能需要把Jenkins部署在离线环境的电脑上(比如内网),这个时候就只能通过离线安装的方式了。

这个时候,我们需要先在有网络(能科学上网)的电脑上下载安装插件。

安装好的插件可以在这个目录中找到:

C:\Windows\System32\config\systemprofile\AppData\Local\Jenkins\.jenkins\plugins

unity Windows 自动构建 ios unity 自动化_打包_60


将其拷贝到内网机的相同路径中,然后重启Jenkins即可。

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

我以创建一个HelloWorld任务为例来演示一下。

点击New Item

unity Windows 自动构建 ios unity 自动化_打包_61


输入任务名,比如HelloWorld,点击Freesytyle project,点击OK

unity Windows 自动构建 ios unity 自动化_自动化_62


输入任务描述,

unity Windows 自动构建 ios unity 自动化_python_63


Build选项选择Execute Windows batch command(即批处理,也就是我们说的bat

unity Windows 自动构建 ios unity 自动化_unity_64


然后在Command中编写我们要执行的bat命令,比如

echo "Hello World"

如下

unity Windows 自动构建 ios unity 自动化_unity_65


最后点击保存,

unity Windows 自动构建 ios unity 自动化_unity_66


这样我们的任务就创建成功了,我们可以点击Build Now来执行这个任务,

unity Windows 自动构建 ios unity 自动化_unity_67


F5刷新一下浏览器,可以看到任务执行的进度,

unity Windows 自动构建 ios unity 自动化_自动化_68


执行完后我们可以查看对应的日志,

unity Windows 自动构建 ios unity 自动化_jenkins_69


从日志中我们可以看到我们输出的Hello World

unity Windows 自动构建 ios unity 自动化_unity_70

8、执行带参数的任务

有时候我们需要创建带参数的任务。

我们勾选This project is parameterized,然后点击Add Parameter,可以看到它提供了多种类型的参数,

unity Windows 自动构建 ios unity 自动化_打包_71


我以选择项参数为例,

unity Windows 自动构建 ios unity 自动化_python_72


分别填写参数名、选项(每个选项一行)、描述,

unity Windows 自动构建 ios unity 自动化_python_73


编写bat命令,

unity Windows 自动构建 ios unity 自动化_jenkins_74


点击Build with Parameters,然后设置好参数,

unity Windows 自动构建 ios unity 自动化_自动化_75


最后点击Build

unity Windows 自动构建 ios unity 自动化_打包_76


执行完毕可以看到输出日志,结果正确,

unity Windows 自动构建 ios unity 自动化_python_77

9、执行python任务

我们看到任务Build中并没有Phython的选项,

unity Windows 自动构建 ios unity 自动化_打包_78


但我们又想要让Jenkins可以执行Python,怎么办呢?很简单,在batcall python就好啦,

unity Windows 自动构建 ios unity 自动化_打包_79


其中python代码如下:

print("Hello, I am python")

最后执行任务,输出日志如下,结果正确,

unity Windows 自动构建 ios unity 自动化_自动化_80

10、周期性触发执行任务

有时候我们需要周期性地执行任务,比如每天8点触发一次执行任务,或者每隔30分钟触发一次执行任务。

Build Triggers(触发器)中勾选Build periodically

unity Windows 自动构建 ios unity 自动化_打包_81


然后在Schedule中编写规则。

格式:

MINUTE HOUR DOM MONTH DOW

字段

说明

取值范围

MINUTE

分钟

0~59

HOUR

小时

0~23

DOM

一个月中的第几天

1~31

MONTH


1~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 Windows 自动构建 ios unity 自动化_unity_82


命令如下,

unity Windows 自动构建 ios unity 自动化_jenkins_83


可以看到它每分钟就触发执行一次任务,

unity Windows 自动构建 ios unity 自动化_打包_84

unity Windows 自动构建 ios unity 自动化_unity_85

五、实战:Unity + Jenkins

下面我演示一下通过Jenkins来调用Unity打包AndroidAPK

我先画个流程图,方便大家理解:

unity Windows 自动构建 ios unity 自动化_unity_86

现在,我们开始吧。

1、Unity Demo工程
1.1、创建Demo工程

创建一个Unity工程,

unity Windows 自动构建 ios unity 自动化_自动化_87


简单弄点东西,

unity Windows 自动构建 ios unity 自动化_unity_88

1.2、切换Android平台

点击 File / Build Settings菜单,切换成Android平台,

unity Windows 自动构建 ios unity 自动化_jenkins_89

1.3、设置JDK、Android SDK、Gradle

点击Edit / Preferences,在External Tools中设置好JDKAndroid SDKGradle

unity Windows 自动构建 ios unity 自动化_jenkins_90

1.4、设置包名

Player Settings中设置一下包名,比如com.linxinfa.test

unity Windows 自动构建 ios unity 自动化_jenkins_91

1.5、测试打包

添加要打包的场景,手动点击Build,测试一下是否能正常打出APK

unity Windows 自动构建 ios unity 自动化_python_92


可以正常打出APK,说明打包环境设置都正确,

unity Windows 自动构建 ios unity 自动化_jenkins_93

2、编写Editor打包工具
2.1、Editor打包工具代码

新建一个Editor文件夹,

unity Windows 自动构建 ios unity 自动化_unity_94


Editor文件夹中新建一个BuildTools脚本,

unity Windows 自动构建 ios unity 自动化_打包_95


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

unity Windows 自动构建 ios unity 自动化_自动化_96


可以正常打出APK

unity Windows 自动构建 ios unity 自动化_jenkins_93

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

unity Windows 自动构建 ios unity 自动化_python_98

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,如下:

unity Windows 自动构建 ios unity 自动化_打包_99


可以看到此时能打出APK

unity Windows 自动构建 ios unity 自动化_jenkins_93


在输出的日志文件中我们也可以看到我们Debug.Log输出的日志,

unity Windows 自动构建 ios unity 自动化_unity_101

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:"))
            {
                string version = s.Split(':')[1];
                // 设置版本号
                PlayerSettings.bundleVersion = version;
            }
        }
       
        // 执行打包
        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!");
    }
}

重新执行命令:

unity Windows 自动构建 ios unity 自动化_打包_99


然后我们安装一下APK,看看APP名字是不是哈哈哈

unity Windows 自动构建 ios unity 自动化_自动化_103


在应用信息里可以看到版本号也是我们命令行中设置的1.2.0.0

unity Windows 自动构建 ios unity 自动化_unity_104

4、Jenkins调用bat脚本

我们回到Jenkins页面中,创建一个带参数的任务,

appName参数:

unity Windows 自动构建 ios unity 自动化_python_105

version参数:

unity Windows 自动构建 ios unity 自动化_python_106


命令行:

E:\UnityProject\UnityDemo\bat\build_app.bat %appName% %version%,如下:

unity Windows 自动构建 ios unity 自动化_python_107


执行Jenkins任务,如下:

unity Windows 自动构建 ios unity 自动化_jenkins_108


等等运行结果:

unity Windows 自动构建 ios unity 自动化_jenkins_109


执行完毕,我们看下输出的日志,

unity Windows 自动构建 ios unity 自动化_自动化_110


可以看到我们的bat脚本被正确执行了,参数也传递正确,

unity Windows 自动构建 ios unity 自动化_unity_111


APK也可以正常生成,

unity Windows 自动构建 ios unity 自动化_jenkins_93


安装到模拟器上,可以看到名字正确,

unity Windows 自动构建 ios unity 自动化_python_113


版本号也正确,

unity Windows 自动构建 ios unity 自动化_自动化_114


流程走通了,剩下的就是根据自己的需求进行扩展啦,比如打包前先执行一下svn更新之类的,需要额外参数,就在Jenkins中添加,传递到bat脚本中,再传递到Unity中,最后根据参数进行打包。

5、拓展:python加强版脚本

我个人其实不是特别喜欢写bat脚本,我更喜欢写pytho,于是,我就写了个python版的脚本,脚本中我加了监控Unity日志输出的逻辑,方便进行一些判断,画个图:

unity Windows 自动构建 ios unity 自动化_自动化_115


python完整代码如下:

import os
import sys
import time
 
# 设置你本地的Unity安装目录
unity_exe = 'D:/software/Unity/2021.1.7f1c1/Editor/Unity.exe'
# unity工程目录,当前脚本放在unity工程根目录中
project_path = 'E:/UnityProject/UnityDemo'
# 日志
log_file = os.getcwd() + '/unity_log.log'
 
static_func = 'BuildTools.BuildApk'
 
# 杀掉unity进程
def kill_unity():
    os.system('taskkill /IM Unity.exe /F')
 
def clear_log():
    if os.path.exists(log_file):
        os.remove(log_file)
 
# 调用unity中我们封装的静态函数
def call_unity_static_func(func):
    kill_unity()
    time.sleep(1)
    clear_log()
    time.sleep(1)
    cmd = 'start %s -quit -batchmode -projectPath %s -logFile %s -executeMethod %s --productName:%s --version:%s'%(unity_exe,project_path,log_file,func, sys.argv[1], sys.argv[2])
    print('run cmd:  ' + cmd)
    os.system(cmd)
 
    
 
# 实时监测unity的log, 参数target_log是我们要监测的目标log, 如果检测到了, 则跳出while循环    
def monitor_unity_log(target_log):
    pos = 0
    while True:
        if os.path.exists(log_file):
            break
        else:
            time.sleep(0.1) 
    while True:
        fd = open(log_file, 'r', encoding='utf-8')
        if 0 != pos:
            fd.seek(pos, 0)
        while True:
            line = fd.readline()
            pos = pos + len(line)
            if target_log in line:
                print(u'监测到unity输出了目标log: ' + target_log)
                fd.close()
                return
            if line.strip():
                print(line)
            else:
                break
        fd.close()
 
if __name__ == '__main__':
    call_unity_static_func(static_func)
    monitor_unity_log('Build App Done!')
    print('done')

我们把脚本保存为build_app.py

unity Windows 自动构建 ios unity 自动化_自动化_116


Jenkins中的命令改为执行python脚本:

call python E:\UnityProject\UnityDemo\bat\build_app.py %appName% %version% 如下:

unity Windows 自动构建 ios unity 自动化_打包_117


执行一下任务,

unity Windows 自动构建 ios unity 自动化_unity_118


耐心等待执行结果,

unity Windows 自动构建 ios unity 自动化_unity_119


执行完毕可以看到监控到的日志,

unity Windows 自动构建 ios unity 自动化_打包_120


我们在python中输出的日志都可以在JenkinsConsole Output中看到,

unity Windows 自动构建 ios unity 自动化_python_121


APK顺利生成,Very Good,完美~

unity Windows 自动构建 ios unity 自动化_unity_122