Command line builds in Unity3d

I’m working on automating the builds of my Android apps made with Unity. So far, I can build from the command line, here’s how.

I use Linux, but the instructions here should work for Mac and Windows with a little tweaking. I also have the personal version of Unity, you don’t need the paid version for this to work.

The first step I took was to set up a test project on the Play Store. I called it testapp and from now, any app I’m working on will be uploaded as this app. I added an alpha release channel and set a lot of random pictures and setting up to be able to publish it. It’s only going to the alpha channel, so only myself and a couple of others will have it. Having it on the Play store means we all get updates to our phones without having to sideload them or use a USB cable. Useful when the team live in opposite corners of the city.

Now set up unity to be able to build the Android app (APK file) from the UI. You need to go through the build setting page and the player settings. Give it a bundle ID and version number, though those will be overridden by the build script later, so don’t worry too much about what they are.

Down at the bottom of the player settings you’ll find the signing key settings. You can create a keystore, if you don’t already have one, and create a signing key for testapp. Now try building it there in the GUI. Fix anything you need to fix here and get it building manually before moving on.

The play store needs a unique version for every uploaded APK file, so create a file called version.txt in the project root folder. Put the text 0.0.1 in this file so the build script can work from there to ensure all builds have a unique number.

Now create a file called build.cs in the project’s Assets/Editor directory. You’ll probably need to create the Editor directory but Assets should be there already. The following script should get the job done. I’ve redacted a few bits for obvious reasons.

using UnityEngine;
using UnityEditor;

public class CommandBuild {
        static void IncrementBundleVersion() {
        string versionText = System.IO.File.ReadAllText("version.txt");

        if (versionText != null) {
            versionText = versionText.Trim(); //clean up whitespace if necessary
            string[] lines = versionText.Split('.');

            int MajorVersion = int.Parse(lines[0]);
            int MinorVersion = int.Parse(lines[1]);
            int SubMinorVersion = int.Parse(lines[2]) + 1; //increment here

            versionText = MajorVersion.ToString() + "." +
            MinorVersion.ToString() + "." +
            SubMinorVersion.ToString();

            PlayerSettings.bundleVersion = versionText;
            PlayerSettings.Android.bundleVersionCode = SubMinorVersion;
            System.IO.File.WriteAllText("version.txt",versionText);
        }
    }
 
    public static void DoCommonBuildStuff(string outPath) {
        string[] levels = {"Assets/Scenes/MainMenuScene.unity", "Assets/Scenes/Area1.unity" };
 
        PlayerSettings.applicationIdentifier = "com.yourcompany.testapp";
        PlayerSettings.Android.keystorePass = "KEYSTORE_MASTER_PASSWORD_GOES_HERE";
        PlayerSettings.Android.keyaliasName = "testapp";
        PlayerSettings.Android.keyaliasPass = "KEY_PASSWORD_GOES_HERE";

        IncrementBundleVersion();

        BuildPipeline.BuildPlayer(levels, outPath, BuildTarget.Android, BuildOptions.None);
    }

    public static void BuildAndroid() {
        PlayerSettings.Android.keystoreName = "/home/geoff/dev/Keystore/My_Publishing_Keys.keystore";
        DoCommonBuildStuff("/home/geoff/dev/PROJECT_FOLDER/Android/testapp.apk");
    }
}

/home/geoff/dev/Keystore/My_Publishing_Keys.keystore should be replaced with the full path to your keystore. using ~ doesn’t seem to work in these scripts.

/home/geoff/dev/PROJECT_FOLDER should be replaced with your project folder.

As you see, I’ve created a function called BuildAndroid. I’ve snipped it out for the moment, but I have another called BuildAndroidOnMac which does the same, but with different paths so I can run it on my Mac. The script sets a few things on the build, including the version number, then builds it.

This can be triggered with one command, but I’ve written a small shell script to make it even easier. I call it build.sh, but it could be anything.

#!/bin/bash
cd /home/geoff/dev/PROJECT_FOLDER
rm buildlog.txt
/opt/Unity/Editor/Unity -projectpath /home/geoff/dev/PROJECT_FOLDER/ -batchmode -quit -executeMethod CommandBuild.BuildAndroid -logfile /home/geoff/dev/PROJECT_FOLDER/buildlog.txt

Again the project folder name has been redacted, but you’ll want to set it to your project name anyway.

If all goes well, you should have a new testapp.apk file in the Android directory. If not, look in the buildlog.txt file for clues.

If you’re using source control – And you should be. Check build.sh, build.cs and version.txt in. Now anyone who does the build will get an APK with the right version number to upload to the Play Store.

 

I’m currently working on how to automate the upload. A package called Fastlane seems to do what I need, but I haven’t got as far as trying it yet.

2 Replies to “Command line builds in Unity3d”

  1. Hi Geoff,
    thanks for the code you provided, helped a lot.
    However: Please note that especially considering a version control system, the build.cs file might not be the best place to save your password from a security point of view, as it should not leave the build system unencrypted.

Leave a Reply

Your email address will not be published.