iOS集成unity模块(Xcode 11.5--unity 2019.3.3f1)
集成unity模块
- 打开项目工程(A工程)和unity导出工程(B工程)文件夹,让A工程页面处于有.xcodeproj目录下,找到B工程中的Classes,Libraries和Data文件夹,先直接复制粘贴到工程当前目录下,然后通过拖拽的方式,将Classes和Libraries添加到项目中,同时勾选Create groups;data也拖拽到项目中并勾选Create folder references。注意在Xcode中各文件夹处于同一层级。
- 找到导入的B工程的.pch文件,全选复制到A工程原有.pch中,并将A工程原有的#import ... 都放到
#ifdef __OBJC__
与#endif
之间。然后添加#import "UnityAppController.h"
,并删除导入的B工程的.pch文件。
- 接下来就是一些Build Setting的配置了。
Enable Bitcode:NO;
Other Linker Flags添加(注意:一定要按顺序)
-weak_framework
CoreMotion
-weak-lSystem
-licucore
-
对Classes和Libraries的路径进行配置;
在Header Search Paths中添加:
$(SRCROOT)/Classes
$(SRCROOT)/Classes/Native
$(SRCROOT)/Libraries/libil2cpp/include
在Library Search Paths中添加:
$(PROJECT_DIR)/Libraries(如有,则不需要重复添加)
$(PROJECT_DIR)/Libraries/Plugins/iOS
Other C Flags添加
-DINIT_SCRIPTING_BACKEND=1
和-DRUNTIME_IL2CPP=1
设置Enable C++ Runtime Types:NO
设置Overriding Deprecated Objective-C Methods:Yes
设置Unintentional Root Class:Yes
添加用户设置Add User-Defined Setting共4项:
GCC_THUMB_SUPPORT : NO GCC_USE_INDIRECT_FUNCTION_CALLS : NO UNITY_RUNTIME_VERSION : 2019.3.3f1(看B工程中Unity实际版本号) UNITY_SCRIPTING_BACKEND : il2cpp
然后是Build Phases配置Link Binary With Libraries,根据B工程中Build Phases里引入的库照搬照抄即可,需要注意的是status也要和B工程中的相同,如果.a文件没有就去刚刚导入到A工程中的Library文件夹里找。
新建UnityFramework.framework,并设置.framework配置。通过TARGETS添加新的framework,并按照B工程中UnityFramework.framework的配置设置新建framework的Build Settings和Build Phases。还要记得把B工程中UnityFramework.h的内容复制到新的framework里。
修改原iOS项目内容
- 将Classes文件夹中main.mm代码全都复制到A工程原有main.m下方,设置
AppControllerClassName = "AppDelegate"
,并将.m改为.mm,再删除Classes中的main.mm。
main.mm中还需要注意的一点,将刚才新建的framework也要引入进来,并且把运行条件添加上。在B工程中也有,可以直接复制。
#include
UnityFramework* UnityFrameworkLoad()
{
NSString* bundlePath = nil;
bundlePath = [[NSBundle mainBundle] bundlePath];
bundlePath = [bundlePath stringByAppendingString: @"/Frameworks/UnityFramework.framework"];
NSBundle* bundle = [NSBundle bundleWithPath: bundlePath];
if ([bundle isLoaded] == false) [bundle load];
UnityFramework* ufw = [bundle.principalClass getInstance];
if (![ufw appController])
{
// unity is not initialized
[ufw setExecuteHeader: &_mh_execute_header];
}
return ufw;
}
-
修改UnityAppController.mm文件,将GetAppController()方法的实现改为AppDelegate中的Controller。
UnityAppController* GetAppController() { //删除原有返回值 // return _UnityAppController; return (UnityAppController *)[[UIApplication sharedApplication] valueForKeyPath:@"delegate.unityController"]; }
-
接下来修改AppDelegate.h和AppDelegate.m文件,等等,在修改AppDelegate之前最好再加一步,就是新建一个Controller,继承UnityAppController,避免修改UnityAppController文件中的内容,并且要把.m改为.mm。
SSSUnityController.h如下
#import
@interface SSSUnityController : UnityAppController + (instancetype)instance; - (void)initUnity; - (void)pauseUnity; - (void)startUnity1; - (BOOL)isPaused; @end SSSUnityController.mm如下
#import "SSSUnityController.h" #import "AppDelegate.h" #import "UnityAppController.h" #import "UnityAppController+ViewHandling.h" #import "UnityAppController+Rendering.h" #import "DisplayManager.h" #import "UnityView.h" #include "RegisterMonoModules.h" #include "RegisterFeatures.h" #include
@interface SSSUnityController() @property (nonatomic, assign) BOOL isInitUnity; @end @implementation SSSUnityController + (instancetype)instance { AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate; return delegate.unityController; } - (instancetype)init { self = [super init]; if (self) { self.isInitUnity = NO; // 注册Unity的事件 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillTerminate:) name:UIApplicationWillTerminateNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; } return self; } void UnityInitTrampoline(); - (void)initUnity { AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate; if (!self.isInitUnity) { [super applicationDidBecomeActive:[UIApplication sharedApplication]]; UnityInitApplicationNoGraphics([[[NSBundle mainBundle] bundlePath] UTF8String]); [self selectRenderingAPI]; [UnityRenderingView InitializeForAPI: self.renderingAPI]; _window = delegate.unityWindow; _unityView = [self createUnityView]; [DisplayManager Initialize]; _mainDisplay = [DisplayManager Instance].mainDisplay; [_mainDisplay createWithWindow: _window andView: _unityView]; [self createUI]; [self preStartUnity]; self.isInitUnity = YES; _unityView.back = ^{ [delegate hideUnityWindow]; }; }else{ [self startUnity1]; } [delegate showUnityWindow]; } extern "C" { void ReturnToIOS() { AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate; [delegate hideUnityWindow]; } } - (void)pauseUnity { // UnitySendMessage("ARCamera", "Exit", ""); // 调Unity方法 退出模型 (与unity交互) UnityPause(1); } - (void)startUnity1 { UnityPause(0); } - (BOOL)isPaused { if (UnityIsPaused() == 1) { return YES; } else { return NO; } } -(void)applicationDidFinishLaunching:(UIApplication *)application{ } - (void)appWillEnterForeground:(NSNotification *)notification { [super applicationWillEnterForeground:[UIApplication sharedApplication]]; } - (void)appDidBecomeActive:(NSNotification *)notification { if (nil == self.unityView) { return; } [super applicationDidBecomeActive:[UIApplication sharedApplication]]; } - (void)appWillResignActive:(NSNotification *)notification { [super applicationWillResignActive:[UIApplication sharedApplication]]; } - (void)appWillTerminate:(NSNotification *)notification { [super applicationWillTerminate:[UIApplication sharedApplication]]; } - (void)appDidReceiveMemoryWarning:(NSNotification *)notification { [super applicationDidReceiveMemoryWarning:[UIApplication sharedApplication]]; } @end
-
现在可以对AppDelegate进行修改了,引入刚才的新建子类SSSUnityController,添加用来展示unity内容的window,添加展示和隐藏window的方法。
#import
@class SSSUnityController; @interface AppDelegate : UIResponder @property (nonatomic, strong)UIWindow *window; @property (nonatomic, strong)UIWindow *unityWindow; @property (nonatomic, strong)SSSUnityController *unityController; - (void)showUnityWindow; - (void)hideUnityWindow; @end
AppDelegate.m中要在- (BOOL)application:didFinishLaunchingWithOptions:
方法中添加初始化SSSUnityController的代码,_unityController = [[SSSUnityController alloc]init];
,同时实现.h中的方法。
- (UIWindow *)unityWindow {
if (!_unityWindow) {
if (!UnityGetMainWindow()) {
_unityWindow = [[UIWindow alloc]initWithFrame:UIScreen.mainScreen.bounds];
_unityWindow.backgroundColor = [UIColor redColor];
}else{
_unityWindow = UnityGetMainWindow();
}
}
return _unityWindow;
}
- (void)showUnityWindow {
[self.unityWindow makeKeyAndVisible];
}
- (void)hideUnityWindow {
[self.window makeKeyAndVisible];
[self.unityController pauseUnity];
}
-
在A工程需要跳转到unity的地方设置入口即可。比如我在ViewController中创建了按钮,点击按钮事件就为:
//点击按钮 - (void)btnClicked { SSSUnityController *vc = [SSSUnityController instance]; [vc initUnity]; }
- 设置A工程的Edit Scheme的Build Configuration为Release,因为unity内容无法在debug环境下运行。当然我们可以通过项目配置设置debug和release环境进行区分,然后将Classes文件夹下的DynamicLibEngineAPI-functions.h中的内容,设置到release中。
- 此时基本配置都已经完成了,但仍然运行不了,因为在导入进来的Libraries文件夹中,只有RegisterMonoModules.cpp,缺少RegisterMonoModules.h文件,需要我们手动添加一个.h文件。
- 这样再运行就不出出现报错了!
可能出现的问题
我在集成的过程中基本上没有出现什么问题,unity设置上看到一个,也不知道是否有用,这里也都一并写出吧。
取消Auto Graphics API的勾选并移除Metal选择OpenGLES2(补充:取消勾选,选择Metal也能成功,根据相关报错信息自行修改)
取消Strip Engine Code的勾选
替换unity内容
如果要替换untiy的内容,只需把Data文件夹和Classes中的Native文件夹删除替换即可,导入方式还与原来相同,unity的内容就会替换了。
祝大家都可以成功集成unity模块~!