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 スクリプティングバックエンドを使用してください。
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.