Unity iOS 插件实践

Unity 和 Objective-C 交互

Unity 调用 iOS 原生方法

iOS 中,C 语言可以和 Objective-C 语言进行混合编译的,C# 语言又提供了一种调用 C(非 C++)语言的机制, 这样就可以实现 C# 调用 Objective-C 的功能

IL2CPP

What is IL2CPP?
The technology that we refer to as IL2CPP has two distinct parts.
1. An ahead-of-time (AOT) compiler
2. A runtime library to support the virtual machine
The AOT compiler translates Intermediate Language (IL), the low-level output from .NET compilers, to C++ source code. The runtime library provides services and abstractions like a garbage collector, platform-independent access to threads and files, and implementations of internal calls (native code which modifies managed data structures directly).

LayoutEngine.png

Unity脚本编译成中间语言(IL,动态库等),通过IL2CPP程序将 IL 转换成 C++语言

DllImport

C# 提供了 DllImport 机制来实现 C#C 语言的方法调用

  • 无参无返回值
1
2
[DllImport("__Internal")]
internal static extern void CallFunction();
  • 有参无返回值
1
2
[DllImport("__Internal")]
internal static extern void CallFunction(string param);
  • 有参有返回值
1
2
[DllImport("__Internal")]
internal static extern string CallFunction(string param);
DllImport 的语法规则
1
2
[DllImport("__Internal")]
internal static extern ReturnValue FunctionName(string parameter1, int parameter2);

由于是 C 语言,支持的参数及其数据类型是非常有限的,诸如 intfloatdoublechar 等这类两种语言中都存在的基础数据类型,是可以实现直接映射的,但是 C# 中的 string 对应到 C 中,就是 char*

iOS 实现 DllImport

.h 文件中

1
2
3
extern "C" {
char* CallFunction(char *parma);
}

.mm 文件中

1
2
3
char* CallFunction(char *parma) {
// return ...
}
iOS 调用 Unity 原生方法

这种方式用于 iOSUnity 一些方法回调

  • MonoPInvokeCallback

Attribute used to annotate functions that will be called back from the unmanaged world.

举个栗子🌰,比如我们现在需要使用手机相册权限拿一张图片在 Unity 中使用

C# 中:

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
// 声明 Unity 中接收回调的事件
private static UnityAction<string> _selectPhotoAction;
// 声明回调代理
private delegate void SelectPhotoCallback(string photo);

// 在一个初始化方法中设置回调
public void Init()
{
_SetSelectPhotoCallback(DidReceiveSelectPhotoCallback);
}

// 供 Unity 中调用选择照片的方法,并传入一个选择结果的回调
public void OnSelectPhoto(UnityAction<string> callback)
{
_selectPhotoAction = callback;
_SelectPhoto();
}

// iOS 原生的回调
[AOT.MonoPInvokeCallback(typeof(SelectPhotoCallback))]
private static void DidReceiveSelectPhotoCallback(string photo)
{
_selectPhotoAction?.Invoke(photo);
}

// 把 Unity 中定义的接收原生事件回调传给 OC
[DllImport("__Internal")]
private static extern void _SetupSelectPhotoCallback(SelectPhotoCallback callback);

// 调用 OC 原生方法
[DllImport("__Internal")]
private static extern void _SelectPhoto();

OC

.h 文件中:

1
2
3
4
5
6
7
8
9
@interface NativeUtils : NSObject

typedef void(*SelectPhotoCallback)(const char *photo);

extern "C"{
void _SetupSelectPhotoCallback(SelectPhotoCallback callback);
void _SelectPhoto();
}
@end

.mm 文件中:

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
45
46
#define Convert2Char( _x_ ) ( _x_ != NULL && [_x_ isKindOfClass:[NSString class]] ) ? strdup( [_x_ UTF8String] ) : strdup( [@"" UTF8String] )

@interface NativeUtils ()
@property (nonatomic, assign) SelectPhotoCallback selectPhotoCallback;
@end

@implementation WMNativeUtils

+ (instancetype)shared {
static dispatch_once_t onceToken;
static NativeUtils *instance = nil;
dispatch_once(&onceToken,^{
instance = [[self alloc] init];
});
return instance;
}

- (void)bindSelectPhotoCallback:(SelectPhotoCallback)callback {
self.selectPhotoCallback = callback;
}

- (void)selectPhoto {
// 调起系统相册,选择...
}

#pragma mark UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info {
[picker dismissViewControllerAnimated:YES completion:nil];
UIImage *image = info[UIImagePickerControllerEditedImage];
// base64 形式
NSString *imageBase64String = [imageData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
if (self.selectPhotoCallback) {
self.selectPhotoCallback(Convert2Char(imageBase64String));
}
}

#pragma mark - CPlusPlus
void _SetupSelectPhotoCallback(SelectPhotoCallback callback) {
[[NativeUtils shared] bindSelectPhotoCallback:callback];
}

void _SelectPhoto() {
[[NativeUtils shared] selectPhoto];
}

@end
top