本页介绍如何构建适用于 iOS 平台的原生代码插件。
要构建适用于 iOS 且包含原生插件的应用程序,请遵循以下步骤:
1.对于要调用的每个原生函数,在 C# 文件中定义一个 extern 方法,如下所示:
```csharp
[DllImport ("__Internal")]
private static extern float FooPluginFunction();
```
2.将原生代码源文件添加到 Unity 项目中。
3.在 Plugin Inspector 窗口中自定义插件的设置。例如,如果原生代码是特定于 iOS,请确保仅为 iOS 启用该插件。
注意:如果使用 C++ (.cpp) 或 Objective-C++ (.mm) 来实现该插件,则必须使用 C 链接来声明函数以免发生名称错用问题:
extern "C" {
float FooPluginFunction();
}
用 C 或 Objective-C 编写的插件不需要此声明,因为这些语言不存在名称错用。
仅当 iOS 原生插件部署在了实际设备上时,您的应用程序才能调用这些插件,因此应该使用额外的 C# 代码层来封装所有原生代码方法。此代码应使用 UNITY_IOS && !UNITY_EDITOR
条件编译,或者检查 Application.platform
,并仅当应用程序在设备上运行时才调用原生方法。最简单的实现方式是:
void MyMethod()
{
# if UNITY_IOS && !UNITY_EDITOR
CallNativeMethodImplementation();
# else
CallEditorMethodImplementation();
# endif
}
有关更详细的实现方法,请参阅下面的 Bonjour 浏览器示例 (Bonjour Browser Sample)。
Unity iOS 支持有限的原生到托管回调功能。有两种方式可以做到这一点:
* 使用 UnitySendMessage
* 通过委托
UnitySendMessage
此选项更简单,但有一些限制。如下所示:
UnitySendMessage("GameObjectName1", "MethodName1", "Message to send");
有三个参数:
* 目标 GameObject
的名称
* 用于调用该对象的脚本方法
* 用于传递给被调用方法的消息字符串
使用 UnitySendMessage
时具有以下限制:
1.通过原生代码,只能调用与以下签名对应的脚本方法:void MethodName(string message);
。
2.对 UnitySendMessage
的调用是异步的,并有一帧延迟。
3.如果两个或多个游戏对象具有相同的名称,则在使用 UnitySendMessage
时可能导致冲突。
这是更复杂的方案。当使用委托时,C# 端的方法必须是静态的,并且必须用 MonoPInvokeCallback
属性进行标记。必须将该方法作为委托传递给在原生代码中作为函数实现的 extern 方法,这个函数采用一个指针,而指针则指向具有对应签名的函数。然后,原生代码中的函数指针再引回 C# 静态方法。
该方法的 C# 代码如下所示:
delegate void MyFuncType();
[AOT.MonoPInvokeCallback(typeof(MyFuncType))]
static void MyFunction() { }
static extern void RegisterCallback(MyFuncType func);
然后,接受回调的 C 代码如下所示:
typedef void (*MyFuncType)();
void RegisterCallback(MyFuncType func) {}
Unity 支持自动插件集成,并且如果在 Plugin Inspector 窗口中为 iOS 启用了文件扩展名,则会将具有以下扩展名的所有文件复制到生成的 Xcode 项目中:.a
、.m
、.mm
、.c
、.cpp
和 .h
。如果具有这些扩展名的任何文件位于 Assets/Plugins/iOS
文件夹中,则 Unity 仅在 iOS 平台上启用这些扩展名。
注意:将文件复制到生成的 Xcode 项目后,它们不再链接到 Unity 项目中的对应文件。如果在 Xcode 中更改了这些文件,必须将它们复制回到您的 Unity 项目中。否则,在下次构建项目时,Unity 将覆盖它们。
1.在 iOS 上,托管到非托管的调用是很耗资源的处理器密集型操作。尽量避免每帧调用多个原生方法。
2.应使用额外的 C# 层来封装原生方法,该层将调用设备上的原生代码并在 Editor 中返回虚拟值。
3.从原生方法返回的字符串值应该是 UTF–8 编码并在堆上分配。Mono 编组调用对于这样的字符串是无成本的。
可在下面下载一个演示如何使用原生代码插件的简单示例:Bonjour 浏览器示例 (Bonjour Browser Sample)。
此示例演示了如何从 Unity iOS 应用程序调用 Objective-C 代码。该应用程序实现了一个简单的 Bonjour 客户端,并包含:
Plugins\Bonjour.cs
是原生代码的 C# 接口,BonjourTest.cs
是实现应用程序逻辑的脚本Assets/Plugins/iOS
中),如上文自动插件集成部分所述,应将此代码添加到构建的 Xcode 项目中