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

文章目录

      • 一、前言
      • 二、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通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第1张图片
不过那篇文章中我只是一笔带过,没有细说具体操作流程。今天,我就专门写一篇关于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通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第2张图片
下载下来后双击即可执行安装,安装过程没什么,这里就不啰嗦了。
安装完毕后,配置一下JDK环境变量
最后在命令行中输入java -version,如果能正常输出版本号,则说明JDK环境弄好了。
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第3张图片

2、Jenkins下载

进入Jenkins官网:https://www.jenkins.io/
点击Download
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第4张图片
根据你的系统和环境选择对应的安装包,因为我是Windows系统,所以我下载Windows版的安装包,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第5张图片
下载下来是一个msi文件,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第6张图片

3、Jenkins安装

双击jenkins.msi,执行安装,设置一下安装路径,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第7张图片
选择Run service as LocalSystem(即使用本地系统账号)
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第8张图片
设置端口号,比如我设置为8075,然后点击Test Port按钮测试一下端口有没有被占用,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第9张图片
确认端口没被占用后,点击Next
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第10张图片
设置JDK所在的路径,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第11张图片
继续Next
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第12张图片
点击Install开始安装,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第13张图片
注意,安装过程中可能会弹出360提醒,选择允许即可。
完整完毕,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第14张图片

4、Jenkins初始化

上面安装完毕后会自动启动Jenkins服务,我们可以在任务管理器中看到一个Java的进程,它就是Jenkins的服务进程。
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第15张图片
我们在浏览器中访问 http://localhost:8075,此时会显示需要解锁Jenkins,如下
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第16张图片
我们找到这个initialAdminPassword文件,使用文本编辑器打开它,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第17张图片
可以看到里面是一串密码,我们复制它,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第18张图片
回到浏览器页面中,在管理员密码栏中粘贴刚刚的密码,然后点击继续,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第19张图片
接下来是插件安装界面,因为Jenkins插件的下载需要,所以如果你可以科学上网,则点击安装推荐的插件,当然也可以先不安装插件,后续有需要再安装对应的插件即可,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第20张图片
如果是离线环境(比如内网环境),则点击跳过插件安装(下文我会教如何在离线环境下安装插件),
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第21张图片
接着创建管理员账号,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第22张图片
完成,进入Jenkins主页,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第23张图片

四、Jenkins的基本操作

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

上面我们说到,在任务管理器中可以看到一个Java进程,它就是Jenkins的服务进程,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第24张图片
如果你直接暴力杀掉这个Java进程,那么Jenkins也就关闭了,不过不建议这么做。

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

以管理员身份运行命令net stop jenkins,如下(我是使用管理员身份运行PowerShell来执行命令的)
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第25张图片

注意,如果你不是以管理员身份执行上面的命令,则会提示发生系统错误 5
如下(普通账号权限下通过cmd执行命令)
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第26张图片
如何以管理员身份运行cmd?
进入cmd所在目录:
C:\Users\linxinfa\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\System Tools
在这里插入图片描述
右键命令提示符,点击以管理员身份运行即可,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第27张图片
如果觉得麻烦的话,也可以直接在系统的开始菜单那里直接以管理员身份运行PowerShell
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第28张图片

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

进入Jenkins的安装目录,如下,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第29张图片
在地址栏输入cmd,然后执行jenkins stop,如下,与上面的效果是一样的,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第30张图片

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

以管理员身份执行命令net start jenkins,如下
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第31张图片

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

进入Jenkins的安装目录,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第32张图片
执行命令jenkins start,如下
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第33张图片
如果想重启Jenkins,则执行jenkins restart,如下
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第34张图片

3、修改端口号

先关闭Jenkins,进入Jenkins的安装目录,可以看到里面有一个jenkins.xml,使用文本编辑器打开它,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第35张图片
--httpPort的端口改为别的,比如我改成8076
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第36张图片
重新启动Jenkins服务,在浏览器中使用新的端口进行测试,能够正常访问则说明端口修改成功了。
在这里插入图片描述

4、新建账号

Jenkins可能需要多人登录,我们可以新建一些账号供其他人登录。
Jenkins主页的左侧栏中点击Manage Jenkins
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第37张图片
接着点击Manager Users
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第38张图片
然后点击Create User
在这里插入图片描述
输入要创建的新账号的账号密码,点击创建即可,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第39张图片
创建成功,可以看到多了一个账号了,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第40张图片
我们可以退出当前账号,使用这个新账号登录,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第41张图片
登录成功,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第42张图片

5、修改密码

点击账号的齿轮按钮,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第43张图片
修改Password,点击Save即可,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第44张图片

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

Manage Jenkins页面中,点击Manage Plugins
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第45张图片
搜索需要的插件名称进行安装即可(需要能科学上网才行)
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第46张图片

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

Jenkins CLI就是Jenkins的命令行工具,类似于MacOS的终端。
我们可以在JenkinsManage Jenkins页面中看到Jenkins CLI,点击进入,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第47张图片
点击jenkins-cli.jar
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第48张图片
把下载下来的jenkins-cli.jar放到Jenkins安装目录中,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第49张图片
接着我们就可以通过命令来操作Jenkins了,具体命令参数可以看Jenkins CLI页面,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第50张图片
我们可以看到安装插件的参数是install-plugin
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第51张图片
点击去可以看到具体的使用方法,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第52张图片
我们进入jenkins-cli.jar所在的目录,通过下面的命令即可安装插件,(注意端口根据你的Jenkins的实际端口号而定)

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

如果不清楚插件名可以上Jenkins的插件官网查看:https://plugins.jenkins.io/
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第53张图片
Maven Integration插件为例,搜索Maven Integration,点击搜索到的插件,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第54张图片
点击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权限即可。
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第55张图片

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

上面两种方式都需要联网,而我们有可能需要把Jenkins部署在离线环境的电脑上(比如内网),这个时候就只能通过离线安装的方式了。
这个时候,我们需要先在有网络(能科学上网)的电脑上下载安装插件。
安装好的插件可以在这个目录中找到:
C:\Windows\System32\config\systemprofile\AppData\Local\Jenkins\.jenkins\plugins
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第56张图片
将其拷贝到内网机的相同路径中,然后重启Jenkins即可。

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

我以创建一个HelloWorld任务为例来演示一下。
点击New Item
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第57张图片
输入任务名,比如HelloWorld,点击Freesytyle project,点击OK
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第58张图片
输入任务描述,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第59张图片
Build选项选择Execute Windows batch command(即批处理,也就是我们说的bat
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第60张图片
然后在Command中编写我们要执行的bat命令,比如

echo "Hello World"

如下
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第61张图片
最后点击保存,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第62张图片
这样我们的任务就创建成功了,我们可以点击Build Now来执行这个任务,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第63张图片
F5刷新一下浏览器,可以看到任务执行的进度,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第64张图片
执行完后我们可以查看对应的日志,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第65张图片
从日志中我们可以看到我们输出的Hello World
在这里插入图片描述

8、执行带参数的任务

有时候我们需要创建带参数的任务。
我们勾选This project is parameterized,然后点击Add Parameter,可以看到它提供了多种类型的参数,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第66张图片
我以选择项参数为例,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第67张图片
分别填写参数名、选项(每个选项一行)、描述,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第68张图片
编写bat命令,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第69张图片
点击Build with Parameters,然后设置好参数,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第70张图片
最后点击Build
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第71张图片
执行完毕可以看到输出日志,结果正确,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第72张图片

9、执行python任务

我们看到任务Build中并没有Phython的选项,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第73张图片
但我们又想要让Jenkins可以执行Python,怎么办呢?很简单,在batcall python就好啦,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第74张图片
其中python代码如下:

print("Hello, I am python")

最后执行任务,输出日志如下,结果正确,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第75张图片

10、周期性触发执行任务

有时候我们需要周期性地执行任务,比如每天8点触发一次执行任务,或者每隔30分钟触发一次执行任务。
Build Triggers(触发器)中勾选Build periodically
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第76张图片
然后在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通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第77张图片
命令如下,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第78张图片
可以看到它每分钟就触发执行一次任务,
在这里插入图片描述

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

五、实战:Unity + Jenkins

下面我演示一下通过Jenkins来调用Unity打包AndroidAPK
我先画个流程图,方便大家理解:
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第80张图片

现在,我们开始吧。

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

创建一个Unity工程,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第81张图片
简单弄点东西,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第82张图片

1.2、切换Android平台

点击 File / Build Settings菜单,切换成Android平台,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第83张图片

1.3、设置JDK、Android SDK、Gradle

点击Edit / Preferences,在External Tools中设置好JDKAndroid SDKGradle
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第84张图片

1.4、设置包名

Player Settings中设置一下包名,比如com.linxinfa.test
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第85张图片

1.5、测试打包

添加要打包的场景,手动点击Build,测试一下是否能正常打出APK
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第86张图片
可以正常打出APK,说明打包环境设置都正确,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第87张图片

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

新建一个Editor文件夹,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第88张图片
Editor文件夹中新建一个BuildTools脚本,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第89张图片
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通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第90张图片
可以正常打出APK
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第91张图片

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通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第92张图片

3.2、命令参数解释

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

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

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

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

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

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

-projectPath
打开指定路径的项目

-logFile
指定输出的日志文件

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

-executeMethod
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通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第93张图片
可以看到此时能打出APK
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第94张图片
在输出的日志文件中我们也可以看到我们Debug.Log输出的日志,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第95张图片

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通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第96张图片
然后我们安装一下APK,看看APP名字是不是哈哈哈
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第97张图片
在应用信息里可以看到版本号也是我们命令行中设置的1.2.0.0
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第98张图片

4、Jenkins调用bat脚本

我们回到Jenkins页面中,创建一个带参数的任务,
appName参数:
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第99张图片

version参数:
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第100张图片
命令行:
E:\UnityProject\UnityDemo\bat\build_app.bat %appName% %version%,如下:
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第101张图片
执行Jenkins任务,如下:
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第102张图片
等等运行结果:
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第103张图片
执行完毕,我们看下输出的日志,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第104张图片
可以看到我们的bat脚本被正确执行了,参数也传递正确,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第105张图片
APK也可以正常生成,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第106张图片
安装到模拟器上,可以看到名字正确,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第107张图片
版本号也正确,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第108张图片
流程走通了,剩下的就是根据自己的需求进行扩展啦,比如打包前先执行一下svn更新之类的,需要额外参数,就在Jenkins中添加,传递到bat脚本中,再传递到Unity中,最后根据参数进行打包。

5、拓展:python加强版脚本

我个人其实不是特别喜欢写bat脚本,我更喜欢写pytho,于是,我就写了个python版的脚本,脚本中我加了监控Unity日志输出的逻辑,方便进行一些判断,画个图:
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第109张图片
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通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第110张图片
Jenkins中的命令改为执行python脚本:
call python E:\UnityProject\UnityDemo\bat\build_app.py %appName% %version%
如下:
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第111张图片
执行一下任务,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第112张图片
耐心等待执行结果,
在这里插入图片描述
执行完毕可以看到监控到的日志,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第113张图片
我们在python中输出的日志都可以在JenkinsConsole Output中看到,
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第114张图片
APK顺利生成,Very Good,完美~
【游戏开发进阶】教你Unity通过Jenkins实现自动化打包,打包这种事情就交给策划了(保姆级教程 | 命令行打包 | 自动构建)_第115张图片

六、完毕

好了,就写这么多吧,我是新发,喜欢我的可以点赞、关注,有任何技术上的疑问欢迎评论或留言~

你可能感兴趣的:(Unity3D,unity,jenkins,打包,自动化,python)