
About connecting a proprietary Objective-C plugin to the Unity 3D game engine
- From the sandbox
- Tutorial

Good day to all.
Let's start with what Unity 3d is. In short, this is a three-dimensional game engine. A free version is available on the official website, a pro version and a version with the ability to upload applications to mobile platforms are already worth the money.
This engine has rich capabilities, but it doesn’t know everything and some things still have to be done natively. For example, you had the task of displaying a web page (for example, your personal page when clicking on the link from the main menu of the game). The WWW class is designed to work with the network in unity, but it has the ability to only exchange data with web pages, it cannot cope with the render task. You go through all the options, and decide that it is better to display the web page using the native iOS WebView (I’ll say right away that the article is not about how to write Web View in Objective-C, but rather how to make friends with Unity). First you need to open xCode (or AppCode) and create an empty application (here it should be noted that the project created by Unity does not support ARC, so you will have to clear the memory with your handles). We will need two Objective-C classes. We will call them WebController and WebViewCaller. Accordingly, four files WebController.h, WebController.m, WebViewCaller.h and WebViewCaller.m will be created. Files with the extension .h are header files, all class methods should be described there, .m files are their direct implementation. To begin with, we decide what we want from our web view. We want the class to take two NSString parameters, the first is the page we should go to if there is a connection to the network, and the second is the path in the file system to the html page that we want to load by default if there is no Internet connection. For WebController, I will provide only an .h file, we will dwell on WebViewCaller in more detail. Accordingly, four files WebController.h, WebController.m, WebViewCaller.h and WebViewCaller.m will be created. Files with the extension .h are header files, all class methods should be described there, .m files are their direct implementation. To begin with, we decide what we want from our web view. We want the class to take two NSString parameters, the first is the page we should go to if there is a connection to the network, and the second is the path in the file system to the html page that we want to load by default if there is no Internet connection. For WebController, I will provide only an .h file, we will dwell on WebViewCaller in more detail. Accordingly, four files WebController.h, WebController.m, WebViewCaller.h and WebViewCaller.m will be created. Files with the extension .h are header files, all class methods should be described there, .m files are their direct implementation. To begin with, we decide what we want from our web view. We want the class to take two NSString parameters, the first is the page we should go to if there is a connection to the network, and the second is the path in the file system to the html page that we want to load by default if there is no Internet connection. For WebController, I will provide only an .h file, we will dwell on WebViewCaller in more detail. To begin with, we decide what we want from our web view. We want the class to take two NSString parameters, the first is the page we should go to if there is a connection to the network, and the second is the path in the file system to the html page that we want to load by default if there is no Internet connection. For WebController, I will provide only an .h file, we will dwell on WebViewCaller in more detail. To begin with, we decide what we want from our web view. We want the class to take two NSString parameters, the first is the page we should go to if there is a connection to the network, and the second is the path in the file system to the html page that we want to load by default if there is no Internet connection. For WebController, I will provide only an .h file, we will dwell on WebViewCaller in more detail.
So, with the help of Habr, Google and stackoverflow, we wrote a class that creates a web view. The .h file looks something like this:
@interface WebController : UIViewController
- (id)initWithOnlineHtml:(NSString*) _onlineHtml withOfflineHtml:(NSString*) _offlineHtml;
@end
This is actually the signature of the public constructor with the name initWithOnlineHtml: withOfflineHtml: and two string parameters _onlineHtml and _offlineHtml, the purpose of which I think should be clear to everyone.
Next, we need to add this view to our application. We will do this in our WebVievCaller class. He should draw our webview, and draw a back button, which will bring us back to our game. To start, our class will look like this (.h file)
#import
#import "TEWebController.h"
@interface WebViewCaller : NSObject
-(IBAction)quitBack:(id)sender;
-(void) callViewWithOnlineHtml:(NSString*) _onlineHtml
withOfflineHtml:(NSString*) _offlineHtml;
@end
quitBack is a function that will be called by pressing a button, callViewWithOnlineHtml: withOfflineHtml: will actually add our WebView to the current window and draw a button. So our class looks like this:
@implementation WebViewCaller
UIWindow* window;
-(IBAction)quitBack:(id)sender
{
NSLog(@"%d",clicked.tag);
}
-(void) callViewWithOnlineHtml:(NSString*) _onlineHtml
withOfflineHtml:(NSString*) _offlineHtml
{
TEWebController* webController = [[TEWebController alloc] initWithOnlineHtml:_onlineHtml withOfflineHtml:_offlineHtml];
window = [[UIApplication sharedApplication] keyWindow]; //1
[window setRootViewController:webController]; //2
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; //3
[button addTarget:self
action:@selector(quitBack:)
forControlEvents:UIControlEventTouchUpInside];
[button setTitle:@"<<" forState:UIControlStateNormal];
button.frame = CGRectMake(0, 0, 160.0, 40.0);
[window addSubview:button]; //4
[webController release];
}
@end
Here you can stay a little more. We create our web view with the parameters that came from unity, line 1 we get the current window, line 2 we set our web view as a display controller, from line 3 to line 4 we create a button that so far simply displays its tag in the console and, finally line 4 we add our button to the screen.
Then begins what this article was intended for. We need to add all this joy to unity and make the button back.
First, we need to add our classes to the folder "/ pathToYourProject / Assets / Plugins / iOS /" (further attachments are not allowed). Why did we do this, you might ask. When building, Unity creates an xCode project, and xCode picks up the files in this folder and adds it to its project. In an xCode project, they are in the Libraries folder. To connect a plugin, functions must be declared in the “C” syntax. That is, we must declare our function in the form
void _CalliOSWebView(const char *onlineHtml, const char *offlineHtml);
(the string char in "C #" "corresponds to const char * in" C ", so we still need to cast our const char * variables to NSString and call callViewWithOnlineHtml: withOfflineHtml: with these parameters). For this, outside the class, we write the function in The "C" style converts the input parameters to NSString and calls callViewWithOnlineHtml: withOfflineHtml :.
If you try to connect the Objective-C method, you will get an error of the form:
Undefined symbols for architecture armv7: "__CalliOSWebView", referenced from: RegisterMonoModules() in RegisterMonoModules.o ld: symbol(s) not found for architecture armv7 clang: error: linker command failed with exit code 1 (use -v to see invocation)
We will make the necessary changes to our class. Now our .m file should look like this:
@implementation WebViewCaller
UIWindow* window;
-(IBAction)quitBack:(id)sender
{
NSLog(@"%d",clicked.tag);
}
-(void) callViewWithOnlineHtml:(NSString*) _onlineHtml
withOfflineHtml:(NSString*) _offlineHtml
{
TEWebController* webController = [[TEWebController alloc] initWithOnlineHtml:_onlineHtml withOfflineHtml:_offlineHtml];
window = [[UIApplication sharedApplication] keyWindow]; //1
[window setRootViewController:webController]; //2
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; //3
[button addTarget:self
action:@selector(quitBack:)
forControlEvents:UIControlEventTouchUpInside];
[button setTitle:@"<<" forState:UIControlStateNormal];
button.frame = CGRectMake(0, 0, 160.0, 40.0);
[window addSubview:button]; //4
[webController release];
}
@end
void _CalliOSWebView(const char *onlineHtml, const char *offlineHtml)
{
NSString *onlineHtmlString = [[NSString alloc] initWithUTF8String:onlineHtml];
NSString *offlineHtmlString = [[NSString alloc] initWithUTF8String:offlineHtml];
WebViewCaller *caller = [[WebViewCaller alloc] init];
[caller callViewWithOnlineHtml:onlineHtmlString withOfflineHtml:offlineHtmlString];
[onlineHtmlString release];
[offlineHtmlString release];
}
we also need to add a description of our function in the .h file
#import
#import "WebController.h"
@interface WebViewCaller : NSObject
-(IBAction)quitBack:(id)sender;
-(void) callViewWithOnlineHtml:(NSString*) _onlineHtml
withOfflineHtml:(NSString*) _offlineHtml;
@end
#ifdef __cplusplus
extern "C" {
#endif
void _CalliOSWebView(const char *onlineHtml, const char *offlineHtml);
#ifdef __cplusplus
}
#endif
Now we can use our plugin. For this, Unity uses [DllImport ("PluginName")], but since we work with iOS where plugins are statically included in the assembly, we will use [DllImport ("__Internal")].
The code in unity will look like this:
public static void CallForWebPage()
{
if (Application.platform == RuntimePlatform.IPhonePlayer)
{
_CalliOSWebView("http://habrahabr.ru", Application.dataPath + "/Raw/test.html");
}
}
I think everything should be clear here, except perhaps for the second argument in the call to _CalliOSWebView. It refers to a file saved in the file system of the iOS device. But how do we put him there? For this, StreamingAssets exists in unity (files placed in this folder will remain unchanged after the project is built). Create this folder and put our test.html there. Now, to display the web view, you will need to call CallForWebPage () from the unit, but there will be a question with the back button. It can be solved as follows. We save the view of the unit, we embed our web view, at the click of a button we restore the view of the unit. The only problem is that Unity is not aware of this, and the game, sounds continue. But this is easily solved if desired. The implementation of the button is presented below:
@implementation WebViewCaller
UIViewController *unityViewController;
UIWindow* window;
-(IBAction)quitBack:(id)sender
{
[window setRootViewController:unityViewController];
}
-(void) callViewWithOnlineHtml:(NSString*) _onlineHtml
withOfflineHtml:(NSString*) _offlineHtml
{
WebController* webController = [[TEWebController alloc] initWithOnlineHtml:_onlineHtml withOfflineHtml:_offlineHtml];
window = [[UIApplication sharedApplication] keyWindow];
unityViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
[window setRootViewController:webController];
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self
action:@selector(quitBack:)
forControlEvents:UIControlEventTouchUpInside];
[button setTitle:@"<<" forState:UIControlStateNormal];
button.frame = CGRectMake(0, 0, 160.0, 40.0);
[window addSubview:button];
[webController release];
}
@end
void _CalliOSWebView(const char *onlineHtml, const char *offlineHtml)
{
NSString *onlineHtmlString = [[NSString alloc] initWithUTF8String:onlineHtml];
NSString *offlineHtmlString = [[NSString alloc] initWithUTF8String:offlineHtml];
WebViewCaller *caller = [[WebViewCaller alloc] init];
[caller callViewWithOnlineHtml:onlineHtmlString withOfflineHtml:offlineHtmlString];
[onlineHtmlString release];
[offlineHtmlString release];
}
The only remaining question is how to debug it all. I decided it for myself as follows. We go to the folder where we collected the iOS project. Open it from xCode, edit, debug and do whatever we want (I remind you that our plugins are in the Libraries folder). Then copy the changes to our classes in the folder "/ pathToYourProject / Assets / Plugins / iOS /".
That's all. If the WebController class is spelled correctly, then everything will start and work. I did not do programming on Objective-C before, and some things may seem clumsy and crooked to professionals, for which I apologize, but I hope that I could convey the main idea of how to connect plug-ins, and I hope that I could save at least some hours of work. Thanks for attention.
To whom Unity is interested, I can advise the following resources:
unity3d.com - official site;
answers.unity3d.com - questions and answers. The most, in my opinion, a useful resource;
forum.unity3d.com - forum about unity;
docs.unity3d.com - official documentation.