Unity provides a common scripting API and experience across all supported platforms. However, some platforms have inherent restrictions. The following table describes which restrictions apply to each platform and scripting backendA framework that powers scripting in Unity. Unity supports three different scripting backends depending on target platform: Mono, .NET and IL2CPP. Universal Windows Platform, however, supports only two: .NET and IL2CPP. More info
See in Glossary:
Platform (scripting backend) | Ahead-of-time compile | Supports threads |
---|---|---|
Android (IL2CPP) | Yes | Yes |
Android (Mono) | No | Yes |
iOS (IL2CPP) | Yes | Yes |
Standalone (IL2CPP) | Yes | Yes |
Standalone (Mono) | No | Yes |
Universal Windows Platform (IL2CPP) | Yes | Yes |
Web (IL2CPP) | Yes | No |
Some platforms don’t allow runtime code generation. Any managed code that depends on just-in-time (JIT) compilation on the target device will fail. Instead, you must compile all the managed code ahead-of-time (AOT). Often, this distinction doesn’t matter, but in a few specific cases, AOT platforms require additional consideration.
Unity supports reflection on AOT platforms. However, if the compiler can’t infer that the code is used via reflection, the code might not exist at runtime. For more information, refer to Managed Code Stripping.
An AOT platform can’t implement any of the methods in the System.Reflection.Emit
namespace.
AOT platforms might encounter issues with serialization and deserialization because of the use of reflection. If a type or method is only used via reflection as part of serialization or deserialization, the AOT compiler can’t detect that it needs to generate the code required for the type or method.
For generic types and methods, the compiler must determine which generic instances are used because different generic instances might require different code. For example, the code for List<int>
is different than the code for List<double>
. However, IL2CPP will share code for usages of reference types, so the same code will be used for List<object>
and List<string>
.
It’s possible to reference generic types and methods that IL2CPPA Unity-developed scripting back-end which you can use as an alternative to Mono when building projects for some platforms. More info
See in Glossary did not find at compile time in the following cases:
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>>>>
.To support those cases, IL2CPP generates generic code that works with any type parameter. However, this code is slower because it can’t determine a type’s size, or whether it’s a reference or value type. If you need to ensure that faster generic methods are generated, do the following:
where: class
constraint. IL2CPP then generates the fallback method using reference type sharing, which causes no performance degradation.where: struct
constraint. This enables some optimizations, but the code will still be slower because the value types can be different sizes.UsedOnlyForAOTCodeGeneration
and add references to the generic types and methods you want IL2CPP to generate. This method never needs to be called. The following example ensures that a specialization for GenericType<MyStruct>
is generated: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.");
}
Note: To compile only the single, fully-sharable version of generic code, set the IL2CPP Code Generation Player setting to Optimize for code size and build time. This reduces the number of methods generated, reducing compile time and build size, but comes at the expense of runtime performance.
Managed methods that need to be marshaled to a C function pointer so that they can be called from native code have a few restrictions on AOT platforms:
[MonoPInvokeCallback]
attribute.[MonoPInvokeCallback(Type)]
overload to specify the generic specializations that must be supported. If so, the type must be a generic instance with the correct number of generic arguments. It’s possible to have multiple [MonoPInvokeCallback]
attributes on a method as follows:// 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;
}
Some platforms don’t support the use of threads, so any managed code that uses the System.Threading
namespace fails at runtime. Some parts of the .NET class libraries also implicitly depend on threads. A common example is the System.Timers.Timer
class, which depends on support for threads.
IL2CPP supports exception filters. However, the execution order of filter statements and catch blocks is different because IL2CPP uses C++ exceptions to implement managed exceptions. This isn’t noticeable unless a filter block writes to a field.
IL2CPP does not support reflection of the MarshalAs
and FieldOffset
attributes at runtime. It does support these attributes at compile time. You should use these for proper platform invoke marshaling.
IL2CPP does not support the C# dynamic
keyword. This keyword requires JIT compilation, which is not possible with IL2CPP.
IL2CPP doesn’t support the Marshal.Prelink
or Marshal.PrelinkAll
API methods.
IL2CPP doesn’t support the System.Diagnostics.Process
API methods. For cases where this is required on desktop platforms, use the Mono scripting backend.