您的位置:首页 > 移动开发 > Unity3D

[转]Building a iOS Unity + UIView / UIViewController / Interface Builder App

2012-10-08 09:50 701 查看
转自:http://alexanderwong.me/post/29949258838/building-a-ios-unity-uiview-uiviewcontroller

 

 

Building a iOS Unity + UIView / UIViewController / Interface Builder App

When you build your Unity 3D project for the iPhone/iPad, Unity will generate a new Xcode project for you from scratch. It will even overwrite most files on subsequent builds. The design pattern assumes you’ll only want to run Unity in the app and nothing
else (no custom UIViews or UIViewControllers, etc).

However, there are a number of cases where you might want to integrate Unity into your app and be able to show custom UIViews. Perhaps, you want to use Unity only for a portion of your application flow. Configuring your Xcode project to allow you to do this
is possible, albeit quite tricky.

Before we get started, you should note:

Unity cannot be completely stopped and then started on demand (as of the writing of this post). The best you’ll be able to do is pause Unity, change to a blank scene to free up some of Unity’s memory use, and then load a new scene and resume.
(In AppController.mm might notice the UnityCleanup method and wrongly assume you can call it and callapplicationDidFinishLaunchingWithOptions to stop and start Unity, but you can’t. If you try, your app will crash.)
Building everything in Unity makes it simple to build your application across platforms (iPhone + Android). Conversely, integrating Unity with your Xcode project means you’ll have to port over your Objective-C.
There is no official support (currently) for writing your application this way, and so it will rest solely on your shoulders to ensure your application continues to function in the future.
Here’s the game plan for how to integrate Unity:

Use your own AppDelegate (from now on referred to as YourAppDelegate) and forward all UIApplicationDelegate methods toAppController, which you instantiate in
applicationDidFinishLaunchingWithOptions in yourYourAppDelegate.
Set YourAppDelegate’s window property to keep track of the window returned byAppController. Instantiate your UIViewControllers or UIViews and add them as a subview to the aforementioned window. Your views are basically overlaid on top
of Unity’s view.
Expose methods to play and pause Unity.
Let’s get started:

0. Import, link, and copy all files and libraries needed by Unity into your app.

Start by copying all files in the folders named “Classes” and ”Libraries” from Unity into your app. Under “Classes”, movemain.mm out of your project so you can reference it later. Also copy ”Data” but do not subversion this folder as it is generated
each time your build your Unity application.

Now, under Targets > YourAppTarget > Build Phases, click “Add Build Phase” and select “Run Script”. Paste the contents of the Run Script from the Xcode project generated by Unity here. Mine looks like:

rm -rf "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Data"

cp -Rf "$PROJECT_DIR/Data" "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Data"

Under “Compile Sources”, check that the Unity Library files are linked. If you are using ARC in your project, add:
-fno-objc-arc

to the “Compiler Flags” next to any of Unity’s .m or .mm files.
Under “Link Binary With Libraries”, add any missing libraries from the Unity Xcode app and set the required/optional field accordingly.
1. Merge Unity’s .pch and main.mm file with your own.
For the .pch file, you can just about copy and paste its contents and overwrite your own. If you have custom code in your own file, you’ll have to merge by hand.
To merge the main.mm files, copy and paste Unity’s code into your file, but replace theirUIApplicationMain call with your own:
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([YourAppDelegate class]));
}

You’ll likely have to change the extension on your main.m file to.mm. Again, if you have any custom code, merge it by hand.
2. Configure your application delegate files.
In YourAppDelegate create the following properties as applicable:
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UINavigationController *navigationController;
@property (strong, nonatomic) AppController *unityController; // unity

In AppController.h and AppController.mm create a getting method to return the window created by Unity.
- (UIWindow *)window
{
return _window;
}

In application didFinishedLaunchingWithOptions instantiateAppController and store the window, also keep track of any UINavigation controllers you need.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// unity
BOOL returnBOOL;
if (_unityController == nil) {
_unityController = [[AppController alloc] init];
}
returnBOOL = [_unityController application:application didFinishLaunchingWithOptions:launchOptions];

//... your code here...

// unity, set window
_window = [_unityController window];

// navigation controller
_navigationController = [[UINavigationController alloc] initWithRootViewController:...];
[_window addSubview:_navigationController.view];

//... your code here...

// unity, return
return returnBOOL;

Lastly, forward all remaining UIApplicationDelegate methods like so…
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
...
// unity
[_unityController applicationDidReceiveMemoryWarning:application];
}

- (void)applicationWillResignActive:(UIApplication *)application
{
...
// unity
[_unityController applicationWillResignActive:application];
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
...
// unity
[_unityController applicationDidEnterBackground:application];
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
...
// unity
[_unityController applicationWillEnterForeground:application];
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
...
// unity
[_unityController applicationDidBecomeActive:application];
}

- (void)applicationWillTerminate:(UIApplication *)application
{
...
// unity
[_unityController applicationWillTerminate:application];
}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
...
// unity
[_unityController application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
...
// unity
[_unityController application:application didFailToRegisterForRemoteNotificationsWithError:error];
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
...
// unity
[_unityController application:application didReceiveRemoteNotification:userInfo];
}

- (void)application:(UIApplication*)application didReceiveLocalNotification:(UILocalNotification*)notification
{
...
// unity
[_unityController application:application didReceiveLocalNotification:notification];
}

Now Unity will be launched when your application launches but your application flow should be unchanged. Since your UINavigationController is added to the window after Unity, it will cover Unity. To handle switching back and forth between Unity
and your views a little better, let’s add the ability to pause and resume Unity.
3. Pause and resume Unity.
Again in AppController.h and AppController.mm, create the following pause method:
- (void)unityPause:(BOOL)pause
{
UnityPause(pause);
}

In YourAppDelegate, create the corresponding methods:
// Unity

- (void)playUnity
{
[_unityController unityPause:NO];
}

- (void)pauseUnity
{
[_unityController unityPause:YES];
}

4. Swap between Unity and your UIViews.
As previously mentioned, Unity will always be running in the background. To display your own views, simply add them to the window above Unity’s view and be sure to pause / resume and clear the scene as appropriate to help alleviate the overhead
of running Unity in the background.
5. Configure “Build Settings” under targets before your build.
b679

Unity is particularly finicky about your build settings and target. In fact, you’ll need to rebuild your Unity project to switch between an iOS device target and a simulator target. The target’s “Build Settings” will also have to be configured
according to your intended device. The best way to set up “Build Settings” is to simply copy and merge settings line by line from the “Build Settings” generated by Unity’s Xcode project.
Create two targets in your project, one for simulator builds and one for device builds so you don’t have to modify settings each time. Then in Unity, build the Xcode project for the simulator and then your actual device. In between builds, copy
over your build settings to your Xcode project’s respective targets.
Some things to note here: Be sure to set the TARGET_IPHONE_SIMULATOR=1 preprocessor macro on your simulator build. And, if you have any-all_load linker flags, you’ll have to remove them.
6. Build your Unity + UIView app.
First build your Unity project. Then in the generate Xcode files, copy the contents of the “Data” folder into your project’s “Data” folder. Ensure that your build settings in Unity match the iOS version and device type you intend to build your
Xcode project for. If you build your Unity project for your iPhone and try to run your Xcode project in the simulator it will not work, and vice-versa.
If all goes well, you might see a few warnings but no errors, and your app should start right up.
If you need more control, you can communicate with your Unity scripts from your Objective-C by following the directions in this post:
http://alexanderwong.me/post/29861010648/call-objective-c-from-unity-call-unity-from

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息