Bridging the Gap – Plugin for Unity and iOS

There is always a need finding out a way of communication from unity to xcode or xcode to unity due to the absence of a direct way. For the first time when I faced this problem, had to spend almost 3-4 days of my app’s development cycle on finding the right way to make this bridge. Through this blog post, I am going to share the method so as to help out any other developer like me.Creating a bridge over unity and iOS requires coding at both ends.So, let’s discuss Xcode side first.

app42 unity3d plugin Bridging the Gap   Plugin for Unity and iOS


get started Bridging the Gap   Plugin for Unity and iOS

According to Unity documentation, “Unity iOS supports automated plugin integration in a limited way. All files with extensions .a,.m,.mm,.c,.cpp located in the Assets/Plugins/iOS folder will be merged into the generated Xcode project automatically. However, merging is done by symlinking files from Assets/Plugins/iOS to the final destination, which might affect some workflows. The.h files are not included in the Xcode project tree, but they appear on the destination file system, thus allowing compilation of .m/.mm/.c/.cpp files”.

So, we will create UnityIOSBridge.m and will place this class to the path “Assets/Plugins/iOS”.Unity needs the plugins to be c named so it is a good practice to wrap up the methods which need to be called from unity, inside extern “C”. But there is no hard and fast rule, you can create .m class and write your c-named methods just outside the implementation part and you can call them from unity. The only constraint is that you can not call these methods if you are building your App on simulator as unity iOS plugins only work on device.

Let’s do some coding e.g. in UnityIOSBridge.m class just write a method that can receive a string and convert it to NSString, now UnityIOSBridge.m class should look like as follows:

#import "UnityIOSBridge.h"
void messageFromUnity(char *message)
{
NSString *messageFromUnity = [NSString stringWithUTF8String:message];
NSLog(@"%@",messageFromUnity);
}
@implementation UnityIOSBridge
@end

To call the above written method from Unity, we have to write a Unity script, so let’s create a file UnityIOSBridge.cs.

using UnityEngine;
using System.Collections;
using System;
//This is needed to import iOS functions
using System.Runtime.InteropServices;
public class UnityIOSBridge : MonoBehaviour
{
/*
* Provide function decalaration of the functions defined in iOS
* and need to be called here.
*/
[System.Runtime.InteropServices.DllImport("__Internal")]
extern static public void messageFromUnity(string message);
//Sends message to iOS
static void SendMessageToIOS()
{
messageFromUnity("Hello iOS!");
}
}

And it’s really as simple as it looks in the above code. Now to call a method written in Unity script from iOS code, we can call UnitySendMessage(“UnityObjectName”, “UnityObject’sMethodName”, “Your message”). In response, Unity will look for the UnityObject and then call that UnityObject’sMethod to provide the message you passed. Now the UnityIOSBridge.m class should look like:

#import "UnityIOSBridge.h"
void messageFromUnity(char *message)
{
NSString *messageFromUnity = [NSString stringWithUTF8String:message];
NSLog(@"%@",messageFromUnity);
}
@implementation UnityIOSBridge
-(void)sendMessageToUnity
{
UnitySendMessage(listenerObject, "messageFromIOS", "Hello Unity!");
}
@end

and the Unity script UnityIOSBridge.cs should look like:

using UnityEngine;
using System.Collections;
using System;
//This is needed to import iOS functions
using System.Runtime.InteropServices;
public class UnityIOSBridge : MonoBehaviour
{
/*
* Provide function decalaration of the functions defined in iOS
* and need to be called here.
*/
[System.Runtime.InteropServices.DllImport("__Internal")]

extern static public void messageFromUnity(string message);
//Sends message to iOS
static void SendMessageToIOS()
{
messageFromUnity("Hello iOS!");
}
//Provides messages sent from iOS
static void messageFromIOS(string message)
{
Debug.Log(message);
}
}

Well this was a very simple requirement but what if we want to do something more e.g. our plugin should be able to notify Unity about the UIApplication delegate calls.There is no need to be worried as we are going to implement that also but to do that we have to do some work around.Objective-C is a runtime oriented language, which means that when it’s possible it defers decisions about what will actually be executed from compile & link time to when it’s actually executing on the runtime.

This gives you a lot of flexibility in that, you can redirect messages to appropriate objects as you need to or you can even intentionally swap method implementations etc. This requires the use of a runtime which can introspect objects to see what they do & don’t respond to and dispatch methods appropriately. So, we will take a simple example of “application: didFinishLaunchingWithOptions:” delegate method UIApplicationDelagate. We will be creating a category class of UIApplication and will implement load method. In load method, we will exchange the setDelagete method implementation of UIApplication with the method setApp42Delegate method of our class as follows:

+(void)load
{
method_exchangeImplementations(class_getInstanceMethod(self, @selector(setDelegate:)), class_getInstanceMethod(self, @selector(setApp42Delegate:)));
}

-(void) setApp42Delegate:(id)delegate
{
static Class delegateClass = nil;
if(delegateClass == [delegate class])
{
return;
}
delegateClass = [delegate class];
exchangeMethodImplementations(delegateClass, @selector(application:didFinishLaunchingWithOptions:),@selector(application:app42didFinishLaunchingWithOptions:), (IMP)

app42RunTimeDidFinishLaunching, "v@:::");
[self setApp42Delegate:delegate];
}

static void exchangeMethodImplementations(Class class, SEL oldMethod, SEL newMethod, IMP impl, const char * signature)
{
Method method = nil;
//Check whether method exists in the class
method = class_getInstanceMethod(class, oldMethod);
if (method)
{
//if method exists add a new method
class_addMethod(class, newMethod, impl, signature);
//and then exchange with original method implementation
method_exchangeImplementations(class_getInstanceMethod(class, oldMethod), class_getInstanceMethod(class, newMethod));
}
else
{
//if method does not exist, simply add as orignal method
class_addMethod(class, oldMethod, impl, signature);
}
}

BOOL app42RunTimeDidFinishLaunching(id self, SEL _cmd, id application, id launchOptions)
{
BOOL result = YES;
if ([self respondsToSelector:@selector(application:app42didFinishLaunchingWithOptions:)])
{
result = (BOOL) [self application:application app42didFinishLaunchingWithOptions:launchOptions];
}
else
{
[self applicationDidFinishLaunching:application];
result = YES;
}
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
return result;
}

Let’s walk through the above code snippets, the method “setApp42Delegate” calls our “exchangeMethodImplementations” that adds the “app42RunTimeDidFinishLaunching” to UIApllication class and exchanges the implementations of “app42RunTimeDidFinishLaunching” with “application: didFinishLaunchingWithOptions:” if it exists.This way we can have the access of all the UIApplicationDelagate methods such as “applicationDidEnterBackground:”, “application:didRegisterForRemoteNotificationsWithDeviceToken:” etc, without making changes directly to the Unity generated Xcode project.You can download the source code of our Unity plugin for iOS push notifications from Git Repo.

If you have any questions or need any further assistance, please feel free to write us at support@shephertz.com

twitter Bridging the Gap   Plugin for Unity and iOSfacebook Bridging the Gap   Plugin for Unity and iOSgoogle Bridging the Gap   Plugin for Unity and iOSlinkedin Bridging the Gap   Plugin for Unity and iOSpinterest Bridging the Gap   Plugin for Unity and iOSreddit Bridging the Gap   Plugin for Unity and iOSstumbleupon Bridging the Gap   Plugin for Unity and iOStumblr Bridging the Gap   Plugin for Unity and iOS

Leave a Reply

Your email address will not be published. Required fields are marked *


nine + 3 =

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>