iOS集成unity模塊(Xcode 11.5--unity 2019.3.3f1)
集成unity模塊
- 打開項(xiàng)目工程(A工程)和unity導(dǎo)出工程(B工程)文件夾,讓A工程頁面處于有.xcodeproj目錄下,找到B工程中的Classes,Libraries和Data文件夾,先直接復(fù)制粘貼到工程當(dāng)前目錄下,然后通過拖拽的方式,將Classes和Libraries添加到項(xiàng)目中,同時(shí)勾選Create groups;data也拖拽到項(xiàng)目中并勾選Create folder references。注意在Xcode中各文件夾處于同一層級(jí)。

- 找到導(dǎo)入的B工程的.pch文件,全選復(fù)制到A工程原有.pch中,并將A工程原有的#import ... 都放到
#ifdef __OBJC__與#endif之間。然后添加#import "UnityAppController.h",并刪除導(dǎo)入的B工程的.pch文件。

- 接下來就是一些Build Setting的配置了。
Enable Bitcode:NO;
Other Linker Flags添加(注意:一定要按順序)
-weak_frameworkCoreMotion-weak-lSystem-licucore-
對(duì)Classes和Libraries的路徑進(jìn)行配置;
在Header Search Paths中添加:
$(SRCROOT)/Classes
$(SRCROOT)/Classes/Native
$(SRCROOT)/Libraries/libil2cpp/include在Library Search Paths中添加:
$(PROJECT_DIR)/Libraries(如有,則不需要重復(fù)添加)
$(PROJECT_DIR)/Libraries/Plugins/iOS Other C Flags添加
-DINIT_SCRIPTING_BACKEND=1和-DRUNTIME_IL2CPP=1設(shè)置Enable C++ Runtime Types:NO
設(shè)置Overriding Deprecated Objective-C Methods:Yes
設(shè)置Unintentional Root Class:Yes
添加用戶設(shè)置Add User-Defined Setting共4項(xiàng):
GCC_THUMB_SUPPORT : NO GCC_USE_INDIRECT_FUNCTION_CALLS : NO UNITY_RUNTIME_VERSION : 2019.3.3f1(看B工程中Unity實(shí)際版本號(hào)) UNITY_SCRIPTING_BACKEND : il2cpp
然后是Build Phases配置Link Binary With Libraries,根據(jù)B工程中Build Phases里引入的庫照搬照抄即可,需要注意的是status也要和B工程中的相同,如果.a文件沒有就去剛剛導(dǎo)入到A工程中的Library文件夾里找。
新建UnityFramework.framework,并設(shè)置.framework配置。通過TARGETS添加新的framework,并按照B工程中UnityFramework.framework的配置設(shè)置新建framework的Build Settings和Build Phases。還要記得把B工程中UnityFramework.h的內(nèi)容復(fù)制到新的framework里。


修改原iOS項(xiàng)目?jī)?nèi)容
- 將Classes文件夾中main.mm代碼全都復(fù)制到A工程原有main.m下方,設(shè)置
AppControllerClassName = "AppDelegate",并將.m改為.mm,再刪除Classes中的main.mm。

main.mm中還需要注意的一點(diǎn),將剛才新建的framework也要引入進(jìn)來,并且把運(yùn)行條件添加上。在B工程中也有,可以直接復(fù)制。
#include <UnityFramework/UnityFramework.h>
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()方法的實(shí)現(xiàn)改為AppDelegate中的Controller。
UnityAppController* GetAppController() { //刪除原有返回值 // return _UnityAppController; return (UnityAppController *)[[UIApplication sharedApplication] valueForKeyPath:@"delegate.unityController"]; }

-
接下來修改AppDelegate.h和AppDelegate.m文件,等等,在修改AppDelegate之前最好再加一步,就是新建一個(gè)Controller,繼承UnityAppController,避免修改UnityAppController文件中的內(nèi)容,并且要把.m改為.mm。
SSSUnityController.h如下
#import <UnityFramework/UnityFramework.h> @interface SSSUnityController : UnityAppController + (instancetype)instance; - (void)initUnity; - (void)pauseUnity; - (void)startUnity1; - (BOOL)isPaused; @endSSSUnityController.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 <csignal> @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; // 注冊(cè)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", ""); // 調(diào)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

-
現(xiàn)在可以對(duì)AppDelegate進(jìn)行修改了,引入剛才的新建子類SSSUnityController,添加用來展示unity內(nèi)容的window,添加展示和隱藏window的方法。
#import <UIKit/UIKit.h> @class SSSUnityController; @interface AppDelegate : UIResponder <UIApplicationDelegate> @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];,同時(shí)實(shí)現(xiàn).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工程需要跳轉(zhuǎn)到unity的地方設(shè)置入口即可。比如我在ViewController中創(chuàng)建了按鈕,點(diǎn)擊按鈕事件就為:
//點(diǎn)擊按鈕 - (void)btnClicked { SSSUnityController *vc = [SSSUnityController instance]; [vc initUnity]; }

- 設(shè)置A工程的Edit Scheme的Build Configuration為Release,因?yàn)閡nity內(nèi)容無法在debug環(huán)境下運(yùn)行。當(dāng)然我們可以通過項(xiàng)目配置設(shè)置debug和release環(huán)境進(jìn)行區(qū)分,然后將Classes文件夾下的DynamicLibEngineAPI-functions.h中的內(nèi)容,設(shè)置到release中。


- 此時(shí)基本配置都已經(jīng)完成了,但仍然運(yùn)行不了,因?yàn)樵趯?dǎo)入進(jìn)來的Libraries文件夾中,只有RegisterMonoModules.cpp,缺少RegisterMonoModules.h文件,需要我們手動(dòng)添加一個(gè).h文件。

- 這樣再運(yùn)行就不出出現(xiàn)報(bào)錯(cuò)了!
可能出現(xiàn)的問題
我在集成的過程中基本上沒有出現(xiàn)什么問題,unity設(shè)置上看到一個(gè),也不知道是否有用,這里也都一并寫出吧。
取消Auto Graphics API的勾選并移除Metal選擇OpenGLES2(補(bǔ)充:取消勾選,選擇Metal也能成功,根據(jù)相關(guān)報(bào)錯(cuò)信息自行修改)
取消Strip Engine Code的勾選
替換unity內(nèi)容
如果要替換untiy的內(nèi)容,只需把Data文件夾和Classes中的Native文件夾刪除替換即可,導(dǎo)入方式還與原來相同,unity的內(nèi)容就會(huì)替換了。
祝大家都可以成功集成unity模塊~!