Unity导出Xcode工程集成进另一个原生Xcode工程,错误及解决方法记录

最后更新时间:2018.4.18

最近在研究Unity导出的Xcode工程如何集成在现有工程中。现将过程中遇见的问题整理如下。

Unity导出Xcode工程编译错误

  1. MapFileParser.sh: Permission denied

    ADB6928C-7EF7-4469-8CEC-856B504A63B3

    打开终端,进入MapFileParser.sh所在目录,执行

    1
    $ chmod 777 MapFileParser.sh
  2. 推送警告

    E432AF53-86D7-44A7-9649-F262E3EBC351

    解决方法Capablilties->Background Modes->Remote notifications

    75BDC5C5-7DC9-4CB4-A55C-1959E7198C10

Unity导出Xcode工程集成进原生Xcode工程

集成步骤

Unity导出Xcode工程

在iOS的Player Setting中进行设置

  • Resolution and Presentation

    根据项目需要设定,需要注意的是Orientation方向必须是原生工程Orientation方向的子集

  • Other Settings

    • 消掉Auto Graphics API,Graphics APIs列表中只留OpenGLES2
    • Scripting Backend选择IL2CPP
    • Bundle Identifier、Target Device、Target minimum iOS Version根据原生工程设置

这是我导出来的工程目录,设备只选择了iPhone

111

集成工程

注意:Build Setting和Build Phases中的设置均是根据Unity_Xcode中设置得到的,集成的时候对照两个工程的设置集成,这里只是一个例子

  • 我在原生工程目录下新建了一个Unity文件夹来放置从Unity_Xcode工程中拷贝过来需要使用的文件

222

  • 将文件添加进工程目录

    将Classes、Libraries、MapFileParser.sh添加进工程目录

333

​ 将Data添加进工程目录

444

​ 注意这两种不同的添加形式

  • 添加framework

    根据自己导出的Unity_Xcode工程添加

555

  • Build Settings

    设置Header Search Paths

111

​ 设置Library Search Paths

444

​ 设置Other Linker Flags

​ 这里顺序保持一致

333

​ 设置Other C Flags & Other C++ Flags

222

​ 设置C Language Dialect,在 2017.3.1f1 测试不更改,使用 GNU99 依然可用

222

​ 设置C++ Language Dialect,,在 2017.3.1f1 测试不更改,使用 GNU++11 依然可用

222

​ 设置C++ Standard Library

222

​ 设置Enable Bitcode

222

​ Add User-Defined Setting

222

​ 添加GCC_THUMB_SUPPORT

​ 添加GCC_USE_INDIRECT_FUNCTION_CALLS

​ 添加UNITY_RUNTIME_VERSION。此项根据Unity导出的版本填写。

​ 添加UNITY_SCRIPTING_BACKEND

222

  • Build Phases

    添加Run Script

222

​ 添加”$PROJECT_DIR/iOS_Unity_Test01/Unity/MapFileParser.sh”

222

  • 新建PCH文件,命名为PrefixHeader。将Classes中的Prefix.pch文件的内容全部拷贝到Supporting Files中的PrefixHeader.pch中,并删除Classes中的Prefix.pch文件引用
  • 将Classes/main.mm全部内容复制到main.m并把扩展名改为.mm,然后删除Classes/main.mm文件引用,注意红色框圈住的修改细节

image-20180419110553779

  • 修改UnityAppController.h

    注意:我当前用的 2017.3.1f1 版本这里已经不需要更改了,可忽略

    1
    2
    3
    4
    5
    #import "AppDelegate.h"
    inline UnityAppController* GetAppController()
    {
    return (UnityAppController *)[[UIApplication sharedApplication] valueForKeyPath:@"delegate.unityController"];
    }
  • 修改AppDelegate.h

1
2
3
4
5
6
7
8
9
10
11
12
#import <UIKit/UIKit.h>
#import "UnityAppController.h"

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UIWindow *unityWindow;

- (void)showUnityWindow;
- (void)hideUnityWindow;

@end
  • 修改AppDelegate.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
@implementation AppDelegate

- (UIWindow *)unityWindow {
return UnityGetMainWindow();
}

- (void)showUnityWindow {
[self.unityWindow makeKeyAndVisible];
UnityPause(false);
}

- (void)hideUnityWindow {
UnityPause(true);
[self.window makeKeyAndVisible];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.

_UnityAppController = [[UnityAppController alloc] init];
[_UnityAppController application:application didFinishLaunchingWithOptions:launchOptions];

self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
TestViewController *vc = [[TestViewController alloc] init];
self.window.rootViewController = vc;
[self.window makeKeyAndVisible];

return YES;
}


- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
[_UnityAppController applicationWillResignActive:application];
}


- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
[_UnityAppController applicationDidEnterBackground:application];
}


- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
[_UnityAppController applicationWillEnterForeground:application];
}


- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
[_UnityAppController applicationDidBecomeActive:application];
}


- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
[_UnityAppController applicationWillTerminate:application];
}


@end

集成过程中遇见的一些问题

  1. 编译完成出现许多Code will never be executed的警告⚠️

    111

    解决方法:在Build Settings中将Unreachable Code设置为No可以消除警告

    222

  2. 编译出现Expected unqualified-id错误

    9D5AA7E6-1800-4904-9E7A-E268547875CB

    解决方法:在PrefixHeader.pch文件中,将自己的头文件全部放入#ifdef __OBJC__中,如下:

    177BB71A-B8E2-4DC9-B155-2EADFF2C9E2D

  3. 编译出现 Control reaches end of non-void function 错误

    解决方法:在 Build Settings 中将 Mismatched Return Type 设置为 Yes 可以消除

参考资料

iOS Player Settings

Unity3D工程并入iOS工程总结

unity3D与iOS原生工程项目合并以及合并过程中的问题

iOS - 将Unity导出的Xcode工程导入到另一个Xcode项目, 及常见报错的解决方法

将U3d工程嵌入iOS工程中