Unity でプラットフォームを切り替えてビルドする
Unity でプラットフォームを切り替えてビルドする
Unity は C# のコードでプラットフォームを切り替えたり、アプリをビルドしたりすることができます。この機能を利用することで、ビルドを自動化することができます。
とはいえ、すんなりいかないのが Unity...
プラットフォームを切り替えてビルドできない
プラットフォームを切り替えてビルドするコードは次のように書けばよさそうに思えます。
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Android, BuildTarget.Android);
BuildPipeline.BuildPlayer(/* ... */);
ところが、このコードは動いたり動かなかったりします。
Unity Editor はプラットフォームを切り替えた際にドメインをリロードします。結果、実行中のコードは停止されます。つまり、BuildPlayer() は呼び出されません。(ただし、元からプラットフォームが Android の場合、切り替えが発生しませんので BuildPlayer() は呼び出されます)
プラットフォームを切り替えたあとにコードを実行するには別の方法が必要です。例えば、プラットフォームの切り替え後に実行されるよう IActiveBuildTargetChanged インターフェイスを実装します。
public class Build : IActiveBuildTargetChanged
{
public int callbackOrder => 0;
public void OnActiveBuildTargetChanged(BuildTarget previousTarget, BuildTarget newTarget)
{
BuildPipline.BuildPlayer(/* ... */);
}
}
こうすることで、SwitchActiveBuildTarget() でプラットフォームを切り替えた後にビルドできるようになります。
とはいえ、この方法は問題だらけで...
- Unity Editor GUI で手動でプラットフォームを切り替えても、ビルドが走ってしまう
- 実際に切り替えが発生しない場合は、このイベントは呼び出されない
前者の対策のために、静的変数を利用して手動で切り替えたかどうかを判断する方法もありますが、ドメインのリロードでは静的変数もリセットされるため、Unity Editor の SessionState を使う必要があります。
後者の対策は、切り替えが発生しなさそうなときはイベント経由ではなく、最初の例のように直接 BuildPlayer() メソッドを呼び出しなければなりません。
さらには、自動化でよく利用する、Unity Editor CLI のバッチモードでは SwitchActiveBuildTarget() を利用してはいけません。-buildTarget 引数を利用する必要があります。
ビルドターゲットを切り替えてビルドを確実に行うには、これらを考慮せねばならず、面倒です。面倒なのはまだいいのですが、本質でないコードをたくさん書く羽目になり、コードが散在します。メンテナンスや改善が困難になります。
どうしたのか
自動化の際に役に立ちそうなライブラリを Unity Build Helper として公開していますが、プラットフォームを切り替えてビルドをするのを簡単にできるように機能を追加しました。(インストール方法などは README を参照してください)
プラットフォームを切り替えて、ビルドを行うには次のようにします。
using Ignis.Unity.Building.Platforms.Extensions;
public static class Build
{
[MenuItem("Build/Android")]
public static void Android()
{
BuildTarget.Android.Switch()
.WithCallback(context => context.InBatchScope(() => {
var report = BuildPipeline.BuildPlayer(/* ... */);
if (report.summary.result != BuildResult.Succeeded)
throw new InvalidOperationException();
});
}
Unity Editor GUI の Build -> Android から実行すると、プラットフォームを Android に切り替えてからビルドされます。コマンドラインからは Unity -batchmode -buildTarget Android -executeMethod Build.Android とするだけです。
このライブラリを利用すれば、細かいことを考えなくてもプラットフォームを切り替えた後にビルドするスクリプトを書くことができますし、両者の処理が近くに書けるため、何をやっているかの見通しも向上します。
是非使ってみて、フィードバックを頂けたらと思います。
どうやってるの? (おまけ)
ドメインがリロードされてもコールバック関数を保持するために、コールバック関数をバイナリシリアライズして Unity Editor の SessionState に保存しています。ドメインのリロード後にプラットフォームの切り替えイベントが発生しますが、コールバック関数をデシリアライズして実行しています。(もちろん、切り替えがなされなかった場合でもコールバック関数は呼び出しています)
ですので、シリアライズできないコールバック関数は実行できません。
Discussion