Here are my editor scripts to automate building for multiple platforms using SwitchActiveBuildTargetAsync .
To be able to respond to the build target changing multiple times using SwitchActiveBuildTargetAsync we need to be able to schedule tasks on the Editor thread.
This editor script gives us a task scheduler in the editor:
using System.Collections.Generic;
using UnityEditor;
[InitializeOnLoad]
public class EditorMain
{
//Tasks to be executed from editor thread
public delegate void Task();
private static Queue<Task> TaskQueue = new Queue<Task>();
private static object _queueLock = new object();
static EditorMain()
{
EditorApplication.update += Update;
}
static void Update()
{
//Perform any tasks from other threads
lock (_queueLock)
{
if (TaskQueue.Count > 0)
TaskQueue.Dequeue()();
}
}
public static void ScheduleTask(Task newTask)
{
lock (_queueLock)
{
if (TaskQueue.Count < 100)
TaskQueue.Enqueue(newTask);
}
}
}
My editor script for the editor GUI lets me toggle what platforms to build for calling a common build function and switching build target if nessesary. SessionState is used to flag that we are switching targets as part of an automated build:
public override void OnInspectorGUI()
{
///...///
EditorGUILayout.LabelField("Build", EditorStyles.boldLabel);
buildPC = EditorGUILayout.Toggle("Build PC", buildPC);
buildAndroid = EditorGUILayout.Toggle("Build Android", buildAndroid);
///And so on for other platforms///
if (GUILayout.Button("Build"))
{
//Set state for build options
SessionState.SetBool("buildPC", buildPC);
SessionState.SetBool("buildAndroid", buildAndroid);
///And so on for other platforms///
///...///
/////////////////////////////////////////////////////////////////
// PC
if (buildPC)
{
if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.StandaloneWindows)
{
EditorUserBuildSettings.SwitchActiveBuildTargetAsync(BuildTargetGroup.Standalone, BuildTarget.StandaloneWindows);
return;
}
StartBuild(BuildTarget.StandaloneWindows);
}
/////////////////////////////////////////////////////////////////
// Android
if (buildAndroid)
{
if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.Android)
{
EditorUserBuildSettings.SwitchActiveBuildTargetAsync(BuildTargetGroup.Android, BuildTarget.Android);
return;
}
StartBuild(BuildTarget.Android);
}
///And so on for other platforms///
I have a ActiveBuildTargetListener class that needs to modify some objects and settings per platform that will now check the SessionState variables to see if we are in the middle of an automated build and schedule the next build target change if required.
using UnityEditor;
using UnityEditor.Build;
using UnityEngine;
public class ActiveBuildTargetListener : IActiveBuildTargetChanged
{
public int callbackOrder { get { return 0; } }
public void OnActiveBuildTargetChanged(BuildTarget previousTarget, BuildTarget newTarget)
{
BuildPreProcessor.SetupAppForPlatform(newTarget);
#if UNITY_STANDALONE_WIN
Debug.Log("OnActiveBuildTargetChanged UNITY_STANDALONE_WIN");
if (SessionState.GetBool("buildPC", false) == true)
{
SessionState.SetBool("buildPC", false); //clear flag
BuildForPlatformsEditor.StartBuild(BuildTarget.StandaloneWindows);
//postbuild move onto next
ScheduleNextBuild();
}
#elif UNITY_ANDROID
Debug.Log("OnActiveBuildTargetChanged UNITY_ANDROID");
if (SessionState.GetBool("buildAndroid", false) == true)
{
SessionState.SetBool("buildAndroid", false); //clear flag
BuildForPlatformsEditor.StartBuild(BuildTarget.Android);
//postbuild move onto next
ScheduleNextBuild();
}
///And so on for other platforms///
}
void ScheduleNextBuild()
{
if (SessionState.GetBool("buildAndroid", false) == true)
{
EditorMain.ScheduleTask(new EditorMain.Task(delegate { EditorUserBuildSettings.SwitchActiveBuildTargetAsync(BuildTargetGroup.Android, BuildTarget.Android); }));
return;
}
///And so on for other platforms///
}
}
This will automate the build for multiple platforms while preprocessing conditional editor code correctly.