跳到主要内容

自定义构建方法

上一节介绍了使用 tj-builder 为工程进行构建,本节将介绍使用个性化的方法来满足项目的构建。

1. 构建脚本

使用 tj-builder 进行构建时,当不指定 buildMethod 的时候,会使用默认的构建方式进行构建。

如果项目有特殊化的构建需求,tj-builder 能够通过指定 buildMethod 的值来调用构建方法。如下代码是一个 EmbeddedLinux 项目的构建脚本,能够在工作流文件中指定

- uses: actions/tj-builder@v3
with:
buildMethod: Builder.Build

来调用改方法。

using UnityEditor;
using UnityEditor.Build.Reporting;
using UnityEngine;

public class Builder
{
private static void BuildEmbeddedLinux(EmbeddedLinuxArchitecture architecture)
{
// Set architecture in BuildSettings
EditorUserBuildSettings.selectedEmbeddedLinuxArchitecture = architecture;

// Setup build options (e.g. scenes, build output location)
var options = new BuildPlayerOptions
{
// Change to scenes from your project
scenes = new[]
{
"Assets/Scenes/SampleScene.unity",
},
// Change to location the output should go
locationPathName = "../EmbeddedLinuxPlayer/",
options = BuildOptions.CleanBuildCache | BuildOptions.StrictMode,
target = BuildTarget.EmbeddedLinux
};

var report = BuildPipeline.BuildPlayer(options);

if (report.summary.result == BuildResult.Succeeded)
{
Debug.Log($"Build successful - Build written to {options.locationPathName}");
}
else if (report.summary.result == BuildResult.Failed)
{
Debug.LogError($"Build failed");
}
}

// This function will be called from the build process
public static void Build()
{
// Build EmbeddedLinux ARM64 Unity player
BuildEmbeddedLinux(EmbeddedLinuxArchitecture.Arm64);
}
}

2. 命令行构建项目

如需在本地进行构建脚本的调试,能够通过命令行进行项目的构建。

下面的示例使用的是 Windows 版本的可执行文件 C:\Program Files\Tuanjie\Hub\Editor\<version>\Editor\Tuanjie.exe,但您也可以根据自己偏好的构建主机操作系统,将其替换为相应的可执行文件。

2.1 命令行调试

以上述构建脚本为例,可以将示例构建脚本放到 Assets/Editor/ 目录中。使用 -executeMethod 选项调用该类的 Build() 方法,该方法会设置构建选项并触发构建。

要指示 Unity 以 CLI 模式启动并在 \<path-to-unity-project-root>处构建项目,请在 powershell 中运行以下命令:

& 'C:\Program Files\Unity\Hub\Editor\<version>\Editor\Tuanjie.exe' `
-quit -batchmode -nographics `
-buildTarget EmbeddedLinux `
-executeMethod Builder.Build `
-projectPath <path-to-unity-project-root>

这样在构建过程还会调用函数 Builder.Build ,以继续构建设置过程。

更多信息,请参阅 BuildPipeline.BuildPlayer 文档.

2.2 命令行参数

自定义构建过程中,构建函数可以通过命令行参数获取命令执行时的变量值。函数如下(ParseCommandLineArguments):

static void ParseCommandLineArguments(out Dictionary<string, string> providedArguments)
{
providedArguments = new Dictionary<string, string>();
string[] args = Environment.GetCommandLineArgs();

Console.WriteLine(
$"{EOL}" +
$"###########################{EOL}" +
$"# Parsing settings #{EOL}" +
$"###########################{EOL}" +
$"{EOL}"
);

// Extract flags with optional values
for (int current = 0, next = 1; current < args.Length; current++, next++) {
// Parse flag
bool isFlag = args[current].StartsWith("-");
if (!isFlag) continue;
string flag = args[current].TrimStart('-');

// Parse optional value
bool flagHasValue = next < args.Length && !args[next].StartsWith("-");
string value = flagHasValue ? args[next].TrimStart('-') : "";
bool secret = Secrets.Contains(flag);
string displayValue = secret ? "*HIDDEN*" : "\"" + value + "\"";

// Assign
Console.WriteLine($"Found flag \"{flag}\" with value {displayValue}.");
providedArguments.Add(flag, value);
}
}

public static void Build()
{
Dictionary<string, string> options;
ParseCommandLineArguments(out options);
if (options.TryGetValue("androidKeystoreName", out string keystoreName) && !string.IsNullOrEmpty(keystoreName))
{
// ...
}
}

2.3 安卓签名构建示例

static void BuildProject(string channel, bool isProject)
{
// ...

Dictionary<string, string> options;
ParseCommandLineArguments(out options);

#if UNITY_2019_1_OR_NEWER
if (options.TryGetValue("androidKeystoreName", out string keystoreName) && !string.IsNullOrEmpty(keystoreName))
{
PlayerSettings.Android.useCustomKeystore = true;
PlayerSettings.Android.keystoreName = keystoreName;
}
#endif
// Can't use out variable declaration as Unity 2018 doesn't support it
string keystorePass;
if (options.TryGetValue("androidKeystorePass", out keystorePass) && !string.IsNullOrEmpty(keystorePass))
PlayerSettings.Android.keystorePass = keystorePass;

string keyaliasName;
if (options.TryGetValue("androidKeyaliasName", out keyaliasName) && !string.IsNullOrEmpty(keyaliasName))
{
PlayerSettings.Android.keyaliasName = keyaliasName;
}

string keyaliasPass;
if (options.TryGetValue("androidKeyaliasPass", out keyaliasPass) && !string.IsNullOrEmpty(keyaliasPass))
PlayerSettings.Android.keyaliasPass = keyaliasPass;

// ...
BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions();
buildPlayerOptions.locationPathName = exportPath;
buildPlayerOptions.target = BuildTarget.Android;
// ...

var report = BuildPipeline.BuildPlayer(buildPlayerOptions);

// ...
}