Initialization paths for native iOS plug-ins
Learn about the different initialization paths available for native iOS plug-ins.
Read time 4 minutesLast updated 12 days ago
Learn about the different initialization paths available for native iOS plug-ins.
Unity and Apple platforms provide multiple mechanisms for initializing a native plug-in. The best approach depends on whether you need to initialize the plug-in early (at application startup) or lazily (on its first use). You can perform initialization from managed C# code, native code, or within Unity's generated Xcode project code.
Managed C# initialization paths
- RuntimeInitializeOnLoadMethodAttribute: Automatically runs a method at different points in the application lifecycle, such as or
BeforeSplashScreen. UseAfterSceneLoadto initialize your plug-in’s C# API and make the first call into native code. For more information, refer to RuntimeInitializeOnLoadMethodAttribute.RuntimeInitializeOnLoadMethodAttribute - SceneManager Callbacks: Use and
SceneManager.sceneLoadedfor lazy initialization tied to specific scene content.SceneManager.sceneUnloaded - MonoBehaviour Lifecycle: Use standard methods like
MonoBehaviour,Awake, andOnEnablefor initialization tied to aStart's lifecycle. Refer to Event function execution order for more information.GameObject
Native initialization paths
The native initialization paths and their timing differ depending on your plug-in's language. Swift follows a different path than C++ or Objective-C. The following sections outline the various initialization paths available for native code.
C++ and Objective-C++ initialization paths
You can use a global C++ object's constructor to run code before and its destructor to run code after completes. A global C++ object constructor is invoked automatically when the application binary loads and its destructor is invoked when the binary unloads.
main()main()Characteristics:
- Timing: Before .
main() - Execution order: Non-deterministic.
- Unity state: Unity isn't initialized.
- Execution: Triggered automatically on binary load and unload.
- Compatibility: Works with ,
.c,.cpp,.m, and.mmfiles..a - Dependency: Behavior depends on linking (static versus dynamic).
UnityFramework.framework
Code example
// Global object — constructor runs before main(), destructor after main()struct GlobalFoo { GlobalFoo() { std::cout << "GlobalFoo constructor running!\n"; } ~GlobalFoo() { std::cout << "GlobalFoo destructor running!\n"; }};GlobalFoo g_foo;
Clang and GCC initialization paths
This method uses the and attributes to register functions that run when a library loads and unloads.
__attribute__((constructor))__attribute__((destructor))Characteristics:
- Timing: Runs before .
main() - Execution order: Non-deterministic.
- Unity state: Unity isn't initialized.
- Execution: Triggered automatically on binary load and unload.
- Compatibility: Works with ,
.c,.cpp, and.mfiles..mm - Dependency: Behavior depends on linking.
UnityFramework.framework
Example
// runs before main__attribute__((constructor))static void MyInit() { printf("Init called\n");}// after program exit/shared library unload__attribute__((destructor))static void MyDone() { printf("Done called\n");}
Objective-C
These methods are for use in and files.
.m.mm+load
The method is executed by the Objective-C runtime when a class loads, which occurs before and before C++ global constructors.
+loadmain()Characteristics:
- Timing: Early. Runs before .
main() - Execution order: Non-deterministic.
- Unity state: Unity isn't initialized.
- Execution: Runs automatically for every class and category that implements it, even if never referenced. Can't be disabled.
- Compatibility: Works with and
.mfiles..mm - Dependency: Behavior depends on linking.
UnityFramework.framework
Example
// Runs as soon as the Obj-C runtime loads the class (before main()).// Categories get +load before classes@implementation MyClass+ (void)load { NSLog(@"+load called");}@end
+initialize
The method is invoked lazily, just before the first message is sent to the class. It's ideal for on-demand initialization.
+initializeCharacteristics:
- Timing: Runs on the first message sent to the class.
- Execution order: Deterministic.
- Unity state: Unity might be initialized, depending on when the first message is sent.
- Execution: Lazy. Doesn't run if the class is never used, thread-safe, and runs exactly once per class.
- Compatibility: Works with and
.mfiles..mm
Example:
// Called on first message dispatch to the class@implementation MyClass+ (void)initialize { NSLog(@"+initialize called");}@end
Swift
In Swift, global variables and objects are lazily initialized. This means the constructor runs only when the object is accessed for the first time. The initial access occurs when calling .
NativeManagermanagerGetValueFromManagerCharacteristics:
- Timing: On first use.
- Execution order: Deterministic.
- Execution: Lazy.
Example:
class NativeManager {init() { rint("NativeManager initialized") }func value() -> Int { return 42 }}// global objectlet manager = NativeManager()@_cdecl("GetValueFromManager")public func GetValueFromManager() -> Int { return manager.value() }
Change App Controller Class
You can modify the Unity-provided class to customize your application's startup behavior. The macro achieves this by replacing Unity’s default class with your own custom Objective-C subclass.
AppControllerIMPL_APP_CONTROLLER_SUBCLASSAppControllerIMPL_APP_CONTROLLER_SUBCLASS- Declare an Objective-C category on your subclass.
- Use (executed before
+load) to override the globalmain()symbol that Unity uses to decide whichAppControllerClassNameorUIApplicationDelegateclass to instantiate.AppController
Use if you need early lifecycle hooks, such as:
IMPL_APP_CONTROLLER_SUBCLASSpreStartUnitystartUnityinitUnityWithSceneapplication:didFinishLaunchingWithOptionsapplicationDidEnterBackgroundapplicationWillTerminate- App-level system integrations that must run before Unity initializes.
Characteristics:
- Dependency: Only compatible with an Objective-C project type.
- Compatibility: Works with and
.mfiles..mm
Code example:
// MyAppController.mm#import "UnityAppController.h"// Custom AppController@interface MyAppController : UnityAppController@end@implementation MyAppController (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { NSLog(@"MyAppController didFinishLaunching"); return [super application:application didFinishLaunchingWithOptions:launchOptions]; } @end// Register this class as Unity's AppControllerIMPL_APP_CONTROLLER_SUBCLASS(MyAppController)