iOS+Unity iOS项目整合 Unity AR+3D(Unity5.4.0 Xcode8.3  OC语言)


swift整合版详见-->swift4.0+xCode9.1+Unity5.4

1、项目准备

工程截图.png
Unity工程.png

1.1 首先要有一个Unity工程和IOS工程
1.2 Unity导出时可选 模拟器模式真机模式,导出后只能在对应的设备运行
1.3 确保导出的unity可以直接运行
1.4 建议在将Unity和IOS放在同一目录下

2.导入

拖动.png
group.png

2.1 在xcode中创建一个group,例如“Unity”,主要便于分类
2.2 拖入操作有三个选项,是否复制、创建组或者关联、添加到目标
建议都不要复制(复制会将内容添加到IOS项目中,后续替换起来麻烦)
而参见1.4操作,更新时,每次替换Unity目录即可
2.3 Classes和Libraries 选择groups
Data文件选择reference
网上很多教程要删除Unity下的一些.h文件,不删也没关系(因为头文件太多,每次删都要好久,只要你不点开,这个只会对你的xcodeproj文件大小有一点点很小的影响)
2.4 特别的,如果使用VR功能,Data文件夹下Raw文件夹中的QCAR和Vuforia要再拖一次放在根目录(原因不明),如下图

vr.png

3 添加framework

framework.png

3.1 就是这么多。。。大家也可以参照导出的Unity工程下的Framework进行添加

4 配置

打开Building Setting

 Build Optons
      Enable Bitcode    NO
 Linking    
     Other Linker Flags
          -weak_framework
          CoreMotion
          -weak-lSystem
          -Wl,-undefined,dynamic_lookup **可以不加,如果报metal相关的错误可以加一下**
Other C Flags
      -DINIT_SCRIPTING_BACKEND=1
C Language Dialect
        选择 C99 
C++ Language Dialect 
        选择 C++ 11

4.1 Search Path
添加头文件路径和库文件路径


头文件.png

这里不用手打,可以直接拖进去添加
4.2 库路径


库文件.png

如果导出的Unity下有 plugin/ios 也添加进去
4.3 如果报头文件找不到之类的错误,看这里是否把包含头文件的路径都添加进去了
4.4 如果报link错误,看库路径是否都添加完整

4.5 其他配置


其他配置1.png

其他配置2.png

**关于配置部分比较麻烦,有两个方式参考:
1、参照导出的Unity项目的Building Setting
2、参照nerd (大神?)的视频教程, 原地址https://vimeo.com/145572230 (不太稳定)
**

5. 文件修改

5.1 修改pch
创建一个新的pch文件,找到原有的pch文件,复制到自定义的pch文件,并添加一行,如下图


原有的pch.png
自定义的pch.png

5.2 Building Setting中修改


添加pch路径.png

5.3 修改main文件
找到Unity的main.mm文件,直接复制到ios的main.m文件中(原有内容注释或者删除),并将文件名改为main.mm
找到

const char* AppControllerClassName = "UnityAppController";

替换为

const char* AppControllerClassName = "AppDelegate";

5.4 打开Build Phases 搜索main.mm会有两个文件,删除Unity下的main.mm(否则会编译冲突)
(如果报错,duplicate xxx 多半是因为这个文件重复)

6 工程文件修改

6.1 APPDelegate.h

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong,nonatomic) UnityAppController *unityAppController;
//@property (nonatomic,strong) UINavigationController *navVC;
@property (nonatomic, strong) UIWindow *unityWindow;
- (void)hideUnityWindow;
- (void)showUnityWindow;
@end

6.2 APPDelegate.m

#import "AppDelegate.h"

@interface AppDelegate ()

@end

@implementation AppDelegate

// Unity相关方法
- (UIWindow *)unityWindow{
    return UnityGetMainWindow();
}

- (void)showUnityWindow{
    UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [backButton setImage:[UIImage imageNamed:@"close.png"] forState:UIControlStateNormal];
    [backButton setAlpha:0.4];
    [backButton setFrame:CGRectMake(self.unityWindow.frame.size.width-60, 10, 50, 50)];
    [backButton addTarget:self action:@selector(hideUnityWindow) forControlEvents:UIControlEventTouchUpInside];

    [self.unityWindow addSubview:backButton];
    [self.unityWindow makeKeyAndVisible];
}

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


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.unityAppController=[[UnityAppController alloc] init];
    [self.unityAppController application:application didFinishLaunchingWithOptions:launchOptions];
    
    return YES;
}


- (void)applicationWillResignActive:(UIApplication *)application {
   
    [self.unityAppController applicationWillResignActive:application];
}


- (void)applicationDidEnterBackground:(UIApplication *)application {
    [self.unityAppController applicationDidEnterBackground:application];
}


- (void)applicationWillEnterForeground:(UIApplication *)application {
    [self.unityAppController applicationWillEnterForeground:application];
}


- (void)applicationDidBecomeActive:(UIApplication *)application {
    [self.unityAppController applicationDidBecomeActive:application];
}


- (void)applicationWillTerminate:(UIApplication *)application {
    [self.unityAppController applicationWillTerminate:application];
}


@end

6.3 UnityAppController.h

两个地方
@class UnityViewControllerBase;

#import "AppDelegate.h"
inline UnityAppController* GetAppController(){
   AppDelegate *delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
   return delegate.unityAppController;
}
#pragma once

#import <QuartzCore/CADisplayLink.h>

#include "PluginBase/RenderPluginDelegate.h"

@class UnityView;
@class UnityViewControllerBase;
@class DisplayConnection;

@interface UnityAppController : NSObject<UIApplicationDelegate>
{
    UnityView*          _unityView;
    CADisplayLink*      _displayLink;

    UIWindow*           _window;
    UIView*             _rootView;
    UIViewController*   _rootController;
    UIView*             _snapshotView;

    DisplayConnection*  _mainDisplay;

    // we will cache view controllers for fixed orientation
    // auto-rotation view contoller goes to index=0
    UnityViewControllerBase* _viewControllerForOrientation[5];
#if !UNITY_TVOS
    UIInterfaceOrientation  _curOrientation;
#endif

    id<RenderPluginDelegate>    _renderDelegate;
}

// override it to add your render plugin delegate
- (void)shouldAttachRenderDelegate;

// this one is called at the very end of didFinishLaunchingWithOptions:
// after views have been created but before initing engine itself
// override it to register plugins, tweak UI etc
- (void)preStartUnity;

// this one is called at first applicationDidBecomeActive
// NB: it will be started with delay 0, so it will run on next run loop iteration
// this is done to make sure that activity indicator animation starts before blocking loading
- (void)startUnity:(UIApplication*)application;

// this is a part of UIApplicationDelegate protocol starting with ios5
// setter will be generated empty
@property (retain, nonatomic) UIWindow* window;

@property (readonly, copy, nonatomic) UnityView*            unityView;
@property (readonly, copy, nonatomic) CADisplayLink*        unityDisplayLink;

@property (readonly, copy, nonatomic) UIView*               rootView;
@property (readonly, copy, nonatomic) UIViewController*     rootViewController;
@property (readonly, copy, nonatomic) DisplayConnection*    mainDisplay;

#if !UNITY_TVOS
@property (readonly, nonatomic) UIInterfaceOrientation      interfaceOrientation;
#endif

@property (nonatomic, retain) id                            renderDelegate;
@property (nonatomic, copy)                                 void(^quitHandler)();

@end

// Put this into mm file with your subclass implementation
// pass subclass name to define

#define IMPL_APP_CONTROLLER_SUBCLASS(ClassName) \
@interface ClassName(OverrideAppDelegate)       \
{                                               \
}                                               \
+(void)load;                                    \
@end                                            \
@implementation ClassName(OverrideAppDelegate)  \
+(void)load                                     \
{                                               \
    extern const char* AppControllerClassName;  \
    AppControllerClassName = #ClassName;        \
}                                               \
@end

#import "AppDelegate.h"

inline UnityAppController*  GetAppController()
{
    AppDelegate *delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
    return delegate.unityAppController;
}

#define APP_CONTROLLER_RENDER_PLUGIN_METHOD(method)                         \
do {                                                                        \
    id<RenderPluginDelegate> delegate = GetAppController().renderDelegate;  \
    if([delegate respondsToSelector:@selector(method)])                     \
        [delegate method];                                                  \
} while(0)

#define APP_CONTROLLER_RENDER_PLUGIN_METHOD_ARG(method, arg)                \
do {                                                                        \
    id<RenderPluginDelegate> delegate = GetAppController().renderDelegate;  \
    if([delegate respondsToSelector:@selector(method:)])                    \
        [delegate method:arg];                                              \
} while(0)



// these are simple wrappers about ios api, added for convenience
void AppController_SendNotification(NSString* name);
void AppController_SendNotificationWithArg(NSString* name, id arg);

void AppController_SendUnityViewControllerNotification(NSString* name);

主要参照了the-nerd的文章
https://the-nerd.be/2015/11/13/integrate-unity-5-in-a-native-ios-app-with-xcode-7/
视频参见:https://vimeo.com/145572230 (经常无法解析)
重新在b站传了一份,参见:https://www.bilibili.com/video/av13740194/

以上,是使用两个window交互显示的方式,可以用最基本的Unitydemo测试一下,OK在导入完整的Unity项目。
至于如何在某个页面的某个View上显示Unity,下一篇再说

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

推荐阅读更多精彩内容