2022-03-30

iOS集成Unity

近年来iOS和Unity发展都非常迅速,而iOS和Unity都有各自擅长的领域,iOS在传统应用开发的中坚力量,而Unity在游戏行业发展强劲,尤其是三维领域。作为可视化项目,我们既需要传统项目的功能模块,又需要三维场景的渲染效果,所以我们今天要把这两个领域的强者融合在一起,在一个项目中发挥各自所长。iOS集成Unity在现实中应用较少,几乎没有完整流程的资料,且其中的坑数不胜数,所以把这些内容整理出来提供给大家。

下面详细介绍下打包流程。

1.打包Unity并导入

Unity中打包iOS包

首先在Unity编辑器打开UnityProject项目,选择Menu -> Window -> Package Manager,因为2.0.8版本不兼容使用Unity作为库,所以要移除Ads资源包,或更新Ads资源包到v 3.*版本。

选择Menu -> Edit -> Player Settings -> Player -> iOS设置标签页 -> Identification Section,设置有效的Bundle Identification和Signing Team ID,以避免后续步骤出现Xcode签名问题。

打开Menu -> File -> Builds Settings,在此选择并切换平台为iOS。将UnityProject项目构建到iosBuild文件夹。

一般Unity导出的iOS工程是可以直接运行的,但是我们既然要集成Unity,只是需要其中的三个文件,分别是Data、Classes、Libraries。

接下来就是修改导出包的文件。

1.文件:main.mm

复制替换:

`int main_unity_default(int argc, char* argv[])

{

  @autoreleasepool

  {

    UnityInitTrampoline();

//    UnityParseCommandLine(argc, argv); //Unity 5.3+

    UnityInitRuntime(argc, argv); //Unity 5.6+,5.4和5.5用哪个我没试过,可以根据报错情况选择。


    RegisterMonoModules();

    NSLog(@"-> registered mono modules %p\n", &constsection);

    RegisterFeatures();


    // iOS terminates open sockets when an application enters background mode.

    // The next write to any of such socket causes SIGPIPE signal being raised,

    // even if the request has been done from scripting side. This disables the

    // signal and allows Mono to throw a proper C# exception.

    std::signal(SIGPIPE, SIG_IGN);


    //UIApplicationMain(argc, argv, nil, [NSString stringWithUTF8String:AppControllerClassName]);

    //    UIApplicationMain(argc, argv, nil, NSStringFromClass([UnitySubAppDelegate class]));

    UIApplicationMain(argc, argv, nil, [NSString stringWithUTF8String:AppControllerClassName]);

  }


  return 0;

}`

2.文件:UnityAppController.h

导入文件:#import <UIKit/UIKit.h>

复制替换:

`NS_INLINE UnityAppController* GetAppController()

{

  NSObject<UIApplicationDelegate>* delegate = [UIApplication sharedApplication].delegate;

  UnityAppController* currentUnityController = (UnityAppController *)[delegate valueForKey:@"currentUnityController"];

  return currentUnityController;

}`

3.文件:SplashScreen.mm

复制替换:

`void ShowSplashScreen(UIWindow* window)

{

  _controller = [[SplashScreenController alloc] init];

  [_controller create: window];

}`

4.文件:DeviceSettings.mm

代码行数:268

复制替换:

return deviceUnknown;

5.文件:CrashReporter.mm

代码行数:81

复制替换://  InitCrashReporter();

导入

为了方便管理,我们可以在我们iOS工程主目录下创建一个文件夹,专门来存放Unity文件,方便管理和维护。比如我们起名为unity。Classes和Libraries以create groups的方式导入进来,而Data文件以Create folder references的形式导入进来。

2.集成环境

添加框架

由于Unity项目依赖了一些框架,我们需要将Unity所有依赖的框架都导入进来,否则Unity无法运行。

配置config文件

1.现在里面用了一些三方库,比如 objectMapper,JsonKit,所以要引用三方库。分两种,使用cocoapods集成,不适用cocoapods集成。

2.Unity.xcconfig文件,这个文件已经编辑好,但是不同机器的文件路径、不同的unity版本会有差异。注意这里我们的Unity使用的是2019版的。

`// Unity.xcconfig

// 对应Build Settings

//User-Defined

GCC_THUMB_SUPPORT = NO;

GCC_USE_INDIRECT_FUNCTION_CALLS = NO

UNITY_RUNTIME_VERSION = 2019.1.4f1

UNITY_SCRIPTING_BACKEND = il2cpp

UNITY_IOS_EXPORT_PATH = $(PROJECT_DIR)/unity_ios;//后面的Search Paths要用

//Apple Clang - Language

GCC_PREFIX_HEADER = $(PROJECT_DIR)/unity_ios/Classes/Prefix.pch

//Swift Compiler - General

SWIFT_OBJC_BRIDGING_HEADER = $(PROJECT_DIR)/RayData Mobile/RayDataEngine/objc/UnityBridge.h

//Build Options

ENABLE_BITCODE = NO

//Apple Clang - Custom Compiler Flags

OTHER_CFLAGS = $(inherited) -DINIT_SCRIPTING_BACKEND=1 -fno-strict-overflow -DNET_4_0 -DRUNTIME_IL2CPP=1 -DIL2CPP_MONO_DEBUGGER=1

//Linking

OTHER_LDFLAGS = -weak_framework CoreMotion -weak-lSystem -weak_framework GameKit -weak_framework iAd -framework CoreGraphics -framework AVFoundation -framework CoreVideo -framework CoreMedia -framework SystemConfiguration -framework CoreLocation -framework MediaPlayer -framework CFNetwork -framework AudioToolbox -framework OpenAL -framework QuartzCore -framework OpenGLES -framework UIKit -framework Foundation -liconv.2 -liPhone-lib

//Search Paths

HEADER_SEARCH_PATHS = $(inherited) $(UNITY_IOS_EXPORT_PATH) $(UNITY_IOS_EXPORT_PATH)/Classes $(UNITY_IOS_EXPORT_PATH)/Classes/Native $(UNITY_IOS_EXPORT_PATH)/Classes/UI $(UNITY_IOS_EXPORT_PATH)/Libraries $(UNITY_IOS_EXPORT_PATH)/Libraries/libil2cpp/include $(UNITY_IOS_EXPORT_PATH)/Libraries/bdwgc/include;

LIBRARY_SEARCH_PATHS = $(inherited) $(UNITY_IOS_EXPORT_PATH) $(UNITY_IOS_EXPORT_PATH)/Libraries $(UNITY_IOS_EXPORT_PATH)/Libraries/libil2cpp/include;

// c 目测没有替换配置里的内容

CLANG_CXX_LANGUAGE_STANDARD = compiler-default;

CLANG_CXX_LIBRARY = libc++;

CLANG_WARN_BOOL_CONVERSION = NO;

CLANG_WARN_CONSTANT_CONVERSION = NO;

CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES;

CLANG_WARN_EMPTY_BODY = NO;

CLANG_WARN_ENUM_CONVERSION = NO;

CLANG_WARN_INT_CONVERSION = NO;

CLANG_WARN_OBJC_ROOT_CLASS = YES;

CLANG_WARN_UNREACHABLE_CODE = NO;

CLANG_WARN__DUPLICATE_METHOD_MATCH = NO;

GCC_C_LANGUAGE_STANDARD = c11;

GCC_ENABLE_OBJC_EXCEPTIONS = NO;

GCC_PRECOMPILE_PREFIX_HEADER = YES;

GCC_THUMB_SUPPORT = NO;

GCC_USE_INDIRECT_FUNCTION_CALLS = NO;

GCC_WARN_64_TO_32_BIT_CONVERSION = NO;

GCC_WARN_64_TO_32_BIT_CONVERSION[arch=*64] = YES;

GCC_WARN_ABOUT_RETURN_TYPE = YES;

GCC_WARN_UNDECLARED_SELECTOR = NO;

GCC_WARN_UNINITIALIZED_AUTOS = NO;

GCC_WARN_UNUSED_FUNCTION = NO;

GCC_NO_COMMON_BLOCKS = NO;

CLANG_ENABLE_MODULES = NO;

CLANG_WARN_DOCUMENTATION_COMMENTS = NO;

CLANG_WARN_EMPTY_BODY = NO;

CLANG_WARN_INFINITE_RECURSION = NO;

GCC_WARN_ABOUT_RETURN_TYPE = YES;

GCC_WARN_UNINITIALIZED_AUTOS = NO;

CLANG_WARN_UNREACHABLE_CODE = NO;

GCC_WARN_UNUSED_FUNCTION = NO;

CLANG_WARN__DUPLICATE_METHOD_MATCH = NO;`

Apple Clang - Language - C++

Apple Clang - Custom Compiler Flags  `

3.UnityBridge.h UnityUtils.h UnityUtils.mm文件已经提前配置好。也在包中

unity下的unity_ios文件加下Data文件夹应该是引用类型文件,蓝色文件夹,其他的都是黄色文件夹

4.配置xcconfig

如果集成了cocoapods

如果没有集成cocoapods

配置Build Settings

添加main.swift文件

import UIKit

custom_unity_init(CommandLine.argc, CommandLine.unsafeArgv)

UIApplicationMain(

  CommandLine.argc,

  UnsafeMutableRawPointer(CommandLine.unsafeArgv)

   .bindMemory(

     to: UnsafeMutablePointer<Int8>.**self**,

     capacity: Int(CommandLine.argc)),

  nil,

  NSStringFromClass(AppDelegate.**self**)

修改AppDelegate.swift文件并做修改。

注释这个代码

//@UIApplicationMain

添加属性

@objc var currentUnityController: UnityAppController!

在 didFinishLaunchingWithOptions 方法中添加以下代码

window = UIWindow.init(frame: UIScreen.main.bounds)

currentUnityController = UnityAppController()

currentUnityController.application(application, didFinishLaunchingWithOptions: launchOptions)

let vc = UIViewController.init()

window?.rootViewController = vc

window?.backgroundColor = UIColor.white

window?.makeKeyAndVisible()

在声明周期代理方法中添加以下方法

func applicationWillResignActive(**_** application: UIApplication) {

currentUnityController.applicationWillResignActive(application)

}

func applicationDidEnterBackground(**_** application: UIApplication) {

    currentUnityController.applicationDidEnterBackground(application)

}

func applicationWillEnterForeground(**_** application: UIApplication) {

   currentUnityController.applicationWillEnterForeground(application)

}

func applicationDidBecomeActive(**_** application: UIApplication) {

  currentUnityController.applicationDidBecomeActive(application)

}

func applicationWillTerminate(**_** application: UIApplication) {

   currentUnityController.applicationWillTerminate(application)

}

设置桥接文件路径

设置 Apple Clang - Language

设置Build Phases,搜索 dynamic后,删除。

配置桥接文件

因为我们用的是Swift语言,而Unity编译成iOS包中大部分是C语言。中间需要Objective-C语言作为中间转换。如果iOS调用Unity顺序为Swift->Objective-C->C;如果Unity调用iOS顺序为C->Objective-C->Swift。

这里需要一个Swift和Objective-C的桥接文件UnityBridge。

#define "useUnityInxxx"

#ifndef UnityBridge_h

#define UnityBridge_h

#if useUnityInRaydata

#import "UnityUtils.h"

#import "UnityAppController.h"

#import "UnityInterface.h"

#endif

#import "UnityTransform.h"

#endif /* UnityBridge_h */

3.iOS原生与Unity的交互与传值

创建Objective-C文件UnityTransform,用来做Objective和Unity中C语言的交互。

声明文件

#import <Foundation/Foundation.h>

#import <UIKit/UIKit.h>

@interface UnityTransform : NSObject

@property(nonatomic,copy)NSString *objectName;

@property(nonatomic,copy)NSString *funcName;

@property(nonatomic,copy)NSString *json;

//快速赋值方法

- (**void**)setup:(NSString *)objectName andFname:(NSString *)fName andJsonStr:(NSString *)jsonStr;

//ios to unity

- (**void**)sendMessageToUnity;

#if defined(__cplusplus)

extern"C"

{

#endif

  extern void UnitySendMessage(const char ,const char , const char );  

#if defined(__cplusplus)

}

#endif

实现文件

`@implementation UnityTransform

static UnityTransform *transform=nil;

- (void)setup:(NSString *)objectName andFname:(NSString *)fName andJsonStr:(NSString *)jsonStr{

  self.objectName = objectName;

  self.funcName = fName;

  self.json = jsonStr;

}

- (void)sendMessageToUnity{

  const char *jsonStr = (char *)[self.json UTF8String];

  const char *objectName = [self.objectName UTF8String];

  const char *funcName = [self.funcName UTF8String];

  UnitySendMessage(objectName, funcName, jsonStr);

}

//单例

+ (UnityTransform *) instance{

  if (transform==nil)

  {

    transform=[[UnityTransform alloc]init];

    transform.objectName = @"";

    transform.funcName = @"";

  }

  return transform;

}`

创建一个Swift单利管理类,用来调用Unity方法及实现回调,UnityManager,这里举一个加载模型的例子

iOS调用unity函数

`

let transformTool = UnityTransform()

func loadModelIOS2Unity() {

    transformTool.setup("APIManager", andFname: "loadModel", andJsonStr: model)

    transformTool.sendMessageToUnity()

  }

`

Unity调用iOS方法

UnityTransform文件中声明一个方法,

void _modelLoadSucess(void);

并实现

void _modelLoadSucess(void){

Unity.loadModelSucess_initDone();

}

UnityManager管理类中写被调用的方法,传递给使用的类。

`var loadModelSuccessCallBack: NullBlock? //完成了模型加载回调

@objc func loadModelSucess_initDone() {

Unity.loadModelSuccessCallBack()

}

`

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

推荐阅读更多精彩内容