iOS集成unity模塊(Xcode 11.5--unity 2019.3.3f1)

iOS集成unity模塊(Xcode 11.5--unity 2019.3.3f1)

集成unity模塊

  1. 打開項(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í)。
  1. 找到導(dǎo)入的B工程的.pch文件,全選復(fù)制到A工程原有.pch中,并將A工程原有的#import ... 都放到#ifdef __OBJC__#endif之間。然后添加#import "UnityAppController.h",并刪除導(dǎo)入的B工程的.pch文件。
  1. 接下來就是一些Build Setting的配置了。
    • Enable Bitcode:NO;

    • Other Linker Flags添加(注意:一定要按順序)-weak_framework CoreMotion -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
  1. 然后是Build Phases配置Link Binary With Libraries,根據(jù)B工程中Build Phases里引入的庫照搬照抄即可,需要注意的是status也要和B工程中的相同,如果.a文件沒有就去剛剛導(dǎo)入到A工程中的Library文件夾里找。

  2. 新建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)容

  1. 將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;
}
  1. 修改UnityAppController.mm文件,將GetAppController()方法的實(shí)現(xiàn)改為AppDelegate中的Controller。

    UnityAppController* GetAppController()
    {
        //刪除原有返回值
    //    return _UnityAppController;
        return (UnityAppController *)[[UIApplication sharedApplication] valueForKeyPath:@"delegate.unityController"];
    }
    
  1. 接下來修改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;
    
    @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 <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
    
  1. 現(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];
}
  1. 在A工程需要跳轉(zhuǎn)到unity的地方設(shè)置入口即可。比如我在ViewController中創(chuàng)建了按鈕,點(diǎn)擊按鈕事件就為:

    //點(diǎn)擊按鈕
    - (void)btnClicked {
        
        SSSUnityController *vc = [SSSUnityController instance];
        [vc initUnity];
    }
    
  1. 設(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中。
  1. 此時(shí)基本配置都已經(jīng)完成了,但仍然運(yùn)行不了,因?yàn)樵趯?dǎo)入進(jìn)來的Libraries文件夾中,只有RegisterMonoModules.cpp,缺少RegisterMonoModules.h文件,需要我們手動(dòng)添加一個(gè).h文件。
  1. 這樣再運(yùn)行就不出出現(xiàn)報(bào)錯(cuò)了!

可能出現(xiàn)的問題

我在集成的過程中基本上沒有出現(xiàn)什么問題,unity設(shè)置上看到一個(gè),也不知道是否有用,這里也都一并寫出吧。

  1. 取消Auto Graphics API的勾選并移除Metal選擇OpenGLES2(補(bǔ)充:取消勾選,選擇Metal也能成功,根據(jù)相關(guān)報(bào)錯(cuò)信息自行修改)

  2. 取消Strip Engine Code的勾選

替換unity內(nèi)容

如果要替換untiy的內(nèi)容,只需把Data文件夾和Classes中的Native文件夾刪除替換即可,導(dǎo)入方式還與原來相同,unity的內(nèi)容就會(huì)替換了。

祝大家都可以成功集成unity模塊~!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容