This post is written by Mina Pêcheux
TL;DR: The Unity Cloud Content Delivery tool is a solution that helps deliver data to users in a synchronized way, which speeds up patching and enables live game updates. And by integrating CCD with Codemagic you can update your cloud content across all platforms and cloud environments at once, whenever you update your game and without error prone and tedious manual work. Ensuring that all your users always get the latest experience as intended.
Did you know you can set up an online bucket of data to make your Unity game updates a walk in the park?
While beginner projects are usually quite small, they quickly start to grow in size as they approach the production stage since high-quality assets tend to weigh a lot. Does that mean that each time you plan on updating your game to patch bugs or add some new content, you’ll have to force your customers to redownload the entire game from the stores, wasting gigabytes of traffic?
Fortunately, it doesn’t. There are multiple ways to avoid this problem. In this post, we’ll be looking at one such solution — the Unity Cloud Content Delivery (CCD) tool. The goal of this service is to use the power of the net to easily deliver data to everyone in a synchronized way and still make it easy to properly re-assemble the outsourced assets with the code and 3D scenes once inside the game.
If you’re already familiar with CCD and have a project ready, you can skip to the automation part! 🙂
Anyhow, in this post, I want to:
- Give a quick overview of what Unity CCD is
- Use a super-simple sample project as a reference to show how to configure a new Unity CCD setup from scratch
- Improve on this configuration and demonstrate how to use Codemagic to automate the synchronization of assets with the game builds
What is the Cloud Content Delivery (CCD) tool?
Unity Cloud Content Delivery is a cloud service that lets us easily store resources online and then deliver them to all the users of our app across the world without forcing them to redownload anything. Simply put, it’s an easy-to-use, fully integrated Unity tool that helps separate the code from the assets so that any bug fix or live data update is a breeze to manage.
We can obviously build our own setup with custom tools, but CCD is really quick to configure and straightforward to use, and it offers 50 GB of bandwidth per month for free when you first start. After that, you’ll pay as you go, which makes it possible to scale your app at your own pace and try out the tool without any financial commitments to see if it fits your workflow.
CCD mostly relies on a system of environments, buckets, entries, and releases.
The environments are similar to namespaces: They allow you to publish content for a given audience or production stage and to have multiple versions in parallel.
The buckets are the core elements of the CCD system — they are the storage units you’ll put your files (called “entries”) in. Usually, you create different buckets for each build target based on your project needs; and of course, you can set these up with Unity’s new Addressables tool to streamline content to your game and get perfectly self-contained assets.
The entries themselves are individual files: They can be images, text files, XML data, asset bundles… the tool accepts a very wide diversity of file types! This is the strength of CCD: You can extract whatever chunk of your game data you want to make it more flexible for further updates. 🙂
Finally, the releases allow us to take a snapshot of the current state of the bucket and mark all the recently added, updated, or removed entries as ready for delivery.
Note: If you want to have full control over which release is currently in use, then you can take advantage of the badges, too — take a look at the official docs for more details!
Setting up the Unity CCD project
For this article, I’ll work with a sample Unity Android app I prepared: The “Shape Browser”. The project in itself is pretty basic — it simply lets you pick one of the three available primitive shapes, change its colors, and optionally set a texture. (Check out the bottom of the article for the link to the GitHub repo!)
This sample project doesn’t have a lot of resources, so it would probably be a bit overkill to use CCD in a real production… but it will be handy to introduce the basics of the service. I will be using a CCD bucket to store all of my images, i.e., all of the files in the Assets/Images
folder:
But before we are able to send any files via CCD, we actually have to prepare a project on the CCD platform and prepare a bucket to store our resources in. We’ll also take this opportunity to write down some useful IDs or keys that we will use in the following section to call the service via the terminal.
First, head over to the Unity Dashboard, and log into your Unity ID account (or create one if you don’t yet have one). You’ll be presented with a general dashboard that shows you the various Unity Gaming Services and lets you create a new project.
When you click the “Create project” button, you’ll be shown a pop-up to set up the basic info about your project — in my case, I just need to fill in the name:
After you’ve created the project, you’ll have access to its detailed dashboard. This is where you can add the various modules for analyzing, testing, and overall monitoring of your game — to see all that’s available, just go to the “Explore Services” menu on the left:
In particular, you can scroll down (and optionally filter using the “LiveOps” tag) to find the CCD tool. Just click on it to add it to your app project:
However, you’ll notice that by default, CCD is not actually active: You’ll have to start your free trial first!
Even though the first 50 GB are completely free, this will require you to give some credit card info just to properly set up your Unity ID account for gaming services. Simply follow the instructions until you get to the confirmation order page, where you can click the “Complete onboarding” button:
From that point on, you can go back to your Unity project dashboard and start to use the CCD tool! Now, it’s time to download the command-line tool (CLI) to call the CCD APIs via a terminal:
You can see that the CLI is available for the various OSes. Since we’ll be testing manual CCD synchronization in the next part, you will need to download the CLI that matches your local computer’s OS from this page:
The next step is to get our API key, which you can find in the “API Key” section in the project menu. Keep in mind that it’s specific to your account and CCD and can’t be used for any other purposes.
Finally, we have to prepare a bucket to store our contents in. Just click on the “Buckets” menu in your project menu:
Here, you can create a new bucket — I simply gave it the name (“Android Content”) and left all the default settings:
When the bucket is created, you’ll need to get its ID, which we’ll use in the next section to upload our resources via shell commands.
By the way, we also need to get another piece of data from the dashboard before we leave: the ID of our default environment. This will be a necessary parameter for our command-line upload, but sadly, Unity’s dashboard UI doesn’t yet make it easy to find. (They’re apparently working on it, though!)
The trick is to go to the bucket we just created and click on the link on the right that says, “Upload content to create your first release” (see the picture above). There, you’ll find various techniques to upload the assets, including the terminal method, with some useful commands that contain the environment ID:
Pausing for just a second
OK, so at this point, we have:
- Our Git repo with all of the codebase and the assets on the one side
- The CCD bucket ready to be filled on the other side
It’s crucial to understand that these two repos have to coexist and that you can’t simply “merge” them together — they are used for different things. Your main repo contains all the files of your project, and it is the usual snapshot you want of all your codebase and resources at a given time. The CCD bucket is a specific “mirror” of your assets with a bunch of nice labels and release versions bound to it so that you can easily serve this version of your assets to your customers.
However, the assets in your CCD buckets still have to live in your main repo too. (For starters, you actually need them for the build!)
Using CCD manually
With that said, let’s give CCD a try. First, we’ll do a manual release of our assets to get more familiar with the system. All I need to do is download the CCD CLI tool (from the download page we saw before) on my local computer and unzip it.
Note: If you want to add the ucd
executable inside the archive to your PATH
to make it accessible from anywhere, feel free to do so — I’m just going to move it to my current project directory to make things simpler. 😉
Then, I’ll head over to my project in a terminal and log in to my CCD service using the API key:
./ucd auth login <api-key>
If all goes well, we get a message that says “Login successful.” We’re now connected to the CCD, and we can start interacting with the buckets, releases, and so on.
In particular, we can set our default bucket to be the “Android Content” one with our bucket ID and our environment ID:
./ucd config set bucket <bucket-id> --environment <environment-id>
When the operation is finished, the tool will log the updated config:
Successfully switched to bucket <bucket-id>.
Currently active project: <project-id>.
Currently active environment: <environment-id>.
Currently active bucket: <bucket-id> (Android Content).
Finally, we just have to actually synchronize the files we want to store and deliver through CCD for our project. In our case, these are the images inside the Assets/Images
folder. The command to use is pretty straightforward:
./ucd entries sync Assets/Images --environment <environment-id>
As usual, the CLI will log the result to help you verify that everything went well by listing the files it added to the bucket:
Calculating...
Added Entry: icon-checker.png.meta
Added Entry: icon-cylinder.png
Added Entry: icon-dots.png.meta
Added Entry: icon-cube.png.meta
...
Complete! Bytes uploaded: 200783
However, at this point, if you go to your Unity Dashboard and take a look at the buckets list, you’ll see that nothing has changed: The bucket seems to still be waiting for some content…
That’s because, at this point, we have synced the files but haven’t actually created a release. So, basically, our changes haven’t been published.
Once again, the CLI has a nice command for this:
./ucd releases create --environment <environment-id>
This time, when you refresh your CCD buckets list in the Unity Dashboard, you’ll notice that your “Android Content” bucket contains a new release (auto-numbered “Release 1”, obviously):
You can click on it to get more info and, in particular, check the various files that were tracked by this release:
That’s great! We’ve successfully synced our assets with the CCD bucket, so our CCD tool can now track, version, and deliver the various resources in our games!
The really cool thing is that at this point, if we change assets and want to “redistribute” them to our customers without asking them to redownload stuff, we can re-sync the data, and the CCD tool will help us auto-deliver the goods properly. 🙂
Auto-syncing the CCD assets in a Codemagic workflow
But wait — what if we change the code and create a completely new build of the app? We should ensure the customers get all the new updates at once, including the images, right? Except we previously said that our Git repo and the CCD buckets are codependent but separated…?
Also, given that CCD has you (generally) use different buckets for each platform and that you typically set it up when you plan on updating your content often (for example, for a live game), running all of the commands we saw before manually every time for every bucket can get tedious and error prone. That’s why lots of developers prefer to use automation tools that have a predefined set of steps to run and thereby avoid inconsistencies during releases. 😉
For example, Codemagic can help you make a more robust pipeline by always executing the CCD synchronization and Unity project build together. Furthermore, because it temporarily lends you a machine to run your workflow, you can actually request a different OS than the one(s) you have and thus build for even more platforms! For more info about Codemagic, check out this article.
Note: To use Codemagic, you need to version your Unity project with Git and then publish it on a common Git provider, like GitHub, GitLab, or Bitbucket.
Basically, for my sample project, I’ll just need to ensure that:
- My Unity project is properly configured for building Android Unity apps, as explained here
- I have all the required API keys and IDs for my Unity CCD project, its buckets, and its environments
- My project repository contains a script to build my project via the command line (this is the equivalent of opening the “Build settings…” panel and clicking on the “Build” button, but it can be called from a terminal)
- Finally, my project repo also contains a configuration file,
codemagic.yaml
, to specify which steps to run in which order whenever I start a new build process
Setting up the Codemagic app with CCD
If you’re not familiar with Codemagic and want to see how to set up an app step by step, take a look at the docs. Also, in case you aren’t a Codemagic user yet, you can sign up here:
The only thing to keep in mind here is that we have to define several environment variables for the workflow to work properly. These are essential to properly secure passwords and other sensitive data — in short, you use a variable in the (publicly versioned) command lines, and then you give them actual (private) values in your Codemagic app’s settings.
Here, we want to create several variables and split them into three groups: “unity”, “keystore_credentials”, and “ccd”:
The various values for the “unity” and “keystore_credentials” variables are discussed here. As for the “ccd” variables, they are pretty self-explanatory:
CCD_API_KEY
: This is the global API key we found in the dashboard — it allows us to log in to our Unity CCD service from the terminal to run the synchronizationCCD_BUCKET_ID
: This is the ID of the bucket you want to synchronizeCCD_ENVIRONMENT_ID
: This is the ID of the environment you want to use for storage
Preparing our automation files
Now that the app is ready, it’s time to add the automation-related files and try it out!
The build script simply calls various Unity APIs to build the project for Android — you can see what this file looks like here.
The codemagic.yaml
file allows us to specify the basic environment configuration we want on the machine and then run shell commands to perform our tasks. For example, in this case, we can use the following setup:
workflows:
unity-android-workflow:
name: Unity Android Workflow
max_build_duration: 120
environment:
groups:
- unity # <-- (Includes UNITY_HOME, UNITY_SERIAL, UNITY_USERNAME and UNITY_PASSWORD)
- keystore_credentials # <-- (Includes CM_KEYSTORE, CM_KEYSTORE_PASSWORD, CM_KEY_PASSWORD, CM_KEY_ALIAS)
- ccd # <-- (Includes CCD_API_KEY, CCD_BUCKET_ID, CCD_ENVIRONMENT_ID)
vars:
UNITY_BIN: ${UNITY_HOME}/Contents/MacOS/Unity
PACKAGE_NAME: "com.minapecheux.ShapeBrowser"
scripts:
- name: Login+Sync CCD
script: |
ucd entries sync ./Assets/Images --apikey ${CCD_API_KEY} --bucket ${CCD_BUCKET_ID} --environment ${CCD_ENVIRONMENT_ID}
ucd releases create --apikey ${CCD_API_KEY} --bucket ${CCD_BUCKET_ID} --environment ${CCD_ENVIRONMENT_ID}
- name: Activate Unity License
script: |
${UNITY_BIN} -batchmode -quit -logFile -serial ${UNITY_SERIAL?} -username ${UNITY_USERNAME?} -password ${UNITY_PASSWORD?}
- name: Set up keystore
script: |
echo ${CM_KEYSTORE} | base64 --decode > ${CM_BUILD_DIR}/keystore.keystore
- name: Set build number and export Unity
script: |
export NEW_BUILD_NUMBER=$(($(google-play get-latest-build-number --package-name "$PACKAGE_NAME" --tracks=alpha) + 1))
${UNITY_BIN} -batchmode -quit -logFile -projectPath . -executeMethod BuildScript.BuildAndroid -nographics
artifacts:
- android/*.apk
publishing:
scripts:
- name: Deactivate Unity License
script: ${UNITY_BIN} -batchmode -quit -returnlicense -nographics
The first lines are general info or constraints on the workflow, and the environment
block lets us import and/or define environment variables for our pipeline. You can see that we just recall the name of the environment variable groups we prepared to directly re-inject all the variables they contain.
Then, the script
part is the true meat of the file: In this workflow config, I use the preinstalled Unity CCD command-line tools to access the bucket I prepared and synchronize the assets inside. Finally, I activate my Unity license, prepare my Android keystore credentials, build the game, and deactivate the license.
You’ll notice that the command that actually uses the CCD CLI to synchronize the files integrates all the environment variables we took from the Unity Dashboard and added as environment variables.
Trying out the pipeline and checking our uploaded resources
Every time this pipeline is run, we’ll re-update our CCD resources to their latest version and build the associated game version (which we can then download from the Codemagic build page as a ZIP “artifact”).
As you can see, synchronizing assets with the Unity CCD tool is actually very fast. Of course, it depends on the amount and size of your resources, but in this case, it takes just three seconds!
Now that I have run my automated workflow, I have an up-to-date version of my game, and if I go back to my Unity CCD project bucket dashboard, I see that my “Android Content” bucket has another release, “Release 2”:
Again, we can see more details. In particular, we can check out the list of releases and see their badges!
Conclusion
Finding the right architecture for a Unity game and its contents can be hard, and usually, the more complex the project, the larger the number of assets it has. But nowadays, tools like the Unity CCD help us better organize our projects and decouple resources from code. Adding a little varnish of automation on top with extra services like Codemagic is also a nice way to avoid any unwanted inconsistencies when you build a new version.
I hope you enjoyed this tutorial — and of course, don’t hesitate to share your ideas for other DevOps topics you’d like me to make Unity tutorials on!
You can check out the sample project for the entire “Shape Browser” project on GitHub over here. 🚀 If you got stuck while following the steps in this tutorial, you can always talk to Codemagic support on Slack. Also, the docs for getting started with Codemagic and Unity can be found here. Or use the contact form below to schedule a call with us!
Mina Pêcheux is a freelance full-stack web & game developer. She’s also passionate about computer graphics, music, data science, and other topics! She runs her own blog. Alternatively, you can find her on Twitter.
Discussion about this post