#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>
<assembly fullname="***" preserve="all"/>
</linker>
#具体例
###Packageフォルダ内にあるもの
PackageManagerでインポートしました。
同じフォルダ内には他にインポート用のpackage.jsonやSayHello.asmdefファイルがあります。
namespace SayHello
{
public interface ITarget
{
string Target();
}
}
namespace SayHello
{
public class Greeter
{
private readonly ITarget _target;
public Greeter(ITarget target)
{
_target = target;
}
public string Get() => $"ハロー, {_target.Target()}";
}
}
###Assetsフォルダ以下
using SayHello;
public class Mac : ITarget
{
public string Target() => "マック";
}
using SayHello;
using Zenject;
public class Installer : MonoInstaller
{
public override void InstallBindings()
{
Container.Bind<ITarget>().To<Mac>().AsSingle();
Container.Bind<Greeter>().AsSingle();
}
}
次のGreeting.csは適当なuGUIのTextにアタッチします。
using SayHello;
using UnityEngine;
using UnityEngine.UI;
using Zenject;
public class Greeting : MonoBehaviour
{
[Inject] private Greeter _greeter;
void Start()
{
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>
<assembly fullname="SayHello" preserve="all"/>
</linker>
無事に動いてくれました。