Synamon’s Engineer blog

Synamonはリアルとデジタルの融合を加速させるため、メタバース領域で法人向けにサービス提供を行うテックカンパニーです。現在開発を進めている「メタバース総合プラットフォーム」をはじめ、メタバース市場の発展に向けた事業展開を行っています。このブログでは、メタバース技術とその周辺の技術、開発全般に関してエンジニアがお話しします。

UnityのBuildSettingsウィンドウの表記とスクリプティングAPIの対応を纏めました(Unity 2021.3.0f1)


エンジニアの岡村です。

Unityのアプリ開発をチームで行う際は、Git等のバージョン管理ツールがほぼ必ず使われます。これを使って他のメンバーとプロジェクトフォルダを共有するのですが、Unityをビルドする際に使われる設定の中にはプロジェクトフォルダの外に保存されるものがあります。

Editorの再生ボタンを叩いている間であれば問題になる事は少ないです。ですが、ビルドしたときの挙動を検証したい時など、作業者それぞれのPCでビルド設定が異なっていると正しく現象を再現できないことがあります。

また、CIで自動ビルドを行う際にも、ビルドマシン上でGUIを開き設定を変えなければなりませんし、普段確認できないために設定が変わっても気づかず、そうするといつの間にかおかしな状態に……という事もあります。これらの問題を解決するためにプロジェクト外に保存される設定も、少なくとも社内テスト版やリリース版に関しては設定内容のバージョン管理をしたくなります。

そこで、弊社のプロジェクトではそれらの設定をC#スクリプトから上書きすることにより、CIワークフローの一部としてプロジェクトフォルダ内で(コードとして)バージョン管理出来るようにしています。


プロジェクトフォルダに保存されない設定は、外部アプリケーションや実行環境に依存するようなものを除き、基本的にはBuild Settingsウィンドウに集約されています。このウィンドウはGUIベースで操作する分には幾分直感的なのですが、GUIの表記とC#のAPIが一致していなかったり名前空間が別の場所にあったり等、内部はかなりカオスになっています。公式ドキュメントもあまり詳しい情報が乗っていません。自分がBuild Settingsをコードから触ろうとした時には項目一つ一つについて調べる必要があった為そこそこ時間を取られました。

なので、今後自分や他の人が参考にするために、Build SettingsウィンドウとC#スクリプトの対応付けを今回テックブログの記事として紹介することにしました。

前提

環境はUnity 2021.3.0f1です。バージョンが前後するとBuild Settingsの内容も変化している可能性がありますのでご了承ください。

Build Settingsの多くの設定項目のAPIは EditorUserBuildSettingsBuildPlayerOptions に含まれています。それらのAPI呼び出しを以下の様なC#コードで記述し検証しました。

using System.Linq;
using UnityEditor;
using UnityEngine;

public static class BuildScript
{
    [MenuItem("Build/Windows")]
    public static void BuildWindows()
    {
        var buildPlayerOptions = new BuildPlayerOptions();

        // ここにBuild Settingsの内容をコードで書く

        var report = BuildPipeline.BuildPlayer(buildPlayerOptions);

        Debug.Log(report.summary.result);
    }
}

ビルドプラットフォームについて

Build Settingsウィンドウにはビルドターゲットのプラットフォーム指定をするUI(以下の画像における黄色の領域)があるのですが、ちょっと複雑なので事前に説明します。

ビルドプラットフォームの指定は、UIにおいてはPlatform, Target Platform, Architectureという表示になっていますが、それぞれBuildTargetGroup, BuildTarget, BuildSubtargetに(一部)対応しています。

それぞれ別のEnumの値を指定する必要があり、かなり複雑に見えますが、実際の所、中身はStandalone周りが多少パターンが多いくらいで、全体として有効な組み合わせの数は少なくなっています。

BuildTargetGroup BuildTarget BuildSubtarget
Unknown
Standalone StandaloneWindows StandaloneBuildSubtarget.Player
Standalone StandaloneWindows StandaloneBuildSubtarget.Server
Standalone StandaloneWindows64 StandaloneBuildSubtarget.Player
Standalone StandaloneWindows64 StandaloneBuildSubtarget.Server
Standalone StandaloneOSX StandaloneBuildSubtarget.Player
Standalone StandaloneOSX StandaloneBuildSubtarget.Server
Standalone StandaloneLinux64 StandaloneBuildSubtarget.Player
Standalone StandaloneLinux64 StandaloneBuildSubtarget.Server
iOS iOS
Android Android
WebGL WebGL
WSA WSAPlayer
PS4 PS4
XboxOne XboxOne
tvOS tvOS
Switch Switch
Stadia Stadia
CloudRendering CloudRendering
PS5 PS5

C#で実際に指定する場合は以下のように書きます。

buildPlayerOptions.targetGroup = BuildTargetGroup.Standalone;
buildPlayerOptions.target = BuildTarget.StandaloneWindows64;
buildPlayerOptions.subtarget = (int)StandaloneBuildSubtarget.Player; // デフォルトがPlayerなので省略可能

また、NamedBuildTarget というenumを使ったプラットフォーム指定方法もありますが、こちらは後に紹介するコードでは使っていないため詳細は割愛します。Dedicated ServerへのSwitch Platformにはこれを使います。

EditorUserBuildSettings.SwitchActiveBuildTarget(NamedBuildTarget.Server, BuildTarget.StandaloneWindows64);

Architectureの指定について

WindowsのArchitectureはBuildTargetに含まれていますが、macOSでは指定方法が異なります。

Windows

buildPlayerOptions.target = BuildTarget.StandaloneWindows64;

macOS

#if UNITY_STANDALONE_OSX
UnityEditor.OSXStandalone.UserBuildSettings.architecture = UnityEditor.OSXStandalone.MacOSArchitecture.x64ARM64;
#endif

余談:ビルド時にプラットフォームを切り替えてもビルドスクリプト中の#if分岐は有効にならない

本筋とはあまり関係ありません。

前述のmacOSにおけるアーキテクチャの指定は、UnityEditorにmacOSビルド用のモジュールをインストールしていないとコンパイルエラーになってしまいます。UNITY_STANDALONE_OSXシンボルが有効になっているならばmacOSプラットフォームにSwitch Platform済、つまりmacOSビルド用のモジュールがインストール済みであるので、これを特定プラットフォーム限定のビルド設定にアクセスする為の判定に使っています。しかし、ビルドスクリプト内でSwitch Platformを呼び出していると、ビルドスクリプト自身に対してシンボルの切り替えが反映されず、#ifで囲まれた部分がスキップされてしまうという問題をはらんでいます。

解決するにはコマンドライン引数の -buildTarget を使い、最初からプラットフォームを指定して起動するか、SwitchPlatformを実行するだけのステップと、ビルドを行うステップに分けて、2回スクリプトを実行する等の対策が必要になります。

もしくは、もう一つの解決策として、SetPlatformSettingsを使うことで特定モジュールに依存せずにプラットフォーム限定の設定を行うことも可能ですが、こちらはどんなキーがありどんな値があるのかのドキュメントが存在しておらずあまり触れていません。一応以下の様に記述することでmacOSのアーキテクチャ指定が機能することは確認しています。

EditorUserBuildSettings.SetPlatformSettings("Standalone", "OSXUniversal", "Architecture", "x64");

Build Settings 一覧

本題のBuild SettingsとC#の対応一覧です。

Windows, Mac, Linux, (Dedicated Server), Android, iOS, WebGLの調査を行いました。スクリーンショットと比較して扱いやすいよう、かなり冗長に記載しています。また、外部のデバイスやプログラムに強く依存するような(手動でビルドするときに使うような)項目は調査していません。

ちなみに、Dedicated ServerのBuild SettingsはWindows, Mac, Linuxとの違いはありませんでした。

Windows

var buildPlayerOptions = new BuildPlayerOptions();

// Platform
buildPlayerOptions.targetGroup = BuildTargetGroup.Standalone;
buildPlayerOptions.subtarget = (int)StandaloneBuildSubtarget.Player;

// Target Platform & Architecture
buildPlayerOptions.target = BuildTarget.StandaloneWindows;
buildPlayerOptions.target = BuildTarget.StandaloneWindows64;

#if UNITY_STANDALONE_WIN

// Copy PDB files
UnityEditor.WindowsStandalone.UserBuildSettings.copyPDBFiles = false;

// Create Visual Studio Solution
UnityEditor.WindowsStandalone.UserBuildSettings.createSolution = false;

#endif

// Development Build
buildPlayerOptions.options |= BuildOptions.Development;

// Autoconnect Profiler
buildPlayerOptions.options |= BuildOptions.ConnectWithProfiler;

// Deep Profiling
buildPlayerOptions.options |= BuildOptions.EnableDeepProfilingSupport;

// Script Debugging
buildPlayerOptions.options |= BuildOptions.AllowDebugging;

// IL2CPP Code Generation = Faster runtime
EditorUserBuildSettings.il2CppCodeGeneration = Il2CppCodeGeneration.OptimizeSpeed;

// IL2CPP Code Generation = Faster (smaller) builds
EditorUserBuildSettings.il2CppCodeGeneration = Il2CppCodeGeneration.OptimizeSize;

// Compression Method = LZ4
buildPlayerOptions.options |= BuildOptions.CompressWithLz4;

// Compression Method = LZ4HC
buildPlayerOptions.options |= BuildOptions.CompressWithLz4HC;

// createSolution=trueの場合は拡張子に.slnを指定する
buildPlayerOptions.locationPathName = "Builds/Build.exe";
var report = BuildPipeline.BuildPlayer(buildPlayerOptions);
Debug.Log(report.summary.result);

macOS

var buildPlayerOptions = new BuildPlayerOptions();

// Platform
buildPlayerOptions.targetGroup = BuildTargetGroup.Standalone;
buildPlayerOptions.subtarget = (int)StandaloneBuildSubtarget.Player;

// Target Platform
buildPlayerOptions.target = BuildTarget.StandaloneOSX;

#if UNITY_STANDALONE_OSX

// Architecture
UnityEditor.OSXStandalone.UserBuildSettings.architecture = UnityEditor.OSXStandalone.MacOSArchitecture.x64ARM64;

// Create Xcode Project
UnityEditor.OSXStandalone.UserBuildSettings.createXcodeProject = false;

#endif

// Development Build
buildPlayerOptions.options |= BuildOptions.Development;

// Autoconnect Profiler
buildPlayerOptions.options |= BuildOptions.ConnectWithProfiler;

// Deep Profiling
buildPlayerOptions.options |= BuildOptions.EnableDeepProfilingSupport;

// Script Debugging
buildPlayerOptions.options |= BuildOptions.AllowDebugging;

// IL2CPP Code Generation = Faster runtime
EditorUserBuildSettings.il2CppCodeGeneration = Il2CppCodeGeneration.OptimizeSpeed;

// IL2CPP Code Generation = Faster (smaller) builds
EditorUserBuildSettings.il2CppCodeGeneration = Il2CppCodeGeneration.OptimizeSize;

// Compression Method = LZ4
buildPlayerOptions.options |= BuildOptions.CompressWithLz4;

// Compression Method = LZ4HC
buildPlayerOptions.options |= BuildOptions.CompressWithLz4HC;

// createXcodeProject=trueにした場合は拡張子に.xcodeprojを指定する
buildPlayerOptions.locationPathName = "Builds/Build.app";
var report = BuildPipeline.BuildPlayer(buildPlayerOptions);

Debug.Log(report.summary.result);

Linux

var buildPlayerOptions = new BuildPlayerOptions();

// Platform
buildPlayerOptions.targetGroup = BuildTargetGroup.Standalone;
buildPlayerOptions.subtarget = (int)StandaloneBuildSubtarget.Player;

// Target Platform
buildPlayerOptions.target = BuildTarget.StandaloneLinux64;

// Development Build
buildPlayerOptions.options |= BuildOptions.Development;

// Autoconnect Profiler
buildPlayerOptions.options |= BuildOptions.ConnectWithProfiler;

// Deep Profiling
buildPlayerOptions.options |= BuildOptions.EnableDeepProfilingSupport;

// Script Debugging
buildPlayerOptions.options |= BuildOptions.AllowDebugging;

// IL2CPP Code Generation = Faster runtime
EditorUserBuildSettings.il2CppCodeGeneration = Il2CppCodeGeneration.OptimizeSpeed;

// IL2CPP Code Generation = Faster (smaller) builds
EditorUserBuildSettings.il2CppCodeGeneration = Il2CppCodeGeneration.OptimizeSize;

// Compression Method = LZ4
buildPlayerOptions.options |= BuildOptions.CompressWithLz4;

// Compression Method = LZ4HC
buildPlayerOptions.options |= BuildOptions.CompressWithLz4HC;

buildPlayerOptions.locationPathName = "Builds/Build.x86_64";
var report = BuildPipeline.BuildPlayer(buildPlayerOptions);

Debug.Log(report.summary.result);

Android

var buildPlayerOptions = new BuildPlayerOptions();

// Platform
buildPlayerOptions.targetGroup = BuildTargetGroup.Android;
buildPlayerOptions.target = BuildTarget.Android;

// Texture Compression = Use Player Settings
EditorUserBuildSettings.androidBuildSubtarget = MobileTextureSubtarget.Generic;

// ETC2 fallback
EditorUserBuildSettings.androidETC2Fallback = AndroidETC2Fallback.Quality32Bit;

// Export Project
EditorUserBuildSettings.exportAsGoogleAndroidProject = false;

// Symlink Sources
EditorUserBuildSettings.symlinkSources = false;

// Build App Bundle (Google Play)
EditorUserBuildSettings.buildAppBundle = true;

// Create symbols.zip
EditorUserBuildSettings.androidCreateSymbols = AndroidCreateSymbols.Disabled;

// Run Device及びBuild to Deviceは未調査

// Development Build
buildPlayerOptions.options |= BuildOptions.Development;

// Autoconnect Profiler
buildPlayerOptions.options |= BuildOptions.ConnectWithProfiler;

// Deep Profiling
buildPlayerOptions.options |= BuildOptions.EnableDeepProfilingSupport;

// Script Debugging
buildPlayerOptions.options |= BuildOptions.AllowDebugging;

// IL2CPP Code Generation = Faster runtime
EditorUserBuildSettings.il2CppCodeGeneration = Il2CppCodeGeneration.OptimizeSpeed;

// IL2CPP Code Generation = Faster (smaller) builds
EditorUserBuildSettings.il2CppCodeGeneration = Il2CppCodeGeneration.OptimizeSize;

// Compression Method = LZ4
buildPlayerOptions.options |= BuildOptions.CompressWithLz4;

// Compression Method = LZ4HC
buildPlayerOptions.options |= BuildOptions.CompressWithLz4HC;

// buildAppBundle=trueにした場合は拡張子に.aabを指定する
buildPlayerOptions.locationPathName = "Builds/Build.apk";
var report = BuildPipeline.BuildPlayer(buildPlayerOptions);

Debug.Log(report.summary.result);

iOS

var buildPlayerOptions = new BuildPlayerOptions();

// Platform
buildPlayerOptions.targetGroup = BuildTargetGroup.iOS;
buildPlayerOptions.target = BuildTarget.iOS;

// Run in Xcodeは未調査

// Run in Xcode as
EditorUserBuildSettings.iOSXcodeBuildConfig = XcodeBuildConfig.Release;

// Symlink Sources
EditorUserBuildSettings.symlinkSources = false;

// Development Build
buildPlayerOptions.options |= BuildOptions.Development;

// Autoconnect Profiler
buildPlayerOptions.options |= BuildOptions.ConnectWithProfiler;

// Deep Profiling
buildPlayerOptions.options |= BuildOptions.EnableDeepProfilingSupport;

// Script Debugging
buildPlayerOptions.options |= BuildOptions.AllowDebugging;

// IL2CPP Code Generation = Faster runtime
EditorUserBuildSettings.il2CppCodeGeneration = Il2CppCodeGeneration.OptimizeSpeed;

// IL2CPP Code Generation = Faster (smaller) builds
EditorUserBuildSettings.il2CppCodeGeneration = Il2CppCodeGeneration.OptimizeSize;

// Compression Method = LZ4
buildPlayerOptions.options |= BuildOptions.CompressWithLz4;

// Compression Method = LZ4HC
buildPlayerOptions.options |= BuildOptions.CompressWithLz4HC;

buildPlayerOptions.locationPathName = "Builds/Build.xcodeproj";
var report = BuildPipeline.BuildPlayer(buildPlayerOptions);

Debug.Log(report.summary.result);

WebGL

var buildPlayerOptions = new BuildPlayerOptions();

// Platform
buildPlayerOptions.targetGroup = BuildTargetGroup.WebGL;
buildPlayerOptions.target = BuildTarget.WebGL;

// Texture Compression = Use default format(DXT)
EditorUserBuildSettings.webGLBuildSubtarget = WebGLTextureSubtarget.Generic;

// Development Build
buildPlayerOptions.options |= BuildOptions.Development;

#if UNITY_WEBGL

// Code Optimization
UnityEditor.WebGL.UserBuildSettings.codeOptimization = UnityEditor.WebGL.CodeOptimization.Speed;

#endif

// Autoconnect Profiler
buildPlayerOptions.options |= BuildOptions.ConnectWithProfiler;

// Deep Profiling
buildPlayerOptions.options |= BuildOptions.EnableDeepProfilingSupport;

// IL2CPP Code Generation = Faster runtime
EditorUserBuildSettings.il2CppCodeGeneration = Il2CppCodeGeneration.OptimizeSpeed;

// IL2CPP Code Generation = Faster (smaller) builds
EditorUserBuildSettings.il2CppCodeGeneration = Il2CppCodeGeneration.OptimizeSize;

buildPlayerOptions.locationPathName = "Builds/Build";
var report = BuildPipeline.BuildPlayer(buildPlayerOptions);

Debug.Log(report.summary.result);

以上

以上の調査結果については、一応一通り叩いてはみていますが、社内のプロジェクトでは深く触っていない項目もある為、間違っている情報もあるかもしれません。何か気付いたところがあればタレコミをお願いします。