# 在构建过程中运行自定义脚本

> Follow this workflow to run custom scripts before and after the build process.

Build Automation 支持用户创建的构建前和构建后自定义脚本。要使用自定义脚本，请将这些脚本签入源代码仓库，然后在构建的 Advanced Settings（高级设置）中配置脚本相对于代码仓库根目录的相对路径。

> **Note:**
>
> **注意**：请将 shell 脚本的行尾设置为 Unix 格式，尤其是在使用 URL 执行行命令时。

## 导出前和导出后方法##prerequisites

使用导出前和导出后方法可在 Unity 项目在云端构建之前和之后触发相应操作。这些方法必须存在于 `Assets/Editor` 文件夹中的类内。如果目录中不存在 Editor 文件夹，您可以创建一个。

> **Important:**
>
> **重要**：`UnityEngine.CloudBuild.BuildManifestObject` 类仅在 Build Automation 中运行时可用，在本地不可用。要在本地编译代码，请将导出前和导出后方法封装在 #if UNITY\_CLOUD\_BUILD 代码块中。您可以在构建目标的 Advanced settings（高级设置）中设置导出前和导出后方法。

## 导出前方法名称##pre-export-and-post-export-methods

要使用导出前方法，请在 Unity 项目中创建一个公共静态方法，其中包含要在 Unity 编辑器导出项目之前和 Unity 编辑器脚本编译阶段之后执行的代码。

```cs
public static void PreExport()
```

可以通过在方法签名中指定 `BuildManifestObject` 对象作为参数，使 Build Automation 将当前构建的构建清单传递给导出前方法。然后，可以在导出项目之前更改 Project（项目）或 **Player（播放器）** 设置。

```cs
public static void PreExport(UnityEngine.CloudBuild.BuildManifestObject manifest)
```

Unity Build Automation 调用该方法时，会将 `BuildManifestObject` 对象作为可选参数传递，并将 `BuildManifestObject` 作为当前构建的构建清单。

## 导出后方法名称##custom-scripting-define-directives

要使用导出后方法，请在 Unity 项目中创建一个公共静态方法，其中包含要在 Unity 编辑器导出项目后执行的代码。

```cs
public static void PostExport(string exportPath)
```

Unity Build Automation 调用该方法时，会传递一个字符串：

* 对于非 iOS 构建目标，该字符串包含所导出项目的路径。
* 对于 **iOS** 项目，该字符串包含导出的 Xcode 项目的路径。您可以使用该路径来找到导出的 Xcode 项目，以便在调用 Xcode 完成构建过程之前执行额外的预处理。
  > **Note:**
  >
  > **注意**：如果在代码中使用 Unity [PostProcessBuildAttribute](https://docs.unity3d.com/ScriptReference/Callbacks.PostProcessBuildAttribute.html) 标记任何方法，则这些方法会在 Unity Build Automation 中配置为导出后方法的任何方法之前执行。

## 自定义脚本 `#define` 指令##pre-build-and-post-build-scripts

使用 Build Automation 可以创建自定义脚本 #define 指令。在 [Unity Dashboard](https://cloud.unity.com) 上，转到构建目标的 **Advanced Settings（高级设置）**。

在 **Scripting Define Symbols（脚本定义符号）** 字段中，可以将自己的自定义脚本 #define 指令添加到可用的内置选项中。对于每个构建目标，输入要定义的符号名称。然后，可以像使用内置符号一样，将这些符号用作 #if 指令中的条件。有关更多信息，请参阅[条件编译](https://docs.unity3d.com/Manual/PlatformDependentCompilation.html)。

## 更改节点版本##source-profile

构建机器上安装了 NVM，以便您可以在构建过程中切换到其他节点版本。以下示例脚本将安装并切换到 Node 16.13.0：

```sh
#!/usr/bin/env bash

## Source profile##install-nvm-modules-and-set-version
. ~/.profile

## Install NVM modules and set version##output-node-version-used
nvm install 16.13.0
nvm use 16.13.0

## Output Node version used##source-profile
node -v

exit 0
```

## 使用其他 Ruby 版本

构建机器上安装了 `RVM` 和 `gem`，以便您可以在构建过程中使用不同的 Ruby 版本。以下示例脚本将安装 Ruby 3.3.0 并使用 `DO` 执行命令，因此不会影响 UBA 工具所使用的系统 Ruby 安装。

```sh
#!/usr/bin/env bash

## Source profile
rvm install ruby-3.3.0
rvm ruby-3.3.0 do gem install fastlane
rvm ruby-3.3.0 do fastlane --help

exit 0
```

> **Note:**
>
> **注意**：如果是在 macOS Ventura 上运行构建，可能需要使用以下命令来使用特定的 OpenSSL 版本：

```sh
rvm install ruby-3.3.0 --with-openssl-dir=$(brew --prefix openssl@1.1)
```

> **Note:**
>
> **注意**：不建议使用 `rvm use NEW_RUBY_VERSION` 来更改系统 Ruby 版本，进行此操作需自行承担风险。

## 设置环境变量

```sh
echo "{environment_variable_name}={value}" >> "$DEVOPS_ENV"
```

要使 Unity 构建和构建后脚本可以使用环境变量，请定义或更新环境变量并将此值写入 `DEVOPS_ENV` 环境文件。创建或更新环境变量的脚本无法访问新值，但所有后续进程都将可以访问。环境变量名称以大写形式存储（例如 `testenv` 会变为 `TESTENV`）。仅支持单行环境变量。

### 将环境变量写入 `DEVOPS_ENV` 的示例##pre-export-method-name

在构建前脚本中设置环境变量。

```sh
echo "TEST_ENV=Sample environment variable" >> $DEVOPS_ENV
```

然后在构建后脚本中输出该环境变量。

```sh
echo $TEST_ENV
```

## 在构建后脚本中访问构建 Artifact

您可以使用构建后脚本访问构建 Artifact，以便自动上传到应用商店，或使构建过程的某些部分实现自动化。如果在构建后脚本中使用环境变量将路径传递给 Windows 可执行文件，则必须使用 cygwin 路径。

### 获取播放器路径的示例脚本##post-export-method-name

```sh
#!/bin/bash

#This is a sample that will simply output the path to the build artifact

echo "START"

PLAYER_PATH=$UNITY_PLAYER_PATH

#If we are using a Windows Builder and using the path to pass it to a native Windows application, we need to properly convert the cygwin player path to windows format

if [[ "$BUILDER_OS" == "WINDOWS" ]]; then
PLAYER_PATH=$(cygpath -wa "$UNITY_PLAYER_PATH")
fi

echo "$PLAYER_PATH"
```

## 在日志中屏蔽值

屏蔽值可以防止字符串或变量在日志中打印出来。无论值内容如何，每个被屏蔽的值都会替换为 `*****`。您可以将环境变量或原始值传递给 mask 命令。

要屏蔽字符串或环境变量，请使用 `::mask-value::` 命令。

```text
echo "::mask-value::{value}"
```

### 示例：屏蔽值##change-node-versions

要屏蔽值 `"SuperS3cretPassword!"`，请为该值设置 `::mask-value::` 命令：

```text
echo "::mask-value::SuperS3cretPassword!"
```

在日志中打印时，输出将显示为 `"*****"`。

> **Warning:**
>
> 必须先使用“mask-value”注册该值，然后再将其输出到日志中。

### 示例：屏蔽变量##use-other-ruby-versions

要屏蔽变量 `DB_PASSWORD` 或变量值 `"SuperS3cretPassword!"`，请为变量设置 `::mask-value::` 命令：

```text
DB_PASSWORD=SuperS3cretPassword!
echo "::mask-value::$DB_PASSWORD"
```

当这类内容打印到日志中时，输出将显示为 `"*****"`。

### 示例：屏蔽环境变量##set-environment-variables

使用 `$DEVOPS_ENV` 设置的环境变量可以被屏蔽。设置环境变量的值，将其屏蔽，然后将该值输出到 `$DEVOPS_ENV` 文件中，以便在其他脚本中使用。

```text
DB_PASSWORD=SuperS3cretPassword!
echo "::mask-value::$DB_PASSWORD"
echo "DB_PASSWORD=$DB_PASSWORD" >> $DEVOPS_ENV
```
