【Unity3D】Jenkins Pipeline流水线自动构建Apk

目录

一、准备阶段

二、创建Pipeline流水线项目

三、注意事项


一、准备阶段

1、安装tomcat 10.0.5

Index of apache-local/tomcat/tomcat-10

2、安装jdk 17

Java Archive Downloads - Java SE 17.0.13 and later

3、下载Jenkins 2.492.1 (.war)包

War Jenkins Packages

将jenkins.war包移动到D:\Program Files\Apache Software Foundation\Tomcat 10.0\webapps下

配置环境变量

CATALINA_HOME

D:\Program Files\Apache Software Foundation\Tomcat 10.0

JAVA_HOME
E:\JDK(保持使用Unity3d所需的JDK 1.8版本)

Path环境变量新增路径

%CATALINA_HOME%\bin

D:\Program Files\Apache Software Foundation\Tomcat 10.0\bin下新建一个setenv.bat文件,tomcat启动jenkins 2.492.1必须使用JDK 17或以上版本(有要求,否则启动会失败)

复制代码
set JAVA_HOME=D:\Program Files\Java\jdk-17

win + R 输入cmd打开运行命令窗口,输入startup,会执行D:\Program Files\Apache Software Foundation\Tomcat 10.0\bin\startup.bat文件,启动tomcat

可检查上面红框处是否已经指定使用对应的JDK版本,若不是可能构建时也会出各种问题。

启动Tomcat窗口后,不能关闭,我们就是使用它访问Jenkins网页的,默认是http://localhost:8080/jenkins/

关于Jenkins的密码登录、插件安装可参考,插件:Unity3d、Gradle、Pipeline、Pipeline: Stage View 、Git plugin、Push Over SSH、Maven Integration Plugin、Docker Pipeline

【Unity】Jenkins自动打包入门小结_jenkins unity-CSDN博客

安装插件镜像地址**(文本使用清华大学维护的镜像中心,可正常安装插件)**

维护方 镜像中心地址

Jenkins 中文社区 https://updates.jenkins-zh.cn/update-center.json
清华大学 https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json

华为开源镜像站 https://mirrors.huaweicloud.com/jenkins/updates/update-center.json

腾讯 https://mirrors.cloud.tencent.com/jenkins/updates/update-center.json

ustc https://mirrors.ustc.edu.cn/jenkins/updates/update-center.json

bit https://mirror.bit.edu.cn/jenkins/updates/update-center.json

lework https://cdn.jsdelivr.net/gh/lework/jenkins-update-center/updates/tencent/update-center.json https://cdn.jsdelivr.net/gh/lework/jenkins-update-center/updates/tsinghua/update-center.json https://cdn.jsdelivr.net/gh/lework/jenkins-update-center/updates/ustc/update-center.json https://cdn.jsdelivr.net/gh/lework/jenkins-update-center/updates/bit/update-center.json

修改Jenkins工作区 workspace地址

2个文件:C:\ProgramData\Jenkins\.jenkins\config.xml 和 C:\Users\lenovo\.jenkins\config.xml都修改如下标签,E:/JenkinsFile/workspace是自定义工作区,E:/JenkinsFile/builds是构建记录目录,${ITEM_FULL_NAME}是Jenkins项目名

Groovy 复制代码
  <workspaceDir>E:/JenkinsFile/workspace/${ITEM_FULL_NAME}</workspaceDir>
  <buildsDir>E:/JenkinsFile/builds/${ITEM_FULL_NAME}</buildsDir> 

二、创建Pipeline流水线项目

脚本式Pipeline语法(还有个是声明式SCM,需配合Git拉取 具体百度)

Groovy 复制代码
pipeline {
    agent any
 
    environment {
        JAVA_HOME = "E:/JDK" // 确保这里的路径正确,或者使用环境变量如${JAVA_HOME}
    }
    
    tools {
        // 指定JDK版本,例如JDK 1.8
        jdk 'JDK'
    }
    
    //参数设定 参数name、choices要对应上Jenkins设置的参数
    parameters{
        choice(name: "Platform",choices:['Android','Window64'],description: "平台")
        string(name: "BuildPath",defaultValue: "E:/UnityProject/MilkGameFramework_AutoBuildTest/BuildOutput/$Platform/AutoBuildTest", description: "构建输出目录")
    }
    
    stages {
        stage('打包') {
            steps {
                script {
                    //执行一个.sh脚本文件(Shell命令)打包
                    sh "F:/SH/build.sh"
                    echo "打包完成"
                }
            }
        }
    }
}

F:/SH/build.sh文件如下,和打包Windows时一样的调用Unity去执行静态方法传参打包, 只有2个参数Platform和BuildPath,这2个参数是直接由Jenkins Pipeline的参数设置传入的,想增加其他参数同理添加,Pipeline 脚本式语法百度下(Groovy语法)

Groovy 复制代码
echo 'execute unity script to build project ' + $Platform + $BuildPath

D:/UnityHubInstallPath/2019.4.0f1/Editor/Unity.exe -quit -batchmode -projectPath E:/UnityProject/MilkGameFramework_AutoBuildTest -executeMethod UnityProjectBuilder.CommandLineBuild -logFile JenkinsBuildUnity.log Platform-$Platform BuildPath-$BuildPath

配置完成后即可去点击构建(构建之前先把Unity相关的脚本配置好)

cs 复制代码
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEditor.Build.Reporting;

public class UnityProjectBuilder
{

    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();
    }

    //测试用
    [MenuItem("BuildPackage/Build(Android)")]
    public static void BuildPackage()
    {
        LocalCommandLineBuild(@"E:\UnityProject\MilkGameFramework_AutoBuildTest\BuildOutput\Android\Test", "Android");
    }

    /// <summary>
    /// 此方法是从jienkins上接受  数据的 方法
    /// </summary>
    static void CommandLineBuild()
    {
        LocalCommandLineBuild(GetJenkinsParameter("BuildPath"), GetJenkinsParameter("Platform"));        
    }

    static void LocalCommandLineBuild(string path, string platform)
    {
        try
        {

            Debug.Log("Command line build\n------------------\n------------------");
            string[] scenes = GetBuildScenes();
            //string path = @"E:\Unity游戏包\Android\消消乐游戏";//这里的路径是打包的路径, 定义
            //string path = GetJenkinsParameter("BuildPath");
            Debug.Log(path);
            for (int i = 0; i < scenes.Length; ++i)
            {
                Debug.Log(string.Format("Scene[{0}]: \"{1}\"", i, scenes[i]));
            }
            // ProjectPackageEditor.BuildByJenkins(GetJenkinsParameter("Platform"), GetJenkinsParameter("AppID"), GetJenkinsParameter("Version"), GetJenkinsParameter("IPAddress"));
            Debug.Log("Starting Build!");
            Debug.Log("Platform: " + GetJenkinsParameter("Platform"));

            //string platform = GetJenkinsParameter("Platform");
            if (platform == "Android")
            {
                Debug.Log("构建安卓开始:" + path + ".apk");
                BuildReport report = BuildPipeline.BuildPlayer(scenes, path + ".apk", BuildTarget.Android, BuildOptions.CompressWithLz4);
                if (report.summary.result == BuildResult.Succeeded)
                {
                    Debug.Log("Build succeeded: " + path + ".apk");
                }
                else if (report.summary.result == BuildResult.Failed)
                {
                    Debug.LogError("Build failed");
                    foreach (var log in report.steps)
                    {
                        if (log.messages != null)
                        {
                            foreach (var message in log.messages)
                            {
                                Debug.LogError(message.content);
                            }
                        }
                    }
                }
            }
            else if (platform == "IOS")
            {
                //BuildPipeline.BuildPlayer(scenes, path, BuildTarget.iOS, BuildOptions.AcceptExternalModificationsToPlayer);
            }
            else if (platform == "Window64")
            {
                BuildReport report = BuildPipeline.BuildPlayer(scenes, path + ".exe", BuildTarget.StandaloneWindows64, BuildOptions.None);
                if (report.summary.result == BuildResult.Succeeded)
                {
                    Debug.Log("Build succeeded: " + path + ".exe");
                }
                else if (report.summary.result == BuildResult.Failed)
                {
                    Debug.LogError("Build failed");
                    foreach (var log in report.steps)
                    {
                        if (log.messages != null)
                        {
                            foreach (var message in log.messages)
                            {
                                Debug.LogError(message.content);
                            }
                        }
                    }
                }
            }
        }
        catch (Exception err)
        {
            Debug.LogError("方法F中捕捉到:" + err.Message);
            throw;//重新抛出当前正在由catch块处理的异常err
        }
        finally
        {
            Debug.Log("---------->  I am copying!   <--------------");
        }
    }


    /// <summary>
    ///解释jekins 传输的参数
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    static string GetJenkinsParameter(string name)
    {
        /*下面是解析这个字符串,用空格分隔,每一个arg是空格分隔后的字符串,然后继续解析出Platform参数和BuildPath参数,
 注意:$BuildPath是我们Jenkins上定义的参数,它会传入一个字符串路径
 -quit -batchmode -projectPath D:\下载文件\游戏蛮牛源码\一个消消乐工程 -executeMethod UnityProjectBuilder.CommandLineBuild -logFile JenkinsBuildUnity.log Platform-$Platform BuildPath-$BuildPath
 */
        foreach (string arg in Environment.GetCommandLineArgs())
        {
            //Debug.Log("arg:" + arg);
            if (arg.StartsWith(name))
            {
                return arg.Split("-"[0])[1];
            }
        }
        return null;
    }
}

等待一会打包成功后会得到

若失败了,去查看Jenkins日志

三、注意事项

1、Pipeline插件有最低Jenkins版本要求,最好是使用最新版本的Jenkins(其他版本可能有问题)

2、Tomcat使用11.0.x版本可能有问题,类似Could not create Java Virtual Machine...,故尝试使用Tomcat 10.0.5版本正常,若有类似问题请更换Tomcat版本(具体原因不清楚)

3、Jenkins版本有对应JDK版本要求,本文Jenkins要求必须JDK 17或以上,否则无法正常启动Jenkins

4、Tomcat启动的Jenkins是查找不到Jenkins服务的。

5、Tomcat换版本后,要注意变更环境变量CATALINA_HOME指定的地址,忘了就还是运行旧的Tomcat,即使你是去到具体的Tomcat双击startup.bat运行的,它只认环境变量。

6、Pipeline Script 语法对\敏感,尽量不要用\,全部改为/

7、点击构建时,可能会立刻报错,此时请把Pipeline代码设置为最简单的案例,例如:

Groovy 复制代码
pipeline {
    agent any
    stages {
        stage('打包') {
            steps {
                script {
                    echo "打包测试"
                }
            }
        }
    }
}

若发现还是有报错,类似找不到stages、stage、steps等字眼的,很可能还是Pipeline相关的插件没更新好,要全部更新到最新。

8、一种非常奇怪的bug,具体怎么解决也是稀里糊涂的,反正就是一点击构建,瞬间失败,1ms都没执行,查看build log

报错1:Also: org.jenkinsci.plugins.workflow.actions.ErrorAction$ErrorId: 3f2d47bc-e83a-4bd4-beae-34a81a0ce08f
groovy.lang.MissingPropertyException: No such property: Platform for class: groovy.lang.Binding
at groovy.lang.Binding.getVariable(Binding.java:63)
at PluginClassLoader for script-security//org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(S

报错2:Also: org.jenkinsci.plugins.workflow.actions.ErrorAction$ErrorId: eddf3d49-e60e-4fd1-aeaf-d230d2946b16
java.lang.NullPointerException: Cannot invoke "java.util.Map.size()" because "map" is null
at java.base/java.util.TreeMap.putAll(TreeMap.java:314)
at hudson.slaves.EnvironmentVariablesNodeProperty.buildEnvVars(EnvironmentVariablesNodeProperty.java:87)

jenkins升级后启动job遇到问题java.lang.NullPointerException: Cannot invoke "java.util.Map.size()" because "map_cannot invoke "java.util.map.size()" because "m" i-CSDN博客

参考如上文章后得知大概是config.xml被我改崩了,因此我直接删了C:\ProgramData\Jenkins\.jenkins\config.xml(记得缓存),然后重启Jenkins,也就是重新关闭tomcat和开启tomcat运行jenkins 去构建一次就会自动生成config.xml,好像还要等它一会儿才会生成,如果还是没生成,可以试试重启电脑,然后正常修改workspace地址即可。之后就能正常打包了,很有可能是我没改<buildsDir>标签,仅改了<workspaceDir>标签问题,也可能是我更换了太多次Jenkins版本,以及也尝试过使用Jenkins.msi安装包形式去安装(安装包形式有Jenkins服务)本文是将所有安装包Jenkins版本卸载,仅使用tomcat+jenkins形式的

相关推荐
leo__5201 小时前
单载波中继系统资源分配算法MATLAB仿真程序
算法·matlab·unity
祖国的好青年1 小时前
VS Code 搭建 React Native 开发环境(Windows 实战指南)
android·windows·react native·react.js
黄林晴1 小时前
警惕!AGP 9.2 别只改版本号,R8 规则与构建链路全线收紧
android·gradle
小米渣的逆袭2 小时前
Android ADB 完全使用指南
android·adb
儿歌八万首2 小时前
Jetpack Compose Canvas 进阶:结合 animateFloatAsState 让自定义图形动起来
android·动画·compose
努力长头发的程序猿2 小时前
Unity使用ScriptableObject序列化资源
unity·游戏引擎
mxwin3 小时前
Unity Shader 手写基于 PBR 的 URP Lit Shader 核心光照计算
unity·游戏引擎·shader
小贺儿开发3 小时前
Unity3D 智能云端数字标牌系统
unity·阿里云·人机交互·视频·oss·广告·互动
zhangphil3 小时前
Android Page 3 Flow读sql数据库媒体文件,Kotlin
android·kotlin
神探小白牙3 小时前
echarts,3d堆叠图
android·3d·echarts