Unity AppController subclassing

So in 4.2 there is this release note:

iOS: Improved support for AppController subclassing and unity view integration with native UI.

I am someone who pretty much hacked the AppController like two years ago to get it integrated with Native Apps, and have just been running on my own method, which works, but is a little hackie.

So it seems like doing this now is a bit more supported?

Also it says ‘integration with Native UI’, does this mean the actual Unity view can be moved around and placed, as a smaller window in Native UI?

I would really like to see some official example code on all the best methods to do this.

well, it depends, but thats our goal sure. 4.2 was mainly about ui integration

yep

we are working on updating our “learn” site with samples of new 4.2 features

1 Like

In case anyone else is struggling with this, this is what we did to get our old custom AppController functions to work with 4.2 (which may change depending on the best practices in the forthcoming documentation) since we had trouble just merging AppController into UnityAppController (it was deploying to the Libraries directory instead of the classes directory where we expected it to go and overwrite the default one).

After building from unity, add a new subclass of UnityAppController in the Libraries directory of your XCode project. We called it CustomAppDelegate. In that class, add the functionality that you had before in AppController. It actually is quite nice to have this separate so you can see your custom functionality easier. Most of ours are just a couple extra lines and then call the methods on the super class. Once you have all that separated out into CustomAppDelegate.mm (you can leave CustomAppDelegate.h the way it is) then edit line 15 of main.mm to point to your subclass’s name (“CustomAppDelegate” in our case). It should be working at this point, but run it just to make sure. Once you know it is running, copy main.mm, CustomAppDelegate.h and CustomAppDelegate.mm into your Plugins/iOS/ directory in your unity project and rebuild. Should be working now.

Oh damn.

Can you have multiple smaller Unity windows in the Native UI???

oh you can have it easier
noticed IMPL_APP_CONTROLLER_SUBCLASS in UnityAppController.h? :wink: it does exactly that
Actually you (more or less) described the process of doing custom AppController: subclass, override what you need, add define so yours is instantiated. And yes, we are prepping samples, just wait a bit

hm, i dont think we support multiple unity views [because you will need ton of stuff to make it work], but on the other hand it is kinda doable (as in - rendering to separate views) - airplay works this way more or less. But as for integrating unity view - yes, you can have smaller unity view somewhere in your hierarchy.

Ah, thanks, I didn’t look for clues in UnityAppController.h so I missed the IMPL_APP_CONTROLLER_SUBCLASS #define. Looking forward to the samples. Thanks again.

What does this do exactly, if you could explain. I am working on figuring this out right now.

So is there then now a way to completely destroy unity? Or still only the Pause / unpause way.

I doubt there is, and really wouldn’t want to at all. I initially wanted to do this, but after understanding a bit more just about Mono in general and how it’s supposed to work.

After your app launches, it is then supposed to completely initialize the Mono core, and have mono running in the background, taking up an extra 5-8 mb of RAM. That is just the downside of Mono, which is pretty minor now, it’s only 5-8 Mb. In MonoTouch you can’t initialize your Mono library, use it, then at some point completely destroy the Mono instance running. Not supposed to be that way. Mono is intended to just be an additional, constant running layer on top of Objective-C in iOS app. Not in anyway is MonoTouch, and thus Unity, supposed to be something which can initialize and uninitialize like a seperate component of the app.

Plus really, would you want to add an additional 2-4 seconds onto the load time to reinitialize the MonoCore and UnityEngine anytime someone loads a Unity scene? I wouldn’t. I initially made it in my hybrid Native+Unity app that Unity didn’t get initialized till first usage. But then I moved it to initialize in ApplicationDidFinishLaunching just because it’s better to have that extra 2 seconds in the very begining of the app rather than once the user is in the UI and clicking around.

What COULD be done is potentiailly the Mono and Unity core could be more intelligent in allocating and unallocating it’s own resources. I don’t know if it is or not. I suspect more could be done with this. Cause how much RMA is an empty unity scene now on iOS with full stripping? Isn’t it like 12 MB? It’d be nice if when you loaded a scene, it kept track of what exactly it needed to put in memory and what it didn’t. 12 MB for just the mono core and an empty unity scene does seem like too much.

Is the documentation for this anywhere near complete ?

Any news about documentation for this?

Hi Alexey,
please let me know where it is possible to get a simple sample application of using IMPL_APP_CONTROLLER_SUBCLASS. I am ok with rough and undocumented one.

best regards,
Alex.

Hello. I’m trying to follow jondbell technique but I can’t get it to work on my project, unfortunately.

I have an application with two views on a storyboard. On the first view I want to display some custom content and a button that makes a push to the second view, where I put my Unity scene.

But when I run the app I get a dark screen and Unity seems to fail initialization. I get the following error on the console

How can I implement that so it will work? Any help or hint will be greatly appreciated. I’m new to Objective-C but I will dedicate all my time to this until I solve this issue.

Thanks!

Ok, so now I got Unity to initialize properly

I had a custom ApplicationDidFinishLaunchingWithOptions method on my Custom App Delegate, so it was overriding the one in UnityAppController. To fix this you need to put

[super application:application didFinishLaunchingWithOptions:launchOptions];

at the very beginning of the method. I guess every time you override a UnityAppController method, you will probably want to make a call to the corresponding super method so you will not loose any functionality. Now it is launching Unity fullscreen with no problems.

So next step is loading my custom Storyboard. And here I’m stuck again.

I tried this

@interface CustomAppDelegate ()
@property (nonatomic, strong) UIStoryboard *storyboard;
@end

@implementation CustomAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
	//Call super method
	[super application:application didFinishLaunchingWithOptions:launchOptions];
	
	//Init storyboard
	self.storyboard = [UIStoryboard storyboardWithName: @"MainStoryboard" bundle: nil];
    self.rootViewController = [self.storyboard instantiateInitialViewController];
	
	//Return
    return YES;
}

First it complained about the assignment of the rootViewController, so I removed the readonly flag of its property declaration in UnityAppController.h. Then I tried to run it and I got a SIGABRT error at launch.

I will keep working on this. Any help or hint would be fantastic

I second this.

I am going to have to be upgrading all of our Unity 3.5 apps to Unity 4 in the next few weeks. Two of these apps are heavily integrated into native CocoaTouch apps and rely on my old hacked AppController.

If there isn’t any documentation or any example soon I’m going to end up just having to wing this on my own next week. Which I’d really prefer not to do.

well, samples are still not up (sigh)
here, i uploaded some for you to try out
http://beta.unity3d.com/alexey/OverlayUI.zip
this one is quite simple and straightforward - it customize default root view controller to show date picker (and pass data back and forth)
http://beta.unity3d.com/alexey/NavigationController.zip
it shows how to insert unity view into NavigationController. It uses your usual default view controller as root, but now unity view is a bit deeper 8)

As usual, if you think that we need to have a bit more samples in this area - spill it. I am fine with doing some more quick projects.

1 Like

Thanks a million times for this. I didn’t realize it was possible to do it in such a clean and elegant way. Just one more thing though, how can I get it to work with storyboards? Usually, I just create my layouts in a storyboard and iOS will launch my first ViewController automatically with no real code.

Imagine this scenario: I have an application with a few scenes. On the first, I select what I want to see next. One of the options is a scene where I have some Unity content inside a view (not fullscreen, just a portion of the window).

1344626--65782--$Storyboard.png

How can I achieve this? I have been using Unity for some years now, but I have only started dealing with native iOS code a few weeks ago and this is frying my brain. Thanks for your help

challenge accepted! 8)
mind you - i have no idea what storyboard is (i wont even call mself objc programmer), but i’ll a bit into this next week

Thank you, Alexey! I understand that Objective C may not be your language of choice, but while reading your post I couldn’t help but think “Alright, yeah! Artillery is coming” :slight_smile:

I will be pleased to give you a quick tour of Storyboards. (I hope this is not considered off topic)

Storyboards is a fast way to layout your apps with little to no code. It gives you a visual editor where you can arrange your views and controls and iterate it very fast with the feedback of designers or clients.

For example, let’s build a prototype for your second project using storyboards.

In Xcode, we create a new project and choose Application > Single View Application. On the next dialog we check the option “Use Storyboards”. We will then see this

Storyboards are only available since iOS 5, so we make sure we target a recent version. The MainStoryboard will be launched when the application starts. If we take a look in the MainStoryboard.storyboard file, we’ll see that it already contains an empty ViewController that we can edit. The arrow in the left means this is the first ViewController that will be displayed.

1345325--65859--$img02.png

If we select this ViewController and open the Identity Inspector, we’ll see that it is an instance of class ViewController (subclassed from UIViewController). This is the place where we can assign different classes to our objects.

1345325--65860--$img03.png

So now let’s create another ViewController for our second scene. We just need to open the Object Library and drag a new UIViewController to the storyboard. We will have this

1345325--65861--$img04.png

Now we change the color of the first view to blue to differentiate it and add a button to it from de Object Library. To make this button open the second ViewController we just need to right click on it (or ctrl-click) and drag to the second scene. It will ask what kind of Action Segue we want. We can choose Push. A final step is to embed everything inside a Navigation Controller, so we select the first ViewController and do

Editor > Embed In > Navigation Controller

Now he have this

1345325--65862--$img05.png

And it should be working now. We can run it on the simulator to test it out. It’s a working prototype and we haven’t write a single line of code yet. So you can see how storyboards are useful. In fact, all the applications that I have seen this last few weeks (in other words, my entire Objective C career :slight_smile: ) use this workflow.

To make the second scene display a web page, we just need a few more seconds of work. We create a new Objective C class, derived from UIViewController, name it WebViewController, for example, and define it as the class of our second ViewController in the Identity Inspector. Then we choose it’s inner view and make it derive UIWebView. Then we open the Assitant Editor to show simultaneously our storyboard and WebViewController.h. We drag from the view to the @interface and we create an outlet named webView.

A bit of code now, in the WebViewController.m we put this inside viewDidLoad

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://unity3d.com"]];

[self.webView loadRequest:request];

And our prototype is almost done! We only need to fill that blue view in the first scene with our Unity content. Unfortunately I have no idea how that can be done. So that’s where your help will be immensely useful :slight_smile:

Here’s hoping it can be done
Cheers!

I got a unity view working within a storyboard. This is a very simple example, but make sure:

  1. You have a StoryBoard created and that it is set as the “Main Storyboard” in the Target Summary settings (it should also show up in the plist).

  2. Add the window property to UnityAppController.h like so:

@property (strong, nonatomic) UIWindow *window;
  1. Your createViewHierarchyImpl function could look like this:
- (void)createViewHierarchyImpl;
{
    
    // STORYBOARD
    
    // Attempt 1: don't set the main storyboard in the target settings; just instantiate it programmatically.
    // THIS DOESN'T SEEM TO WORK
/*    UIStoryboard *storyBoard    = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
    UIViewController *mainVC    = [storyBoard instantiateInitialViewController];
    _rootController             = mainVC;
    _rootView                   = mainVC.view;*/
    
    // Attempt 2: set the main storyboard in the target settings and then grab the existing view controller
    // THIS SEEMS TO WORK
    _rootController             = [self.window rootViewController];
    _rootView                   = _unityView;// _rootController.view;
}