Skip to content

Unity IL2CPP (iOS and AOT)

Rikimaru edited this page Sep 4, 2019 · 6 revisions

What?

Ceras generates code at runtime for maximum performance, but on some platforms that' not possible:

  • Unity IL2CPP
  • iOS
  • Universal Windows Platform (UWP)

For example when compiling your project with the Unity IL2CPP compiler, you end up with a native C++ binary (so no new code can be generated). And as for iOS, the AppStore simply doesn't allow runtime code-generation.

This quick guide explains how to use Ceras' "AotMode" so those limitations are not a problem! 😄

How?

1.) Activate AotMode

var config = new SerializerConfig();
config.AotMode = AotMode.Enabled;

2.) Generate Formatters

After following the steps in the basic Unity guide you'll have an editor script that automatically does everything.

Just place [GenerateFormatter] on your classes/structs. (Can be found here)

You can put the attribute on base-types as well. So if you have a abstract class NetworkPacket { } you can just put the attribute on it and any type that inherits from it will get included. (As long as the type is part of the assembly/assemblies you have provided)

  • Create a static method that returns a SerializerConfig and put the [AotSerializerConfig] attribute on it. It doesn't matter where the method is or if it is private or not.
    • It will collect all the types contained in config.KnownTypes
    • Any types that have been configured using config.ConfigType<MyClass>()... will be included as well.

You can also just mix both ways as well, the generator will search for both attributes anyway.

Warning: Keep this little pitfall in mind

The generator checks what formatter would get used for the types it collected, and removes all types that won't be handled by DynamicFormatter<> anyway.

So if you run the generator a second time, and you're using AotSerializerConfig, and you're adding the already generated formatters as well, then your AotGenerator will filter them of course (because it looks like that those types already have a dedicated formatter, and won't have to rely on DynamicFormatter<>!).

That means if you're using AotSerializerConfig you should not add the generated formatters to the config before returning it!

Also, this is the time to consider making your field/property types sealed. Both Unity's IL2CPP and Ceras can do some performance optimizations on variables that have a type that is known to be sealed. Note that this is about variable types, so for example having a field defined as ISomeInterface or object will prevent the optimization. The more variables are known to be sealed the better.

3.) Use the formatters

Somewhere in your code just call the code of the generated file:

GeneratedFormatters.UseFormatters(config);

4.) "Byte-Code-Stripping"

The Unity IL2CPP Compiler will try to reduce the assembly size by removing unused code - or at least what it thinks is unused code. Since Ceras refers to many things indirectly (even many of its internals), we need to make sure the byte-code-stripper will not remove any important code.

The included link.xml file should already be in your project (it got copied along with UnityAddon in the basic Unity guide)

Check out the Unity Docs for more info about link.xml.

5.) Done

If there's anything missing or not working, open an issue or join the discord server and send me a message.

Future todo:

  • Add some sort of marker attribute to the generated formatters, so if the generator gets called twice, it will not skip over any types (thinking "that type isn't handled by DynamicFormater, guess we don't need to generate a Formatter for it!")