Learn about the different initialization paths available for native iOS plug-insA set of code created outside of Unity that creates functionality in Unity. There are two kinds of plug-ins you can use in Unity: Managed plug-ins (managed .NET assemblies created with tools like Visual Studio) and Native plug-ins (platform-specific native code libraries). More info
See in Glossary.
Unity and Apple platforms provide multiple mechanisms for initializing a native plug-inA platform-specific native code library that is created outside of Unity for use in Unity. Allows you can access features like OS calls and third-party code libraries that would otherwise not be available to Unity. More info
See in Glossary. 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.
BeforeSplashScreen or AfterSceneLoad. Use RuntimeInitializeOnLoadMethodAttribute to initialize your plug-in’s C# API and make the first call into native code. For more information, refer to RuntimeInitializeOnLoadMethodAttribute.SceneManager.sceneLoaded and SceneManager.sceneUnloaded for lazy initialization tied to specific sceneA Scene contains the environments and menus of your game. Think of each unique Scene file as a unique level. In each Scene, you place your environments, obstacles, and decorations, essentially designing and building your game in pieces. More infoMonoBehaviour methods like Awake, OnEnable, and Start for initialization tied to a GameObject’s lifecycle. Refer to Event function execution order for more information.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.
You can use a global C++ object’s constructor to run code before main() and its destructor to run code after main() completes. A global C++ object constructor is invoked automatically when the application binary loads and its destructor is invoked when the binary unloads.
main()..c, .cpp, .m, .mm, and .a files.UnityFramework.framework linking (static versus dynamic).// 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;
This method uses the __attribute__((constructor)) and __attribute__((destructor)) attributes to register functions that run when a library loads and unloads.
main()..c, .cpp, .m, and .mm files.UnityFramework.framework linking.// 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");
}
These methods are for use in .m and .mm files.
The +load method is executed by the Objective-C runtime when a class loads, which occurs before main() and before C++ global constructors.
main()..m and .mm files.UnityFramework.framework linking.// 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
The +initialize method is invoked lazily, just before the first message is sent to the class. It’s ideal for on-demand initialization.
.m and .mm files.// Called on first message dispatch to the class
@implementation MyClass
+ (void)initialize {
NSLog(@"+initialize called");
}
@end
In Swift, global variables and objects are lazily initialized. This means the NativeManager constructor runs only when the manager object is accessed for the first time. The initial access occurs when calling GetValueFromManager.
class NativeManager {
init() { rint("NativeManager initialized") }
func value() -> Int { return 42 }
}
// global object
let manager = NativeManager()
@_cdecl("GetValueFromManager")
public func GetValueFromManager() -> Int { return manager.value() }
You can modify the Unity-provided AppController class to customize your application’s startup behavior. The IMPL_APP_CONTROLLER_SUBCLASS macro achieves this by replacing Unity’s default AppController class with your own custom Objective-C subclass.
IMPL_APP_CONTROLLER_SUBCLASS works as follows:
+load (executed before main()) to override the global AppControllerClassName symbol that Unity uses to decide which UIApplicationDelegate or AppController class to instantiate.Use IMPL_APP_CONTROLLER_SUBCLASS if you need early lifecycle hooks, such as:
preStartUnitystartUnityinitUnityWithSceneapplication:didFinishLaunchingWithOptionsapplicationDidEnterBackgroundapplicationWillTerminate.m and .mm files.// 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 AppController
IMPL_APP_CONTROLLER_SUBCLASS(MyAppController)