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

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

集成unity模块

  1. 打开项目工程(A工程)和unity导出工程(B工程)文件夹,让A工程页面处于有.xcodeproj目录下,找到B工程中的Classes,Libraries和Data文件夹,先直接复制粘贴到工程当前目录下,然后通过拖拽的方式,将Classes和Libraries添加到项目中,同时勾选Create groups;data也拖拽到项目中并勾选Create folder references。注意在Xcode中各文件夹处于同一层级。
  1. 找到导入的B工程的.pch文件,全选复制到A工程原有.pch中,并将A工程原有的#import ... 都放到#ifdef __OBJC__#endif之间。然后添加#import "UnityAppController.h",并删除导入的B工程的.pch文件。
  1. 接下来就是一些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
  1. 然后是Build Phases配置Link Binary With Libraries,根据B工程中Build Phases里引入的库照搬照抄即可,需要注意的是status也要和B工程中的相同,如果.a文件没有就去刚刚导入到A工程中的Library文件夹里找。

  2. 新建UnityFramework.framework,并设置.framework配置。通过TARGETS添加新的framework,并按照B工程中UnityFramework.framework的配置设置新建framework的Build Settings和Build Phases。还要记得把B工程中UnityFramework.h的内容复制到新的framework里。


修改原iOS项目内容

  1. 将Classes文件夹中main.mm代码全都复制到A工程原有main.m下方,设置AppControllerClassName = "AppDelegate",并将.m改为.mm,再删除Classes中的main.mm。

main.mm中还需要注意的一点,将刚才新建的framework也要引入进来,并且把运行条件添加上。在B工程中也有,可以直接复制。

#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()方法的实现改为AppDelegate中的Controller。

    UnityAppController* GetAppController()
    {
        //删除原有返回值
    //    return _UnityAppController;
        return (UnityAppController *)[[UIApplication sharedApplication] valueForKeyPath:@"delegate.unityController"];
    }
    
  1. 接下来修改AppDelegate.h和AppDelegate.m文件,等等,在修改AppDelegate之前最好再加一步,就是新建一个Controller,继承UnityAppController,避免修改UnityAppController文件中的内容,并且要把.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;
            // 注册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
    
  1. 现在可以对AppDelegate进行修改了,引入刚才的新建子类SSSUnityController,添加用来展示unity内容的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];,同时实现.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工程需要跳转到unity的地方设置入口即可。比如我在ViewController中创建了按钮,点击按钮事件就为:

    //点击按钮
    - (void)btnClicked {
        
        SSSUnityController *vc = [SSSUnityController instance];
        [vc initUnity];
    }
    
  1. 设置A工程的Edit Scheme的Build Configuration为Release,因为unity内容无法在debug环境下运行。当然我们可以通过项目配置设置debug和release环境进行区分,然后将Classes文件夹下的DynamicLibEngineAPI-functions.h中的内容,设置到release中。
  1. 此时基本配置都已经完成了,但仍然运行不了,因为在导入进来的Libraries文件夹中,只有RegisterMonoModules.cpp,缺少RegisterMonoModules.h文件,需要我们手动添加一个.h文件。
  1. 这样再运行就不出出现报错了!

可能出现的问题

我在集成的过程中基本上没有出现什么问题,unity设置上看到一个,也不知道是否有用,这里也都一并写出吧。

  1. 取消Auto Graphics API的勾选并移除Metal选择OpenGLES2(补充:取消勾选,选择Metal也能成功,根据相关报错信息自行修改)

  2. 取消Strip Engine Code的勾选

替换unity内容

如果要替换untiy的内容,只需把Data文件夹和Classes中的Native文件夹删除替换即可,导入方式还与原来相同,unity的内容就会替换了。

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354