Override app delegate in Unity for iOS and OSX (1/4)
Plugin workflow

When it comes to create native plugins for Unity, often the plugins need customize behaviour how the application starts / launches by override app delegate (see UIApplicationDelegate for iOS and NSApplicationDelegate for OSX). Opening app via Push Notifications, URL Schemes, Documents, User activities, or even via WatchKit events are all great examples of this.

TL;DR

You may get the example project immediately by heading to GitHub (in that case you should really be aware of the folder structure at the end of the article, as there are numerous sub-projects can be found all around). However, I strongly recommend to take the next 15 minutes to understand what is going on, and read along.

See Unity.Blog.Override_App_Delegate at

Override app delegate in iOS Unity player (Poor man’s method)

Like many things in the Unity ecosystem, this feature is also heavily underdocumented. However, if you take a closer look to a Unity iOS player Xcode project, you can find that Unity provided some tools that can help.

There is an external constant called AppControllerClassName can be found in every main.mm of every iOS Unity player Xcode project. This class name will be passed as the app delegate class to UIApplicationMain. That means that UIApplication (or any principal class given in Info.plist) will create an instance of that delegate (that should conform to UIApplicationDelegate), and call the given template methods throughout the application lifecycle.

IMPL_APP_CONTROLLER_SUBCLASS

There you can find the only piece of documentation about this thing in that single comment line.

Unity also provided a macro called IMPL_APP_CONTROLLER_SUBCLASS(className) that creates a tiny little category, which overrides the AppControllerClassName constant as soon as it gets loaded (along all the other classes).

In short, if you put this file OverrideAppDelegate.m into your Plugins folder, you can essentially extend / override app delegate this way.

#import "UnityAppController.h"


@interface OverrideAppDelegate : UnityAppController
@end


IMPL_APP_CONTROLLER_SUBCLASS(OverrideAppDelegate)


@implementation OverrideAppDelegate


-(BOOL)application:(UIApplication*) application didFinishLaunchingWithOptions:(NSDictionary*) options
{
    NSLog(@"[OverrideAppDelegate application:%@ didFinishLaunchingWithOptions:%@]", application, options);
    return [super application:application didFinishLaunchingWithOptions:options];
}


@end
See OverrideAppDelegate.m at

This can be a quick solution when your project has a single iOS plugin intended to override app delegate. But if you are about to use more iOS plugins that uses the same technique, one or the other will be broken. (Unfortunately) you can find countless Unity plugins on GitHub using the very same technique.

You may create an override chain of plugins, but if you are conflicting with a closed source iOS plugin binary that uses this technique, then you basically can’t (unless you crack it).

Unity Plugin workflow considerations when override app delegate

To have a maintainable plugin, the first consideration is being totally encapsulated. It should not make a single assumption about the application, also it should not change a single thing in the application architecture itself. In the example above, you make two assumptions, both can be wrong. You assume that the base class of the app is UnityAppController, then you are assume that the value of AppControllerClassName is not gonna be changed after you have changed so.

So in general, if you make such assumptions, the application may break the plugin (often the case when using multiple plugins), or the plugin may break the app (often the case when the app development progresses, but the plugin does not follow).

I found that the most common consideration people pass over during plugin development is being compatible with other plugins (!). You may define a new base class for the main Unity controller, but if you are using another plugin that essentially does the same, you will break its intended behaviour.

Almost the same considerations lead to the Unity Android Plugin Architecture in the article Unity Android plugin tutorial (2/3) Project setup and workflow, that extends behaviour without overriding application’s main Activity. Two or more plugins wanting to do the same could also create such conflicting situations.

Ultimately this mindset leads to a healthier Unity plugin ecosystem in the long run.

Unity Plugin architectures for iOS and OSX

On iOS, Unity plugins can be packed / compiled along with the rest of the application code. They can be added in form of native classes, static or dynamic libraries (Libraries or Frameworks using iOS terms). That means native plugin classes gets loaded alongside the application classes. As application launch happens after the classes gets loaded, iOS plugins can extend application launching behaviours more easily.

On OSX, however, Unity asks for plugins in form of bundles (following the general OSX plugin pattern). That means that plugin code will be loaded by the Objective-C application runtime (probably using an :[NSBunde load]: call). As a consequence, the plugin code gets loaded after the application has finished launching, seemingly even after Unity Player has launched, around the loading of the first scene. Obviously, using solely this architecture, you cannot customize app launching behaviour with OSX plugins.

A simple yet maintainable Unity iOS plugin workflow

Now comes the step-by-step tutorial part. First we create a simple Unity iOS plugin. While you can add Objective-C sources directly to Unity, I find it more maintainable to pack plugins as libraries (or even frameworks).

In general, I found it really convenient to have the native plugin projects (iOS, OSX, Android) in the Unity project root folder (outside Assets folder), then setup a copy command in Xcode that puts the resulting plugins into Assets folder (I actually did something very similar at Unity Android plugin tutorial (2/3) Project setup and workflow). Having this, version control also comes really easy (you can even maintain sub-projects as Git Submodules).

So for this plugin, you should make a folder called iOS beside the Assets folder. As your native platform count grows, this folder structure can really grow with them.

Create Cocoa Touch Static LibraryCreate Override iOS Static Library

Now in Xcode create a new Cocoa Touch Static Library called Override_iOS. It automatically creates a single class called Override_iOS. To see the plugin working, we simply log a message to the console when it is loaded. Fortunately Objective-C classes have a class method template called load you can use for this.

#import "Override_iOS.h"


@implementation Override_iOS


+(void)load
{ NSLog(@"[Override_iOS load]"); }


@end
See Override_iOS.m at

New Copy Files Build Phase

You can build the library ⌘+B, the resulting file libOverride_iOS.a can be found in the Products group. Next we make Xcode to deploy the library file automatically. First make sure you have a folder called Plugins in Unity. After that, select the Override_iOS target in Xcode, and add a New Copy Files Phase in the targets Build Phases.

Copy Files Build Phase Absolute Path

Drag the libOverride_iOS.a to the file list, then simply define the Assets/Plugins folder as an Absolute Path (you can see where my project resides above, you should locate yours). After hit build ⌘+B in Xcode, the library should be copied right into your Unity project.

iOS Static Library Unity Import SettingiOS Unity PlayerSettings

If you click on the libOverride_iOS.a file in Unity project window, you can see the Unity plugin inspector. Select iOS as the plugin platform, and click apply. Similar to the structure I used with plugin projects, I prefer somewhat similar folder structure for Unity builds as well. So make a folder called Build beside Assets, then create an iOS folder in it. To be able to run the app in the simulator, set Target SDK to Simulator SDK in iOS PlayerSettings.

Unity iOS Player Plugin Static LibraryUnity iOS Player Build Phases Link Binary With Libraries

There you go, build an iOS player, then open it in Xcode. You can see that the library has been deployed to the Libraries/Plugins group, also if you take a look on the Build Phases tab, it is linked in the Link Binary With Libraries along with the rest of the libraries.

Load iOS Unity plugin before application launches

Now if you run ⌘+R the resulting iOS app in the simulator, you should see the message coming from the plugin in the console indicating that the framework has been loaded. But you don’t.

Unity iOS Build TargetUnity iOS Build Other Linker Flags ObjC

You don’t see it, as by default iOS won’t link the library until you need it. You can change this behaviour by tell the linker to force load static library symbols. Select the Unity-iPhone build target in Xcode, then in the Build Settings tab, add this entry to the Other Linker Flags -ObjC.

Unity iOS Build Other Linker Flags ObjC

After this, run ⌘+R the resulting iOS app in the simulator, and take a look at the console. You can see [Override_iOS load] right at the top, that means the plugin code has been loaded before (!) any other thing happened in the application. This is very promising considering that we want to override app launching behaviour later on.

To manage the workflow accordingly, the build settings alteration should be included right into the Unity project. There is an API called PBXProject to manipulate the built Xcode project. So create a file in Unity called BuildPostProcessor.cs in Assets/Editor, and put this content from the Gist below (you can remove the frameworks part leaving the linker flag only). This method also proven quiet useful when hijacking OSX executables later.

Implement basic features in Unity iOS plugin

Ready to add some basic features to the plugin, actually a simple hello world that comes to Unity from the plugin side. So create some files in the plugin Xcode project. A helper tool called UnityString_C++.mm for string conversion between iOS and Unity, and a simple Objective-C++ file called Override_C++.mm with a single static external C function called getMessage.

#import "UnityString_C++.mm"
#import "Override_iOS.h"


extern "C"
{

    
    const char* getMessage()
    { return UnityStringFromNSString(@"Greetings from iOS!"); }
    
    
}
See Override_C++.mm at

After this you can now create the C# counterpart in Unity. Create a C# script file called Override.cs in Assets/Plugins folder, then hook up the message from the plugin with a text label. These parts are mostly taken after the official Building Plugins for iOS documentation.

using UnityEngine;
using UnityEngine.UI;
using System.Runtime.InteropServices;


public class Override : MonoBehaviour
{


	public Text label;


#if !UNITY_EDITOR && UNITY_IOS

	[DllImport("__Internal")]
	static extern string getMessage();

	void Awake()
	{ label.text = getMessage(); }

#endif


}
See Override.cs at
Unity iOS Plugin Workflow Folder StructureUnity iOS Plugin Hello World 400px

There you go, you have setup a really convenient plugin workflow that fits well to version control, changes, also come without any need for manual Xcode project post-processing (you can recap the resulting folder structure to the left). Ready to be filled up with all the heavy features in the upcoming parts of the series.

DISCLAIMER. THE INFORMATION ON THIS BLOG (INCLUDING BUT NOT LIMITED TO ARTICLES, IMAGES, CODE SNIPPETS, SOURCE CODES, EXAMPLE PROJECTS, ETC.) IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE INFORMATION ON THIS BLOG (INCLUDING BUT NOT LIMITED TO ARTICLES, IMAGES, CODE SNIPPETS, SOURCE CODES, EXAMPLE PROJECTS, ETC.).

  • Tim R

    The load message does not print when running on device. But it works fine in the simulator. Does this method work on device for you still?

    • Hi, if you build for device, the library (libOverride_iOS.a) should be built for device as well. It is setup for Simulator by default, you should change it and rebuild (change the blue “iPhone 6s Plus” scheme at the top to some device you have connected).

      • Tim R

        Thanks, just saw this, yes that was the problem.

    • Tim R

      So I solved this problem. It was an architecture issue. After digging around if found that my lib was being built for x86_64 and i386 (just run lipo ‘libname’ -info from the console to see). I fixed this by setting the scheme to ‘generic iOS device’ now running ‘lipo libname -info’ returns arm7. Still had problems with iOS version after that so I set the BaseSDK to highest version, and OS Deployment version to lowest possible, and now the ‘Load’ method is getting called on startup.

    • So you just have to build the library for device as well. 💻📲
      Select Generic iOS Device build scheme, and rebuild library.

      https://uploads.disquscdn.com/images/12a11c95ac9f62df6d32d617b9b3a229a61ddd816db3c7587bd2dd63b347e1a0.gif

  • ADNAN NAZIR

    how to build when I don’t have UnityAppController.h
    I mean, I am trying to build myplugin.a file from a clean new xcode project, that I can use in my game.

    • It is implied in the article actually. Just skip stuff related to early class loading.
      However, it doesn’t add up too much extra, so you can stay in step-by-step tutorial mode, then remove stuff later (if ever remove at all).

      • ADNAN NAZIR

        I can’t compile my .h and .m file into myplugin.a file in Xcode because I don’t have a UnityAppController.h