Skip to content

Instantly share code, notes, and snippets.

@hmans
Last active Mar 7, 2021
Embed
What would you like to do?
A basic pipeline for performing headless Unity builds for multiple platforms at once.

Basic Local Unity Build Pipeline

Here's my "local build pipeline" for Unity. It consists of a C# Editor script defining the various build targets and a convenient BuildAll method, and a shell script that invokes the latter method.

Running headless builds like this is a lot less work than switching platforms and triggering builds manually in the editor, and it is most definitely faster than using the god-awfully slow Unity Cloud Build to do it. (In my game, running this local pipeline produces builds for all my targeted platforms in just over 7 minutes on my Macbook Pro, while Unity Cloud Build would often take longer than an hour.)

As you can see from the code, it will read the secrets required for Play Store publishing from the environment. Ideally, in the future it will also source the Android build number like this (or maybe even increment it automatically.)

I'm a perpetual Unity newbie, so if you have any suggestions on how to tweak this further, let me know in the comments!

@hmans, July 2020

/* This needs to live in a folder named "Editor", or it won't work. Doesn't have to be named
"BobTheBuilder", though. Name it whatever you want! */
using System;
using UnityEditor;
using UnityEngine;
public class BobTheBuilder
{
/* List of scenes to include in the build */
public static string[] scenes = { "Assets/HendrikMans/GAMENAME/Scenes/Game.unity" };
[MenuItem("GAMENAME/Build/All Targets")]
public static void BuildAll()
{
BuildHTML5();
BuildWindows();
BuildMacOS();
BuildiOS();
BuildAndroid();
}
[MenuItem("GAMENAME/Build/HTML5 (release)")]
public static void BuildHTML5()
{
Debug.Log("Starting HTML5 Build!");
BuildPipeline.BuildPlayer(
scenes,
"Build/HTML5",
BuildTarget.WebGL,
BuildOptions.None);
}
[MenuItem("GAMENAME/Build/Windows (release)")]
public static void BuildWindows()
{
Debug.Log("Starting Windows Build!");
BuildPipeline.BuildPlayer(
scenes,
"Build/Windows/GAMENAME.exe",
BuildTarget.StandaloneWindows,
BuildOptions.None);
}
[MenuItem("GAMENAME/Build/macOS (release)")]
public static void BuildMacOS()
{
Debug.Log("Starting macOS Build!");
BuildPipeline.BuildPlayer(
scenes,
"Build/macOS/GAMENAME.app",
BuildTarget.StandaloneOSX,
BuildOptions.None);
}
[MenuItem("GAMENAME/Build/Android (release)")]
static void BuildAndroid()
{
Debug.Log("Starting Android Build!");
/* We absolutely do not want to ever store secrets in code (or even add them to
version control), so instead we'll fetch them from the system environment.
Don't forget to set these environment variables before invoking the build script! */
PlayerSettings.Android.keystorePass = Environment.GetEnvironmentVariable("KEY_STORE_PASS");
PlayerSettings.Android.keyaliasPass = Environment.GetEnvironmentVariable("KEY_ALIAS_PASS");
BuildPipeline.BuildPlayer(
scenes,
"Build/Android/GAMENAME.aab",
BuildTarget.Android,
BuildOptions.None);
}
[MenuItem("GAMENAME/Build/iOS (release)")]
static void BuildiOS()
{
Debug.Log("Starting iOS Build!");
BuildPipeline.BuildPlayer(
scenes,
"Build/iOS",
BuildTarget.iOS,
BuildOptions.AcceptExternalModificationsToPlayer);
}
}
#!/usr/bin/env sh
set -e
# Note I've hard-coded the path to the Unity executable. There's probably a million
# ways to make this nicer.
/Applications/Unity/Hub/Editor/2019.4.3f1/Unity.app/Contents/MacOS/Unity \
-batchmode \
-nographics \
-silent-crashes \
-logFile - \
-projectPath $(pwd) \
-quit \
-executeMethod BobTheBuilder.BuildAll
echo "Done!"
@hoonsubin

This comment has been minimized.

Copy link

@hoonsubin hoonsubin commented Nov 6, 2020

This is pretty awesome! Being able to call an editor script through a CLI can really expand the possibilities of what we can do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment