Unity は、サポートしているすべてのプラットフォームで共通のスクリプティング API と体験を提供します。ただし、独自の制限があるプラットフォームもあります。これらの制限を理解するために、以下の表では、各プラットフォームとスクリプティングバックエンドに適用される制限について説明します。
プラットフォーム (スクリプティングバックエンド) | 事前 (AOT) コンパイル | スレッドに対応 |
---|---|---|
Android (IL2CPP) | 可 | 可 |
Android (Mono) | なし | 可 |
iOS (IL2CPP) | 可 | 可 |
スタンドアロン (IL2CPP) | 可 | 可 |
スタンドアロン (Mono) | なし | 可 |
ユニバーサル Windows プラットフォーム (IL2CPP) | 可 | 可 |
WebGL (IL2CPP) | 可 | なし |
プラットフォームの中には、ランタイムのコード生成ができないものもあります。そのため、そのようなデバイスで実行時 (Just-In-Time、JIT) コンパイルをおこなうと失敗します。代わりに、すべてのコードを事前 (Ahead-Of-Time、AOT) にコンパイルする必要があります。しばしば、この差異はあまり重要でないこともあります。しかし、ある特定の場合では、AOT コンパイルを必要とするプラットフォームには、追加の配慮が必要なことがあります。
リフレクションは AOT プラットフォームでサポートされています。 しかし、コードがリフレクションによって使用されていることをこのコンパイラーが推測できない場合、ランタイムにコードが存在しない可能性があります。 詳細は マネージコードストリッピング を参照してください。
AOT プラットフォームは、System.Reflection.Emit
名前空間のメソッドを実装できません。
事前 (AOT) コンパイルが必要なプラットフォームでは、リフレクションの使用が原因でシリアライズと非シリアライズで問題が発生することがあります。シリアライズと非シリアライズの一部として、型とメソッドをリフレクション経由でのみ使用できる場合、事前コンパイラーは型とメソッドのためにコードが生成される必要があることを検知することができません。
ジェネリック型とメソッドの場合、異なるジェネリックインスタンスは異なるコードを必要とするため、コンパイラーはどのジェネリックインスタンスを使うかを判断しなければなりません。例えば、List<int>
に使われるコードは、List<double>
に使われるコードと異なります。しかし、IL2CPP は参照型のためのコードを共有します。つまり、List<object>
と List<string>
には同じコードが使われます。
以下のような場合、IL2CPP がコンパイル時に見つけられなかったジェネリック型やメソッドを参照することが可能です。
Activator.CreateInstance(typeof(SomeGenericType<>).MakeGenericType(someType));
typeof(SomeGenericType<>).MakeGenericType(someType)).GetMethod("AMethod").Invoke(null, null
);typeof(SomeType).GetMethod("GenericMethod").MakeGenericMethod(someType).Invoke(null, null
);Struct<Struct<Struct<...<Struct<int>>>>
このようなケースをサポートするために、IL2CPP はどんな型のパラメーターでも動作するジェネリックコードを生成します。ただし、このコードは、型のサイズや、参照型か値型かを仮定することができないため、高速ではありません。より速いジェネリックメソッドを確実に生成する必要がある場合は、以下のようにします。
* ジェネリック引数が常に参照型になる場合は、where: class
制約を加えます。 そうすると、IL2CPP は参照型の共有を使ってフォールバックメソッドを生成します。これによりパフォーマンスが低下することはありません。
* ジェネリック引数が常に値型である場合は、where: struct
制約を加えます。 これにより、いくつかの最適化が可能になりますが、値型のサイズが異なる可能性があるため、コードは依然として遅くなります。
* UsedOnlyForAOTCodeGeneration
という名前のメソッドを作成し、IL2CPP に生成させたいジェネリック型とメソッドへの参照を加えます。 このメソッドは呼び出される必要はありません (おそらく呼び出されるべきではありません)。 以下の例では、GenericType<MyStruct>
の特殊化が生成されることを確認します。
public void UsedOnlyForAOTCodeGeneration()
{
// Ensure that IL2CPP will create code for MyGenericStruct
// using MyStruct as an argument.
new GenericType<MyStruct>();
// Ensure that IL2CPP will create code for SomeType.GenericMethod
// using MyStruct as an argument.
new SomeType().GenericMethod<MyStruct>();
public void OnMessage<T>(T value)
{
Debug.LogFormat("Message value: {0}", value);
}
// Include an exception so we can be sure to know if this
// method is ever called.
throw new InvalidOperationException(
"This method is used for AOT code generation only. " +
"Do not call it at runtime.");
}
“速い (小さな) ビルド” 設定を有効にすると、ジェネリックコードの完全に共有可能な 1 つのバージョンだけがコンパイルされることに注意してください。 これは生成されるメソッドの数を減らし、コンパイル時間とビルドサイズを削減しますが、ランタイムのパフォーマンスを犠牲にします。
ネイティブコードから呼び出せるように C 言語の関数ポインターにマーシャリングを行う必要があるマネージメソッドには、AOT プラットフォーム上でいくつかの制限があります。
MonoPInvokeCallback
属性を持つ必要があります。[MonoPInvokeCallback(Type)]
オーバーロードを使用して、サポートする必要があるジェネリックの特殊化を指定する必要があるかもしれません。 その場合、型は正しい数のジェネリック引数を持つジェネリックインスタンスでなければなりません。以下のように、1 つのメソッドに複数の[MonoPInvokeCallback]
属性を指定することができます。// Generates reverse P/Invoke wrappers for NameOf<long> and NameOf<int>
// Note that the types are only used to indicate the generic arguments.
[MonoPInvokeCallback(typeof(Action<long>))]
[MonoPInvokeCallback(typeof(Action<int>))]
private static string NameOfT<T>(T item)
{
return typeof(T).Name;
}
プラットフォームによっては、スレッドの使用をサポートしていません。そのため、System.Threading
名前空間を使用するマネージコードはすべて、ランタイムに失敗します。また、.NET クラスライブラリの一部は、暗示的にスレッドに依存しています。よく使われる例としては、System.Timers.Timer
クラスがあり、スレッドのサポートに依存しています。
IL2CPP は例外フィルターをサポートしていますが、IL2CPP は C++ 例外を使用してマネージ例外を実装しているため、フィルターステートメントと catch ブロックの実行順序が異なります。 フィルターがフィールドへの書き込みをブロックしない限り、気づかないかもしれません。
IL2CPP は、MarhsalAs
と FieldOffset
属性をランタイムで反映することをサポートしていません。IL2CPP はコンパイル時にはこれらの属性をサポートしています。適切な プラットフォーム呼び出しによるマーシャリング を行うために、これらを使用する必要があります。
IL2CPPは、C# の dynamic
キーワードには対応していません。このキーワードには JIT コンパイルが必要ですが、IL2CPP では不可能です。
IL2CPPは、 Marshal.Prelink
または Marshal.PrelinkAll
APIメソッドをサポートしていません。
IL2CPP は、System.Diagnostics.Process
API メソッドをサポートしていません。デスクトッププラットフォームでこれが必要な場合は、Mono スクリプティングバックエンドを使用してください。