0%

iOS与Unity的交互

前言

今天听说了一个很有意思的需求,把Unity游戏打成一个包,嵌入到原生APP中
正好两种技术栈我都有过相关经验,所以手痒实现一下!

版本
Unity 2019.2.0f1
Xcode9.3.1

Show Me The Code

创建一个Unity工程
拖入一个Cube和Text控件

然后BuildSetting中切换到iOS

注意如果需要用模拟器调试 需要在Player Settings中把Other Settings中的Target SDK切换为Simulator SDK

Unity2019.2.0f中勾选Auto Graphics API并不会添加依赖
e777aca23b92c1b49d29c3a5b6d0a262

需要手动取消Auto Graphics API并在Graphics APIs中添加OpenGLES3
f819fcc8e0d848700bbc018346f48ef7

然后点击Build

f91efed2b8f55c422b56b03f3602f87c

iOS唤起Unity

Unity默认在iOS AppDelegate中的applicationDidBecomeActive调用一个startUnity:方法
如果要自定义唤起时间,则需要改变这个方法的调用时机

UnityAppController修改并添加以下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

- (void)applicationDidBecomeActive:(UIApplication*)application
{
::printf("-> applicationDidBecomeActive()\n");

[self removeSnapshotView];

if (_unityAppReady)
{
if (UnityIsPaused() && _wasPausedExternal == false)
{
UnityWillResume();
UnityPause(0);
}
if (_wasPausedExternal)
{
if (UnityIsFullScreenPlaying())
TryResumeFullScreenVideo();
}
UnitySetPlayerFocus(1);
}
else if (!_startUnityScheduled)
{
_startUnityScheduled = true;
// 替换startUnity:为startSelfIOSView
[self performSelector: @selector(startSelfIOSView) withObject: application afterDelay: 0];
}

_didResignActive = false;
}
// 创建原生页面和控件,自己控制唤起Unity时机
- (void)startSelfIOSView
{
UIViewController *vc = [[UIViewController alloc] init];
vc.view.frame = [UIScreen mainScreen].bounds;
vc.view.backgroundColor = [UIColor whiteColor];
UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake(100, 100, 200, 50)];
btn.backgroundColor = [UIColor blueColor];
[btn setTitle:@"跳转到Unity界面" forState:UIControlStateNormal];
// 按钮被点击时唤起Unity项目
[btn addTarget:self action:@selector(startUnity:) forControlEvents:UIControlEventTouchUpInside];
[vc.view addSubview:btn];
[_window addSubview:vc.view];
}

然后就可以通过我们的定义的时机唤起Unity了
f01bd0aa7ef7071ccb876c6e63061187

Unity唤起iOS

因为Unity界面跳转到IOS界面涉及到了暂停Unity所以我们需要实现一个单例来判断Unity的暂停或启动

LARManager.h

1
2
3
4
5
6
7
#import <Foundation/Foundation.h>

@interface LARManager : NSObject
/** 是否暂停Unity */
@property (assign, nonatomic) BOOL unityIsPaused;
+ (instancetype)sharedInstance;
@end

LARManager.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#import "LARManager.h"

@implementation LARManager

+ (instancetype)sharedInstance
{
static LARManager *manager;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[self alloc] init];
});
return manager;
}

- (instancetype)init
{
if (self = [super init]) {
self.unityIsPaused = NO;
NSLog(@"单例初始化成功");
}
return self;
}
@end

然后在iOS中声明被Unity调用的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
extern "C"
{
// 对Unity中的unityToIOS方法进行实现
void unityToIOS(char* str){
// Unity传递过来的参数
NSLog(@"%s",str);
UnityPause(true);
// 跳转到IOS界面,Unity界面暂停
[LARManager sharedInstance].unityIsPaused = YES;
// GetAppController()获取appController,相当于self
// UnityGetGLView()获取UnityView,相当于_window
// 点击按钮后跳转到IOS界面,设置界面为IOS界面
GetAppController().window.rootViewController = GetAppController().vc;
}
}

在Unity中调用

1
2
3
4
5
6
7
8
[DllImport("__Internal")]
private static extern void unityToIOS (string str);

// 按钮点击后切换到iOS界面发送一个字符串
public void ButtonClick()
{
unityToIOS("Hello iOS");
}

实现效果:
d728085a9a2a591edd57e8d1379dd101

Unity向iOS传值

第一种方法

在上个例子中已经展示了Unity向iOS传值的方法
在iOS中在extern "C"中声明方法,然后在Unity中添加方法属性并添加标签[DllImport("__Internal")]
然后就可以直接调用了

第二种方法

在Unity项目中添加Test.h Test.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Test.h
extern "C"
{
extern void outputAppendString (char *str1, char *str2);
}

Test.m
#import <Foundation/Foundation.h>

void outputAppendString (char *str1, char *str2)
{
NSString *string1 = [[NSString alloc] initWithUTF8String:str1];
NSString *string2 = [[NSString alloc] initWithUTF8String:str2];

NSLog(@"###%@", [NSString stringWithFormat:@"%@ %@", string1, string2]);
}

然后两个文件Include Platforms设置为iOS

ffd2bd502a9c319fdfc582d422327b2d

然后添加一个按钮绑定事件

1
2
3
4
5
6
7
8
9
// 导入OC文件
[DllImport("__Internal")]
static extern void outputAppendString (string str1, string str2);
public void ButtonClickCalliOS()
{
#if UNITY_IPHONE
outputAppendString("Hello", "World");
#endif
}

实现效果:

593baeaa982ff03e9fd8168517c085f8

iOS向Unity传值

iOS向Unity传值主要通过void UnitySendMessage(const char* obj, const char* method, const char* msg);这个方法
这个方法可以传入三个参数:

  • 参数一为unity脚本挂载的gameobject
  • 参数二为unity脚本中要调用的方法名
  • 参数三为传递的数据,*注意:传递的数据只能是char 类型
    974200c7700fc209041003b64aa631e6

总结

总之就是删除Unity默认的启动时机

然后再通过自定义的时机跳转到Unity界面 或着跳回到原生界面

甚至可以用iOS的原生控件去操作Unity的对象

这样 iOS部分的开发 和 Unity部分的开发就可以同时进行了

其它

项目地址:
https://github.com/Lafree317/iOS-Unity-Bridge

参考文章:
iOS与Unity3d交互-Larrycal:
https://www.jianshu.com/p/4c49655aff8b
iOS 与 unity3D 交互整合的那些事:
https://juejin.im/entry/58abd6df2f301e006c3be2f4


随缘更新RN/Week或其它移动端框架和Unity的交互