IL2CPP and Managed Code Stripping¶
LoL Engine works on IL2CPP platforms (iOS, Android, consoles, Windows/macOS/Linux IL2CPP — WebGL is not supported, see the Platform Support table in README.md), but because the engine relies on reflection for service creation and discovery, managed code stripping needs to be understood by every project that builds with IL2CPP.
What the Engine Does via Reflection¶
| Mechanism | Reflection used |
|---|---|
| Engine service creation | ConfigurableServiceInitializer resolves constructors via reflection and invokes them |
IServiceRegistrar auto-discovery |
All loaded assemblies are scanned; registrars are created with Activator.CreateInstance |
ServiceRegistrationInfo custom services |
Interface and implementation types are resolved from string type names via Type.GetType |
At Managed Stripping Level Medium or High, the Unity linker removes types and
members it cannot prove are used. Reflection call paths are invisible to it, so without
protection the linker can strip service constructors or whole classes, and the engine
fails at runtime (services come back null, registrars never run).
What the Engine Already Protects (you do not need to do this)¶
The package ships link.xml at the package root (next to
package.json), which preserves all four runtime assemblies:
<linker>
<assembly fullname="LoLEngine-Core" preserve="all" />
<assembly fullname="LoLEngine-Runtime" preserve="all" />
<assembly fullname="LoLEngine-Helpers" preserve="all" />
<assembly fullname="LoLEngine-Utility" preserve="all" />
</linker>
Unity only honors link.xml files located in a package's root folder (or anywhere
under the project's Assets/). Files in package subfolders are silently ignored —
versions of this package before 1.0.0-rc.5 shipped the file at Runtime/link.xml, where
it had no effect; consuming projects on those versions must preserve the four
LoLEngine-* assemblies in their own Assets/link.xml. With the file at the package
root, engine-side types are safe at any stripping level.
What Your Project Must Do¶
The shipped link.xml only covers LoL Engine's assemblies. Game-side types that are
reached only through reflection need protection in your project:
1. IServiceRegistrar implementations¶
Registrars are discovered by assembly scanning and instantiated via reflection — nothing
references them statically. Add [Preserve]:
using UnityEngine.Scripting;
[Preserve]
public class GameServiceRegistrar : IServiceRegistrar
{
public int Priority => 0;
public void RegisterServices(IServiceLocator serviceLocator, ServiceConfiguration serviceConfig)
{
// ...
}
}
[Preserve] on the class keeps the class, its constructors, and its methods.
2. Custom services registered via ServiceRegistrationInfo (inspector-driven)¶
These are resolved from assembly-qualified string type names, which the linker cannot
see at all. Either add [Preserve] to both the interface and the implementation, or add
them to a link.xml in your project's Assets/ folder:
<linker>
<assembly fullname="MyGame">
<type fullname="MyGame.Services.IWalletService" preserve="all" />
<type fullname="MyGame.Services.WalletService" preserve="all" />
</assembly>
</linker>
3. Types you serialize with the save system¶
JsonDataSerializer can construct objects via Activator.CreateInstance<T>(). Your
PersistableData subclasses are normally referenced statically by your own code, but if
a data class is only ever created through deserialization, give it [Preserve] too.
Verifying Your Build¶
- Set Project Settings → Player → Managed Stripping Level to the level you ship with (test High if unsure — it is the strictest).
- Make an IL2CPP build for your target platform.
- Run it and confirm:
- The engine boots (no
ServiceNotFoundExceptionfor enabled services). - Your
IServiceRegistrarlog lines appear (External registrar executed: ...). - A save/load round-trip works if you use the save system.
If a service disappears only in IL2CPP builds (works in the Editor and Mono builds), stripping is almost always the cause — check the linker log in the build output for the type name, then apply one of the protections above.
When a service class survives stripping but its constructors do not, the engine logs an
explicit error at initialization: Service type '…' has no public constructors — likely
stripped by the managed linker. That message in the Player log is a direct signal to
add or fix a link.xml entry for the named assembly.
See Also¶
- Unity Manual — Managed code stripping
Samples~/Scripts/09_GameServiceRegistrarSample.cs— registrar sample with[Preserve]applied- ServiceLocator.md, ServiceDependencies.md