LoginSignup
10
6

More than 3 years have passed since last update.

UnityのManaged code strippingをどうにかする

Posted at

Managed code stripping is 何?

 ビルドする時、Unityが不要なコードを削除してくれる機能です。ビルドのサイズは小さくなり、時間も短くなるっぽいのでそれなりに良いやつではあります。

リフレクションの罠

 不要判定するには、実際のコードで使用されているかどうかを追ってくれているようなのですが、リフレクションを使って呼び出すようなケースは検知してくれません。リフレクションを使うZenjectのようなDIコンテナを使ってるとわちゃわちゃするわけです。デジゲー博寸前にこいつに気付いて半ベソかきました。

PlayerSettingsで無効化できんの?

 Monoでビルドするときはできます。が、IL2CPPビルドではStripping Levelを調整することはできても無効化することはできません(2019.2.0f1 Personal)。後述の対応が必要です。
スクリーンショット 2019-11-18 16.22.44.png

具体的にStrippingされるもの

 ちょっと追い切れていないのですが、Lowレベルだと、Assetsフォルダ内にあるものはStrippingされないようです。一方、自作package等をインポートして、Packageフォルダ内にあるものをリフレクションでしか呼び出さないような場合はStippingされます。自分はこいつをZenjectで呼び出してやられました。

対応

 以下のような感じのlink.xmlを書いて、Assetsフォルダ以下に置きます。これでビルドしてもStrippingされなくなります。

<linker>
       <assembly fullname="***" preserve="all"/>
</linker>

具体例

Packageフォルダ内にあるもの

 PackageManagerでインポートしました。
 同じフォルダ内には他にインポート用のpackage.jsonやSayHello.asmdefファイルがあります。

ITarget.cs
namespace SayHello
{
    public interface ITarget
    {
        string Target();
    }
}
Greeter.cs
namespace SayHello
{
    public class Greeter
    {
        private readonly ITarget _target;
        public Greeter(ITarget target)
        {
            _target = target;
        }
        public string Get() => $"ハロー, {_target.Target()}";
    }
}

Assetsフォルダ以下

Mac.cs
using SayHello;

public class Mac : ITarget
{
    public string Target() => "マック";
}
Installer.cs
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にアタッチします。

Greeting.cs
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がない状態での動作

スクリーンショット 2019-11-18 15.53.30.png
 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フォルダに置きます。

link.xml
<linker>
       <assembly fullname="SayHello" preserve="all"/>
</linker>

スクリーンショット 2019-11-18 16.10.49.png

無事に動いてくれました。

参考

Unity Manual : Managed bytecode stripping with IL2CPP

10
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
6