Smash/Riot Logo

Smash/Riot

Focusing on Interactive Media and Unique Experiences

Unity Build Automation

Automatically create and deploy new Unity builds using a command line script

Jesse/SmashRiot

6-Minute Read

Unity Build Automation Banner

All of the different builds needed for Dr. Spacezoo are compiled, packaged, and uploaded via a single monolithic build script. This article will detail the scripting defines, target platform configurations, and other parameters used to automatically build and package for multiple OS platforms.

This build script utilizes Unity’s Command line compiling to set Scripting Define Symbols and Target Platform. These Scripting Define Symbols allow Unity to include/exclude, configure, etc. code and variables based on the build target and other parameters (demo vs full version etc).

Here’s an example of the command line build script compiling, packaging, and uploading the full Win/Mac/Linux version of Dr. Spacezoo:

Unity Build Script : Example Output

Additionally, be sure to read Unity Build Automation with Jenkins as another option for automating builds.

Player settings

Code is excluded or included, and variables are configured based on the Scripting Define Symbols in the Player Settings. The Scripting Define Symbols are set at:

Build Settings -> Player Settings -> Other Settings -> Scripting Define Symbols

Unity Build Script : Unity Player Settings

Here’s an example of setting the APP_NAME string based on the version define in player settings:

#if DRSPACEZOO_VER_DEVELOPMENT
    public const string APP_NAME = "Dev (Alpha)";
#elif DRSPACEZOO_VER_ITCH_FULL
    public const string APP_NAME = "Itch.io (Alpha)";
#elif DRSPACEZOO_VER_ITCH_DEMO
    public const string APP_NAME = "Itch.io (Demo)";
#else
    public const string APP_NAME = "Dev (Alpha)";
#endif

Editor Script

This is how the Scripting Define Symbols and Build Target are set via the build script. Note, to use -executeMethod in the build script, this editor script needs to reside in ProjectName/Assets/Editor/ and the methods to be executed must be defined as static.

using UnityEditor;

// this will set player defines when building from command line
public static class SRSpaceZooBuild {

	// -------------------------------------------------------------------------------------------------
	// -------------------------------------------------------------------------------------------------
	public static void buildVersion_DevelopmentWeb(){

		PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.WebPlayer, "DRSPACEZOO_DEMO,DRSPACEZOO_VER_DEVELOPMENT,DRSPACEZOO_WEBBUILD");
 	}

	// -------------------------------------------------------------------------------------------------
	// -------------------------------------------------------------------------------------------------
	public static void buildVersion_Development(){

		// set before build phase
		PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, "DRSPACEZOO_FULL,DRSPACEZOO_VER_DEVELOPMENT");
 	}

	// -------------------------------------------------------------------------------------------------
	// -------------------------------------------------------------------------------------------------
	public static void buildVersion_ItchFull(){

		// set before build phase
		PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, "DRSPACEZOO_FULL,DRSPACEZOO_VER_ITCH_FULL");
	}

	// -------------------------------------------------------------------------------------------------
	// -------------------------------------------------------------------------------------------------
	public static void buildVersion_ItchDemo(){

		// set before build phase
		PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, "DRSPACEZOO_DEMO,DRSPACEZOO_VER_ITCH_DEMO");
	}
}

Bash Build Script

The bash build script sets the build target, compiles, compresses, uploads, etc. I fire the build script off and come back 15 minutes later to hot and ready builds. Note, Unity needs to be fully closed for this script to work.

Here’s an example build command to build the full Win/Mac/Linux version of Dr. Spacezoo and upload to itch.io: ./buildAll.sh v0.6.3 itch yes

The “-executeMethod SRSpaceZooBuild.buildVersion_x” methods used in the script below are the static methods defined in the Editor script above that set the Scripting Define Symbols for the indicated build target (e.g. Standalone).

#!/bin/bash
clear

# command line parms
APP_VERSION=$1
APP_BUILD=$2
APP_UPDATE_PUSH=$3

# help?
if [ $# -ne 3 ] || [ $APP_VERSION == "help" ] || [ $APP_VERSION == "-?" ] || [ $APP_VERSION == "-h" ]; then
    echo "usage:  ./buildAll.sh v0.x.y type push"
    echo " type: all, web, webgl, itch, itchdemo, steam, magfest, indiedb"
    echo " push: yes, no"
    echo " ./buildAll.sh v0.6.0 itch no"
    echo " ./buildAll.sh v0.6.0 steam yes"
    echo " ./buildAll.sh v0.6.0 all no"
    exit;
fi

# vars
APP_NAME="DrSpacezoo"
APP_NAME_WIN_EXT=".exe"

# set these to your locations
PATH_PROJECT="/Users/user/DrSpacezoo/DrSpacezoo/"
PATH_FINAL_ZIPS="/Users/user/Desktop/builds/final/"
PATH_BUILD="/Users/user/Desktop/builds/auto/"

# I put a symlink from /Users/user/Library/Application Support/itch/bin/butler to this folder.
ITCH_BUTLER_PATH=/Users/user/projectpath/builds/butler # symlink to /Users/user/Library/Application Support/itch/bin/butler
ITCH_BUTLER_CHANNEL_WIN="smashriot/dr-spacezoo:win-release";
ITCH_BUTLER_CHANNEL_OSX="smashriot/dr-spacezoo:osx-release";
ITCH_BUTLER_CHANNEL_LINUX="smashriot/dr-spacezoo:linux-release";
ITCH_BUTLER_VERSION="--userversion";

# build names
PATH_DEV_WEB="DrSpacezoo-Dev-Web"
# itch
PATH_ITCH_WIN_FULL="DrSpacezoo-Itch-Win-Full"
PATH_ITCH_MAC_FULL="DrSpacezoo-Itch-Mac-Full"
PATH_ITCH_LINUX_FULL="DrSpacezoo-Itch-Linux-Full"
# itch demo
PATH_ITCH_WIN_DEMO="DrSpacezoo-Itch-Win-Demo"
PATH_ITCH_MAC_DEMO="DrSpacezoo-Itch-Mac-Demo"
PATH_ITCH_LINUX_DEMO="DrSpacezoo-Itch-Linux-Demo"

# ==========================================
# this moves old build directory and creates a new build directory
# ==========================================
echo "Starting $APP_BUILD builds for $APP_NAME $APP_VERSION."
/bin/mv "/Users/user/Desktop/builds/" "/Users/user/Desktop/builds_old/"
/bin/mkdir "/Users/user/Desktop/builds/"
/bin/mkdir $PATH_BUILD
/bin/mkdir $PATH_FINAL_ZIPS

# ==========================================
# should try to quit unity if it is running or this won't work
# ==========================================
# this doesnt work
#/Applications/Unity/Unity.app/Contents/MacOS/Unity -quit

# ==========================================
# Unity WebPlayer
# ==========================================
if [ $APP_BUILD == "all" ] || [ $APP_BUILD == "web" ]; then
    echo "Building Web:Dev to: $PATH_FINAL_ZIPS$PATH_DEV_WEB"
    /bin/mkdir $PATH_FINAL_ZIPS$PATH_DEV_WEB
    /Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode -executeMethod SRSpaceZooBuild.buildVersion_DevelopmentWeb -projectPath $PATH_PROJECT -buildWebPlayer $PATH_FINAL_ZIPS$PATH_DEV_WEB"/"$APP_NAME -quit
fi

# ==========================================
# ITCH FULL - These now push the app to itch.io via butler
# ==========================================
if [ $APP_BUILD == "all" ] || [ $APP_BUILD == "itch" ]; then
    echo "Building Itch:Win:Full"
    cd $PATH_BUILD
    /bin/mkdir $PATH_ITCH_WIN_FULL
    /Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode -executeMethod SRSpaceZooBuild.buildVersion_ItchFull -projectPath $PATH_PROJECT -buildWindowsPlayer $PATH_BUILD$PATH_ITCH_WIN_FULL"/"$APP_NAME$APP_NAME_WIN_EXT -quit
    echo "Removing PDB files.."
    rm -f $PATH_ITCH_WIN_FULL"/"player_win_x86_s.pdb
    rm -f $PATH_ITCH_WIN_FULL"/"player_win_x86.pdb
    echo "Compressing Itch:Win:Full"
    /usr/bin/zip -r -X -q $PATH_FINAL_ZIPS$PATH_ITCH_WIN_FULL"-"$APP_VERSION".zip" $PATH_ITCH_WIN_FULL
    # example: /Users/user/Library/Application\ Support/itch/bin/butler push DrSpacezoo-Itch-Mac-Full-0.6.3.zip smashriot/dr-spacezoo:osx-release --userversion 0.6.3
    if [ $APP_UPDATE_PUSH == "yes" ]; then
        echo "Pushing to Itch:Win:Full via Butler" #: $ITCH_BUTLER_PATH push $PATH_BUILD$PATH_ITCH_WIN_FULL $ITCH_BUTLER_CHANNEL_WIN $ITCH_BUTLER_VERSION $APP_VERSION"
        $ITCH_BUTLER_PATH "push" "$PATH_BUILD$PATH_ITCH_WIN_FULL" "$ITCH_BUTLER_CHANNEL_WIN" "$ITCH_BUTLER_VERSION" "$APP_VERSION"
    fi

    # --------------
    echo "Building Itch:Mac:Full"
    cd $PATH_BUILD
    /bin/mkdir $PATH_ITCH_MAC_FULL
    /Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode -executeMethod SRSpaceZooBuild.buildVersion_ItchFull -projectPath $PATH_PROJECT -buildOSXPlayer $PATH_BUILD$PATH_ITCH_MAC_FULL"/"$APP_NAME -quit
    # an older version of unity wasn't copying in the icon for Mac, so these two lines fix that issue.
    cp "/Users/user/projectpath/builds/ScreenSelector.tif" $PATH_BUILD$PATH_ITCH_MAC_FULL"/"$APP_NAME".app/Contents/Resources/ScreenSelector.tif"
    cp "/Users/user/projectpath/builds/PlayerIcon.icns" $PATH_BUILD$PATH_ITCH_MAC_FULL"/"$APP_NAME".app/Contents/Resources/PlayerIcon.icns"
    echo "Compressing Itch:Mac:Full"
    /usr/bin/zip -r -X -q $PATH_FINAL_ZIPS$PATH_ITCH_MAC_FULL"-"$APP_VERSION".zip" $PATH_ITCH_MAC_FULL
    if [ $APP_UPDATE_PUSH == "yes" ]; then
        echo "Pushing to Itch:Mac:Full via Butler" #: $ITCH_BUTLER_PATH push $PATH_BUILD$PATH_ITCH_MAC_FULL $ITCH_BUTLER_CHANNEL_OSX $ITCH_BUTLER_VERSION $APP_VERSION"
        $ITCH_BUTLER_PATH "push" "$PATH_BUILD$PATH_ITCH_MAC_FULL" "$ITCH_BUTLER_CHANNEL_OSX" "$ITCH_BUTLER_VERSION" "$APP_VERSION"
    fi

    # --------------
    echo "Building Itch:Linux:Full"
    cd $PATH_BUILD
    /bin/mkdir $PATH_ITCH_LINUX_FULL
    /Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode -executeMethod SRSpaceZooBuild.buildVersion_ItchFull -projectPath $PATH_PROJECT -buildLinuxUniversalPlayer $PATH_BUILD$PATH_ITCH_LINUX_FULL"/"$APP_NAME -quit
    echo "Compressing Itch:Linux:Full"
    /usr/bin/zip -r -X -q $PATH_FINAL_ZIPS$PATH_ITCH_LINUX_FULL"-"$APP_VERSION".zip" $PATH_ITCH_LINUX_FULL
    if [ $APP_UPDATE_PUSH == "yes" ]; then
        echo "Pushing to Itch:Linux:Full via Butler" #: $ITCH_BUTLER_PATH push $PATH_BUILD$PATH_ITCH_LINUX_FULL $ITCH_BUTLER_CHANNEL_LINUX $ITCH_BUTLER_VERSION $APP_VERSION"
        $ITCH_BUTLER_PATH "push" "$PATH_BUILD$PATH_ITCH_LINUX_FULL" "$ITCH_BUTLER_CHANNEL_LINUX" "$ITCH_BUTLER_VERSION" "$APP_VERSION"
    fi
fi

# ==========================================
# ITCH DEMO - does not auto push
# ==========================================
if [ $APP_BUILD == "all" ] || [ $APP_BUILD == "itchdemo" ]; then
    echo "Building Itch:Win:Demo"
    cd $PATH_BUILD
    /bin/mkdir $PATH_ITCH_WIN_DEMO
    /Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode -executeMethod SRSpaceZooBuild.buildVersion_ItchDemo -projectPath $PATH_PROJECT -buildWindowsPlayer $PATH_BUILD$PATH_ITCH_WIN_DEMO"/"$APP_NAME$APP_NAME_WIN_EXT -quit
    echo "Removing PDB files.."
    rm -f $PATH_ITCH_WIN_DEMO"/"player_win_x86_s.pdb
    rm -f $PATH_ITCH_WIN_DEMO"/"player_win_x86.pdb
    echo "Compressing Itch:Win:Full"
    /usr/bin/zip -r -X -q $PATH_FINAL_ZIPS$PATH_ITCH_WIN_DEMO"-"$APP_VERSION".zip" $PATH_ITCH_WIN_DEMO

    # --------------
    echo "Building Itch:Mac:Demo"
    cd $PATH_BUILD
    /bin/mkdir $PATH_ITCH_MAC_DEMO
    /Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode -executeMethod SRSpaceZooBuild.buildVersion_ItchDemo -projectPath $PATH_PROJECT -buildOSXPlayer $PATH_BUILD$PATH_ITCH_MAC_DEMO"/"$APP_NAME -quit
    cp "/Users/user/projectpath/builds/ScreenSelector.tif" $PATH_BUILD$PATH_ITCH_MAC_DEMO"/"$APP_NAME".app/Contents/Resources/ScreenSelector.tif"
    cp "/Users/user/projectpath/builds/PlayerIcon.icns" $PATH_BUILD$PATH_ITCH_MAC_DEMO"/"$APP_NAME".app/Contents/Resources/PlayerIcon.icns"
    echo "Compressing Itch:Mac:Demo"
    /usr/bin/zip -r -X -q $PATH_FINAL_ZIPS$PATH_ITCH_MAC_DEMO"-"$APP_VERSION".zip" $PATH_ITCH_MAC_DEMO

    # --------------
    echo "Building Itch:Linux:Demo"
    cd $PATH_BUILD
    /bin/mkdir $PATH_ITCH_LINUX_DEMO
    /Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode -executeMethod SRSpaceZooBuild.buildVersion_ItchDemo -projectPath $PATH_PROJECT -buildLinuxUniversalPlayer $PATH_BUILD$PATH_ITCH_LINUX_DEMO"/"$APP_NAME -quit
    echo "Compressing Itch:Linux:Demo"
    /usr/bin/zip -r -X -q $PATH_FINAL_ZIPS$PATH_ITCH_LINUX_DEMO"-"$APP_VERSION".zip" $PATH_ITCH_LINUX_DEMO
fi

# ==========================================
# FESTIVAL BUILD -- ATTRACT MODE++
# ==========================================
if [ $APP_BUILD == "festival" ]; then
    echo "Copying Attract Movie to StreamingAssets"
    cp "/Users/username/projectpath/AttractMode/attract.ogg" $PATH_PROJECT"Assets/StreamingAssets/attract.ogg"
    echo "Building Festival:Mac:Full"
    cd $PATH_BUILD
    /bin/mkdir $PATH_FESTIVAL_MAC
    /Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode -executeMethod SRSpaceZooBuild.buildVersion_Festival -projectPath $PATH_PROJECT -buildOSXPlayer $PATH_BUILD$PATH_FESTIVAL_MAC"/"$APP_NAME -quit
    cp "/Users/username/projectpath/builds/ScreenSelector.tif" $PATH_BUILD$PATH_FESTIVAL_MAC"/"$APP_NAME".app/Contents/Resources/ScreenSelector.tif"
    cp "/Users/username/projectpath/builds/PlayerIcon.icns" $PATH_BUILD$PATH_FESTIVAL_MAC"/"$APP_NAME".app/Contents/Resources/PlayerIcon.icns"
    echo "Compressing Festival:Mac:Full"
    /usr/bin/zip -r -X -q $PATH_FINAL_ZIPS$PATH_FESTIVAL_MAC"-"$APP_VERSION".zip" $PATH_FESTIVAL_MAC
    echo "Removing Attract Movie from StreamingAssets"
    rm -f $PATH_PROJECT"Assets/StreamingAssets/attract.ogg"
    rm -f $PATH_PROJECT"Assets/StreamingAssets/attract.ogg.meta"
fi

# ==========================================
# ==========================================
echo "Done!"

Note: The wonderful Amos from itch.io suggests pointing butler at the build output folder instead of the packaged zip to save butler from having to uncompress the zip first.

Steam Upload

The above show itch.io uploads, but can also update Steam via steamcmd:

    # push to steam
    if [ $APP_UPDATE_PUSH == "yes" ]; then
        echo "Uploading to Steam via SteamPipe"
        cd $PATH_STEAMPIPE
        ./steamcmd.sh +login username +run_app_build steam_script_location/app_build_123456.vdf +quit
        echo "Steam Upload Complete. Remember to visit Steamworks and set build live"
    fi

Helpful References

In Closing

Hope you found this article on build script automation for Unity interesting,

Jesse from Smash/Riot

Recent Posts

About

Smash/Riot LLC focuses on interactive media, virtual experiences, games, visual effects, VR/AR, and networked experiences for modern platforms.