In this article, we’ll look at Unity APIs and supporting tools that can help you create a robust CI/CD pipeline for your projects.
A complete example project – including the Unity project, Jenkins configuration, Docker containerization templates, and scripts – is available here: GitHub Repository
Why Automate Builds?
Save Development Time
Over the lifetime of a project, you’ll probably create hundreds or even thousands of builds for QA, internal testing, and release. Automating these steps saves countless hours compared to manual workflows, far outweighing the time required to build the automation system.
Ensure Consistency
Build pipelines eliminate human error. Instead of relying on checklists and memory, automation guarantees that every build follows the same sequence of steps.
Automate Expensive Tasks
A build pipeline is a great place to offload time-consuming or resource-heavy processes:
- Asset compression and optimization
- Static code/security analysis
- Mesh and material merging
- Shader/code generation
- Full-quality light baking
- Scene and prefab analysis
A Simple CI/CD Workflow Example
Once you’re satisfied with your local changes and commit them, it’s time to build for testing. With automation in place, a single click in the web interface triggers the build machine to:
- Checkout the Git repository
- Rebake lighting
- Run unit and play tests (with feedback on failures)
- Build for Android, iOS, and Web
- Deploy builds to local test devices
- Upload builds to Google Play and App Store (TestFlight)
For simplicity, I’ll skip APIs for pt. 6 details, handling signing keys, provisioning profiles, KMS, and secrets management deserve a separate article.
Now, let’s dive into the Unity APIs and system tools required to build such a pipeline.
Unity APIs and Tools for Build Automation
Running Unity Editor Scripts from CLI
You can launch the Unity Editor from the command line, specify a static method from your editor scripts to execute, and the editor will close automatically once the method finishes.
{UNITY_EDITOR_PATH} -batchmode -quit -projectPath {UNITY_PROJECT_PATH} {EDITOR_CLASS_NAME}.{EDITOR_CLASS_METHOD}
Docs: https://docs.unity3d.com/2020.1/Documentation/Manual/CommandLineArguments.html
Automating Unity Scene Manipulation
With a simple script, you can open, modify, and save Unity scenes directly – no manual editor interaction required:
EditorSceneManager.OpenScene(scenePath);
// Do some stuff with a scene
EditorSceneManager.SaveOpenScenes();
Unity Light Baking
Lighting can be baked programmatically on the currently opened scene:
Lightmapping.Bake();
Docs: https://docs.unity3d.com/6000.2/Documentation/ScriptReference/Lightmapping.Bake.html
Unity Build Target Switching
You can change the active build target on the fly via script:
EditorUserBuildSettings.SwitchActiveBuildTarget(namedBuildTarget, target);
Unity Addressables
You can trigger an Addressables build directly from code:
AddressableAssetSettings.BuildPlayerContent();
Docs: https://docs.unity3d.com/Packages/com.unity.addressables@1.15/manual/BuildPlayerContent.html
Player Settings
You can modify player settings programmatically during the build process.
This is useful for tasks like retrieving an Android keystore from secure storage at build time, applying it, and then discarding changes afterward.
PlayerSettings.Android.keystoreName =
"PathToKeystore";
PlayerSettings.Android.keystorePass =
"";
PlayerSettings.Android.keyaliasName =
"KeyaliasName";
PlayerSettings.Android.keyaliasPass =
"";
Docs:
Unity Project Builds
You can build a Unity project for any supported platform directly from code.
Build Options:
varbuildPlayerOptions =
newBuildPlayerOptions {
locationPathName = {PATH},
target = {BUILD_TARGET},
extraScriptingDefines = {SCRIPT_DEFINES},
options = {BUILD_OPTIONS},
scenes = {SCENES}
};
Docs: https://docs.unity3d.com/ScriptReference/BuildPlayerOptions.html
Build Pipeline:
BuildPipeline.BuildPlayer(buildPlayerOptions);
Docs: https://docs.unity3d.com/6000.2/Documentation/ScriptReference/BuildPipeline.BuildPlayer.html
Unity Test Running
You can run both PlayMode tests and EditMode unit tests automatically as part of your build pipeline.
Run PlayMode Tests via Script:
vartestRunner = ScriptableObject.CreateInstance<TestRunnerApi>();
varfilter =
newFilter {
targetPlatform = {PLATFORM},
testMode = TestMode.PlayMode
};
varexecutionSettings =
newExecutionSettings {
filters =
new[] { filter }
};
testRunner.Execute(executionSettings);
Run Unit Tests via Command Line:
${UNITY_PATH} -runTests -batchmode -projectPath
${UNITY_PROJECT_PATH} -testPlatform EditMode -logfile stdout -testResults
Docs: https://docs.unity3d.com/Packages/com.unity.test-framework@1.1/manual/reference-command-line.html
Building an iOS Project from the Command Line
You can build and package iOS projects directly from the command line using xcodebuild
.
1. Create an XCArchive
xcodebuild -workspace {WORKSPACE_PATH} -scheme {SCHEME_NAME} -archivePath {XCARCHIVE_PATH} archive
2. Prepare Export Options (.plist)
Create a .plist
file with your desired export settings:
<?xml version="1.0"encoding=
"UTF-8"?>
<!DOCTYPE plistPUBLIC"-//Apple//DTD PLIST 1.0//EN""http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plistversion=
"1.0">
<dict>
<key
>method
</key>
<string
>app-store
</string>
<key
>teamID
</key>
<string
>{YOUR_TEAM_ID}
</string>
<key
>uploadBitcode
</key>
<true
/>
<key
>uploadSymbols
</key>
<true
/>
</dict>
</plist>
3. Build the .ipa File
xcodebuild -exportArchive -archivePath {XCARCHIVE_PATH} -exportPath {EXPORT_PATH} -exportOptionsPlist {OPTIONS_PLIST_PATH}
Docs: Apple Technical Note TN2339
Installing Test Builds on Local iOS Devices
The easiest way to install .ipa
files locally is with Apple Configurator, which includes the cfgutil
tool:
1. Install Apple Configurator 2 – https://apps.apple.com/us/app/apple-configurator/id1037126344?mt=12
2. Add cfgutil to your PATH:
sudo ln -s "/Applications/Apple Configurator 2.app/Contents/MacOS/cfgutil" /usr/local/bin/cfgutil
3. Install the .ipa on a connected device (via USB):
cfgutil install-app {IPA_PATH}
Wireless installation on iOS devices is cumbersome and unreliable. In most cases, it’s far easier to automate TestFlight uploads and distribute builds that way.
Installing Test Builds on Local Android Devices
You can install .apk
files directly onto Android devices connected by USB cable or over a local wireless connection.
Wireless setup:
adb pair {IP}:{PORT}
adb connect {IP}:{PORT}
adb install {APK_PATH}
adb shell am start -n {APP_PACKAGE}/{ENTRY_POINT}
Docs: https://developer.android.com/tools/adb
App Store TestFlight & Google Play Internal Testing Upload Automation
Simple usage examples, provided without context …
AppStore
xcrun notarytool submit {IPA_PATH} --apple-id {APPLE_ID_EMAIL} --team-id {TEAM_ID} --password {APP_SPECIFIC_PASSWORD}
Google Play
gcloud auth activate-service-account --key-file={SERVICE_ACCOUNT_JSON} --project={GCP_PROJECT_ID}
gcloud firebase appdistribution:distribute {AAB_PATH} --app {FIREBASE_APP_ID} --testers {TESTERS} --release-notes {RELEASE_NOTE}
Wrapping Up
The APIs and examples above cover most of what you’ll need to assemble a custom Unity build pipeline. Add a bit of Git integration, Slack notifications, etc, and you’ve got a simple yet powerful automated workflow.
The final piece is choosing a tool to tie everything together. In my example, I’ve used Jenkins. While it may feel a little bit dated, its rich plugin ecosystem and ability to easily leverage external worker machines (e.g., running light baking on a Windows PC with a dedicated GPU) still make it a solid choice for local, self-hosted setups.
That said, almost any modern CI/CD solution can do the job just as well – the APIs and scripts remain the same.