Cloud native mobile game CI/CD with Unity and CircleCI
Senior Solutions Engineer
This tutorial provides an easy-to-understand introduction on how to run your mobile gaming CI/CD in the cloud using CircleCI, GameCI, and Unity.
What is Unity?
Unity is a game development platform created by Unity Technologies that enables developers to build games in C# for the following platform types:
- Desktop PCs (Windows/macOS)
- Mobile devices (iOS / Android)
- Video game consoles (PlayStation / Xbox / Nintendo Switch)
Unity provides a library of ready-made resources and tools via the Unity Asset Store.
Unity has been adopted as a game development environment for projects of all scales and has a high market share, especially in mobile gaming.
Implementing mobile CI/CD in the cloud with CircleCI and GameCI
Developing consistently high quality games requires the use of good CI/CD tooling and practices. Mobile games in particular require high-performance CI/CD tools because of their frequent updates and large user bases. But the unique and complex requirements of mobile game building, testing, and distribution make configuring mobile CI/CD from scratch a daunting task. These requirements include:
- Correctly and consistently configuring the build environment (especially for iOS!)
- Installing the Unity Editor
- Activating the Unity license
- Preparing the build script
As a result, many mobile development teams fall into one or more anti-patterns, including:
- Manually building and testing in a local development environment
- Manually testing, building, and distributing that application
- Performing CI/CD tasks in a quickly configurable but difficult-to-scale environment, such as self-hosted Jenkins
GameCI is an open source tool that was created to solve these common mobile game development CI/CD challenges. It boasts the following features:
- CI/CD environment with Unity Editor pre-installed (Docker image)
- Automated Unity license activation
- Ability to run builds for any platform supported by Unity
GameCI integrates with CircleCI by using an orb. With the GameCI Unity orb, you can easily create CI/CD pipelines for Unity projects without writing a complex, custom build script from scratch.
In this tutorial, we will demonstrate how to set up a Unity mobile game CI/CD pipeline with CircleCI and GameCI.
Prerequisites
You can find all the code used in this tutorial in the sample repository.
This tutorial assumes you have already set up CircleCI with your VCS. If you have not, sign up for a free account and follow our quickstart guide to get your CI/CD pipeline up and running. Once you have your CircleCI account configured, you can proceed with the steps outlined in this tutorial.
Activating your Unity license
Before we can build a Unity project, we need to activate a Unity license. In this tutorial, we will be using a Unity Personal license. (Please note that the activation method differs depending on the license used. Refer to the following GameCI document for more details: Activation with GameCI).
To obtain an activated Unity license file, we first need to generate a Unity activation file. Let’s create a CircleCI configuration file in our project repo at the path .circleci/config.yml
. Next, we’ll add the code shown below, and then commit our change. CircleCI will run the create-unity-activation-file
job.
version: 2.1
orbs:
unity: gameci/unity@1.6.0
workflows:
create-unity-activation-file:
jobs:
- unity/create-activation-file
After the job completes, we can download the activation file (Unity.alf
) from the ARTIFACTS tab.
Upload the activation file to Unity’s manual activation page to activate your Unity license.
After the activation is complete, we can download the Unity license file (Unity_v20XX.x.ulf
). We will store this file as a secret in a CircleCI context so that we can use it in our Unity jobs. First, we will create a context in CircleCI. In our new context, we’ll create the following variables with their corresponding values:
UNITY_ENCODED_LICENSE
- The license file encoded as a base64 string; see here for instructions
UNITY_USERNAME
UNITY_PASSWORD
Building and distributing (Android)
The next step after activating our Unity license is to run a build. First, let’s run a build for the Android platform. Below, I am doing so in a job named build-android
:
build-android:
executor:
name: unity/ubuntu
editor_version: 2021.3.26f1
resource_class: xlarge
target_platform: android
steps:
- checkout
- unity/prepare-env
- unity/build:
build-target: Android
compress: false
store-artifacts: false
persist-to-workspace: true
Let’s break down the build-android
job in detail.
The executor uses the Unity orb to select an appropriate execution environment. resource_class determines the size of the build machine. We can choose from the Docker resource classes listed in the relevant CircleCI documentation.
Building Unity projects often requires provisioning expensive machines with large amounts of CPU and memory. CircleCI enables you to keep costs low by spinning these machines up only for the duration of the build job. CircleCI also aids you in rightsizing your build machines by logging each job’s resource usage in a set of intuitive graphs available in the Insights dashboard, shown below.
Continuing our breakdown of the build-android
job, the steps are an ordered list of tasks that make up the job. This job is doing the following:
- Checking out the source code (
checkout
) - Preparing the license file we saved in our context (
unity/prepare-env
) - Running a build for Android (
unity/build
)
This will create a binary (APK) for Android on the build machine. You could upload this APK as-is to the Google Play Store to release it, distribute it via Firebase App Distribution, or use another distribution method of your choice.
In our case, we will use fastlane to distribute our APK to Firebase App Distribution. Here is the relevant CircleCI config:
beta-android:
executor:
name: ruby/default
tag: 3.2.2
steps:
- checkout
- attach_workspace:
at: .
- ruby/install-deps:
key: android
- run: bundle exec fastlane android beta
And here is the related fastlane config (/fastlane/Fastfile
)
platform :android do
lane :beta do
firebase_app_distribution(
app: "Firebase App ID",
apk_path: "Builds/Android/Android.apk",
)
end
end
And that’s it! You’ve successfully built and distributed your Android game on the cloud!
Building and distributing (iOS)
Next, let’s run a build for iOS. Below we have a CircleCI job called export-ios
:
export-ios:
executor:
name: unity/ubuntu
editor_version: 2021.3.26f1
resource_class: xlarge
target_platform: ios
steps:
- checkout
- unity/prepare-env
- unity/build:
build-target: iOS
compress: false
store-artifacts: false
persist-to-workspace: true
This export-ios
job uses the same Unity orb as our Android job above. However, unlike the Android job, the unity/build
job does not produce a binary (IPA). Instead, an Xcode project like the one below is generated on the build machine:
In order to create our iOS binary (IPA), we must sign and build this Xcode project in a macOS environment. We will do this in a second job, build-and-beta-ios
, shown below:
build-and-beta-ios:
macos:
xcode: 13.4.1
resource_class: macos.m1.large.gen1
steps:
- checkout
- attach_workspace:
at: .
- ruby/install-deps:
key: ios
- run: bundle exec fastlane ios beta
Because this job requires a macOS environment, we are using a CircleCI M1 macOS VM.
In the final run
step in the build-and-beta-ios
job, we are using fastlane to do the following:
- Perform code signing using fastlane match
- Build the Xcode project that we generated
- Distribute our app to Firebase App Distribution
Here is the related fastlane configuration code:
platform :ios do
before_all do
setup_circle_ci
end
lane :beta do
match(type: "adhoc")
update_code_signing_settings(
use_automatic_signing: true,
path: "Builds/iOS/iOS/Unity-iPhone.xcodeproj"
)
update_code_signing_settings(
use_automatic_signing: false,
team_id: ENV["sigh_com.tadashi0713.CircleCIUnityMobileDemo_adhoc_team-id"],
code_sign_identity: 'iPhone Distribution',
targets: 'Unity-iPhone',
path: "Builds/iOS/iOS/Unity-iPhone.xcodeproj",
profile_name: ENV["sigh_com.tadashi0713.CircleCIUnityMobileDemo_adhoc_profile-name"],
profile_uuid: ENV["sigh_com.tadashi0713.CircleCIUnityMobileDemo_adhoc"]
)
build_app(
project: "Builds/iOS/iOS/Unity-iPhone.xcodeproj",
scheme: "Unity-iPhone",
configuration: "Debug",
export_method: "ad-hoc",
xcargs: "-allowProvisioningUpdates",
export_options: {
compileBitcode: false
}
)
firebase_app_distribution(
app: "Firebase App ID"
)
end
end
Conclusion
Using CircleCI and GameCI together greatly simplifies the complex task of running Unity builds in a cloud-native environment. Using this approach you can:
- Increase developer productivity via scalable, on-demand, pre-configured build environments
- Reduce tool maintenance overhead by using GameCI to eliminate the need for complex, customized build scripts
- Easily rightsize your build machines by checking resource usage with CircleCI’s resource utilization graphs
If you are struggling to automate your Unity builds in an elegant and maintainable fashion, or if you find yourself spending too much and budget configuring, maintaining, and troubleshooting your self-hosted CI/CD tooling, CircleCI and GameCI are definitely worth a shot. Sign up for your free account and get started today.