Managed code stripping is 何?
ビルドする時、Unityが不要なコードを削除してくれる機能です。ビルドのサイズは小さくなり、時間も短くなるっぽいのでそれなりに良いやつではあります。
リフレクションの罠
不要判定するには、実際のコードで使用されているかどうかを追ってくれているようなのですが、リフレクションを使って呼び出すようなケースは検知してくれません。リフレクションを使うZenjectのようなDIコンテナを使ってるとわちゃわちゃするわけです。デジゲー博寸前にこいつに気付いて半ベソかきました。
PlayerSettingsで無効化できんの?
Monoでビルドするときはできます。が、IL2CPPビルドではStripping Levelを調整することはできても無効化することはできません(2019.2.0f1 Personal)。後述の対応が必要です。
具体的にStrippingされるもの
ちょっと追い切れていないのですが、Lowレベルだと、Assetsフォルダ内にあるものはStrippingされないようです。一方、自作package等をインポートして、Packageフォルダ内にあるものをリフレクションでしか呼び出さないような場合はStippingされます。自分はこいつをZenjectで呼び出してやられました。
対応
以下のような感じのlink.xmlを書いて、Assetsフォルダ以下に置きます。これでビルドしてもStrippingされなくなります。
<linker><assemblyfullname="***"preserve="all"/></linker>
具体例
Packageフォルダ内にあるもの
PackageManagerでインポートしました。
同じフォルダ内には他にインポート用のpackage.jsonやSayHello.asmdefファイルがあります。
namespaceSayHello{publicinterfaceITarget{stringTarget();}}
namespaceSayHello{publicclassGreeter{privatereadonlyITarget_target;publicGreeter(ITargettarget){_target=target;}publicstringGet()=>$"ハロー, {_target.Target()}";}}
Assetsフォルダ以下
usingSayHello;publicclassMac:ITarget{publicstringTarget()=>"マック";}
usingSayHello;usingZenject;publicclassInstaller:MonoInstaller{publicoverridevoidInstallBindings(){Container.Bind<ITarget>().To<Mac>().AsSingle();Container.Bind<Greeter>().AsSingle();}}
次のGreeting.csは適当なuGUIのTextにアタッチします。
usingSayHello;usingUnityEngine;usingUnityEngine.UI;usingZenject;publicclassGreeting:MonoBehaviour{[Inject]privateGreeter_greeter;voidStart(){GetComponent<Text>().text=_greeter.Get();}}
link.xmlがない状態での動作
Editor上でTextに入れていた文字がそのまま表示されてしまいました。左下に
MissingMethodException: Constructor on type 'SayHello.Greeter' not found.
NullReferenceException: Object reference not set to an instance of an object.
とか出てますね。下ネタなんかを入れていたら、元祖西遊記スーパーモンキー大冒険の再来です。
link.xmlを書く
次のlink.xmlを書いてAssetsフォルダに置きます。
<linker><assemblyfullname="SayHello"preserve="all"/></linker>
無事に動いてくれました。