Jenkins 构建 Unity打包APK

Jenkins 构建 Unity打包APK

一、创建一个 Pipeline 任务

在项目跟目录创建 Pipeline 脚本 jenkins_scripts\Pipeline\android_master_pipeline
脚本如下

// Android Master 打包 apk
pipeline {
    agent any
	
    stages {
        stage('Test Parameter') {
            steps {
                script {
				    // shell 脚本目录
					ANDROID_MASTER_SHELL_PATH="${env.WORKSPACE}/jenkins_scripts/shell/android_master.sh"
					// 给 shell 脚本添加权限并执行
					sh "chmod +x ${ANDROID_MASTER_SHELL_PATH} && ${ANDROID_MASTER_SHELL_PATH}"
                }
            }
        }
    }
}

在项目跟目录创建 Shell 脚本 jenkins_scripts\shell\android_master.sh

#!/bin/sh

#!/bin/bash

echo "this is android_master.sh"
# 输出工作目录
echo "WORKSPACE=${WORKSPACE}"

# Unity 安装目录
UNITY_PATH=/Applications/Unity/Hub/Editor/2022.3.26f1/Unity.app/Contents/MacOS/Unity
# Unity 项目目录 Assets、Library、ProjectSettings 文件夹在 PROJECT_PATH 路径下
PROJECT_PATH="${WORKSPACE}/Project"

# 通过 export 将变量标记为环境变量,并传递给 Unity 使用
# 导出到 Unity 后都是 字符串
# 在 Unity 中通过 string value = Environment.GetEnvironmentVariable(key); 获取
# bool 类型的传递过去是字符串 "true" 和 "false"
export WORKSPACE_PATH="${WORKSPACE}"
# 生成文件保存目录,也通过 export 传递给 Unity
export EXPORT_PATH="${WORKSPACE}/Export"
export KEY_STORE_PATH="${WORKSPACE}/jenkins_scripts/Tools/user.keystore"
# 生成的 apk 名字
export APK_NAME="${JOB_BASE_NAME}_${BUILD_ID}_${BRANCH_NAME}.apk"
# 生成的 apk 路径
export EXPORT_APK_PATH="${EXPORT_PATH}/${APK_NAME}"
# 生成 .aab 文件
export BUILD_AAB="false"    

echo "UNITY_PATH=${UNITY_PATH}"
echo "PROJECT_PATH=${PROJECT_PATH}"
echo "APK_NAME=${APK_NAME}"
echo "EXPORT_APK_PATH=${EXPORT_APK_PATH}"
echo "BUILD_AAB=${BUILD_AAB}"


# 下面是调用 Unity 的命令
# 在 Assets 文件夹下任意目录 创建文件夹 Editor
# 新建 ProjectExportApk.cs  删除继承 MonoBehaviour   
# 添加一个 public static void ExportAPK() 方法
# 下面命令通过 ProjectExportApk.ExportAPK 调用
$UNITY_PATH -projectPath $PROJECT_PATH \
-buildTarget android \
-executeMethod ProjectExportApk.ExportAPK \
-logfile - \
-batchMode -quit \
-GMMode 


echo "this is testShellUnity.sh end"
二、配置 Unity 项目

打开 Unity 项目
Project Settings -> Player -> Android -> Other settings 修改配置
下面只说几个比较关键的配置

  • Identification

    • Package Name:Android 应用包名
    • Minimum API Level:支持的 Android 以及 API 最低等级
    • Target API Level:目标 API 等级,选择最高的即可如现在最高的是 API Level 35
  • Configuration

    • Scripting Backend:IL2Cpp
    • Api Compatibility Level:.NET Framework
    • IL2CPP Code Generation:Faster runtime
    • C++ Compiler Configuration:Release
    • Use incremental GC:勾选
    • Target Architectures:安装包CUP 目标架构
    • ARMv7:勾选
    • ARM64:勾选
  • Optimization:

    • Managed Stripping Level:代码裁剪剔除等级,最好选 High
  • Publishing Settings

    • Keystore Manager…:Keystore 文件管理,可以从这里创建一个,记录创建 Keystore 文件时配置的参数以及 Keystore密码,Alias 对应的密码
    • Custom Keystore:勾选,使用自定义 Keystore 文件,配置一个为这个 Android 项目创建的 Keystore 文件
    • Password:对应 Keystore 文件对应的密码
    • Project Key
      • Alias:创建 Keystore 输出的 Alias 参数
      • Password:Alias 对应的密码
  • Build

    • Custom Main Manifest:勾选
    • Custom Launcher Manifest:不勾选
    • Custom Main Gradle Template:勾选
    • Custom Launcher Gradle Tmplate:勾选
    • Custom Base Gradel Template:勾选
    • Custom Gradle Properties Template:勾选
    • Custom Gradle Settings Template:勾选
    • Custom Proguard File:不勾选
      勾选后保存,Unity 自动在 Assets/Plugins/Android 目录下生成各自对应的文件
三、C# 生成 APK 代码

Assets 目录下任意层级下创建 Editor 文件夹,创建 ProjectExportApk.cs

using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;

public class ProjectExportApk : Editor
{

    private static BuildOptions s_BuildOptions = BuildOptions.CompressWithLz4HC;


    [MenuItem("Tools/ExportAPK")]
    public static void ExportAPK()
    {
        Debug.Log("ExportApk ExportAPK start");

        // 切换平台到 Android 分支
        bool switchAndroid = EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Android, BuildTarget.Android);
        if (!switchAndroid)
        {
            Debug.LogError("ExportApk Switch Android Error");
            return;
        }

        Debug.Log("ExportApk Switch Android success");
        string exportPath = WorkExportPath();
        if (Directory.Exists(exportPath))
        {
            Directory.Delete(exportPath, true);
        }
        Directory.CreateDirectory(exportPath);

        PlayerSettings.applicationIdentifier = "com.DeCompany.Project";

        string keystorePath = GetKeyStorePath();
        Debug.Log("keystorePath:" + keystorePath);
        // 配置 keystore 信息
        PlayerSettings.Android.keystoreName = keystorePath;
        PlayerSettings.Android.keystorePass = "123456";
        PlayerSettings.Android.keyaliasName = "testapk";
        PlayerSettings.Android.keyaliasPass = "123456";
        PlayerSettings.Android.useCustomKeystore = true;

        PlayerSettings.Android.bundleVersionCode = 2;
        PlayerSettings.Android.useAPKExpansionFiles = false;

        EditorUserBuildSettings.buildAppBundle = EnvironmentUtil.GetBool("BUILD_AAB", false);
        // 生成符号文件
        EditorUserBuildSettings.androidCreateSymbols = AndroidCreateSymbols.Public;
        EditorUserBuildSettings.exportAsGoogleAndroidProject = false;

        var options = s_BuildOptions;
        // 是否连接 profiler
        bool connectProfiler = false;
        if (connectProfiler)
        {
            options |= BuildOptions.Development;
            EditorUserBuildSettings.development = true;
            EditorUserBuildSettings.connectProfiler = true;
            EditorUserBuildSettings.buildWithDeepProfilingSupport = true;
        }

        EditorUserBuildSettings.androidBuildSystem = AndroidBuildSystem.Gradle;
        PlayerSettings.bundleVersion = "1.1.1";
        PlayerSettings.productName = "TestProduct";
        var targetArchitectures = AndroidArchitecture.ARM64 | AndroidArchitecture.ARMv7;
        PlayerSettings.Android.targetArchitectures = (AndroidArchitecture)targetArchitectures;

        // PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, defs);

        List<string> levels = new List<string>();
        foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes)
        {
            if (!scene.enabled) continue;
            // 获取有效的 Scene
            levels.Add(scene.path);
        }

        string apkPath = GetApkPath();
        Debug.Log("apkPath:" + apkPath);
        BuildPipeline.BuildPlayer(levels.ToArray(), apkPath, BuildTarget.Android, options);
    }

    public static string WorkExportPath()
    {
        return EnvironmentUtil.GetString("EXPORT_PATH", Application.dataPath);
    }

    private static string GetKeyStorePath()
    {
        return EnvironmentUtil.GetString("KEY_STORE_PATH", string.Empty);
    }

    private static string GetApkPath()
    {
        return EnvironmentUtil.GetString("EXPORT_APK_PATH", "output.apk");
    }
}

上面代码中用到的 EnvironmentUtil 类在这里 Jenkins 调用 Shell 脚本,在Shell脚本中调用 Unity 类方法,传递参数给Unity

执行 Jenkins 构建测试生成结果

你可能感兴趣的:(jenkins,Unity,jenkins,unity,批处理,编辑器)