Unity —如何搭建桥梁:iOS到Swift的Unity
通过添加ARKit和iOS 11中的Core ML,能够将iOS功能桥接到Unity中,使您作为开发人员能够获得更强大和独特的产品体验。 在ustwo建立实验时,我们必须创建一个自定义屏幕录制功能,该功能涉及尚未桥接到Unity中的iOS功能。
结果是使用iOS的ReplayKit API记录游戏玩法,保存记录并将文件传递回Unity的桥梁。
源代码在这里:ReplayKitUnityBridge
在DemoUnityAndReplayKit文件夹中运行DemoScene
- 将Xcode的“构建设置”中的Swift版本设置为4.0,以便正确构建*
步骤1:如何从Unity向iOS发送消息
首先打开Xcode> New Project> Cocoa Touch Framework
将该项目命名为“ ReplayKitUnityBridge”
在左上角显示“ ReplayKitUnityBridge”。 右键单击->单击“新建组”
右键单击您的源文件夹,然后单击“新建文件”> Swift文件
将您的新文件命名为“ ReplayKitNative ”
将以下内容添加到您的ReplayKitNative.swift文件中
进口基金会
导入UIKit
导入ReplayKit
@objc公共类ReplayKitNative:NSObject {
@objc静态让共享= ReplayKitNative()
私人let screenRecorder = RPScreenRecorder.shared()
让kCallbackTarget =“ ReplayKitUnity”
@objc func startScreenCapture(){
self.screenRecorder.startRecording {(错误)在
// UnitySendMessage(kCallbackTarget,“ OnStartRecording”,“”)
}
}
让我们回顾一下上面的代码:
- 使用@objc标志来标记要公开给Objective-C和Unity的内容
@objc公共类ReplayKitNative:NSObject
@objc静态让共享= ReplayKitNative()
为了让Unity的C#脚本调用Swift代码,我们必须使用@objc标志标记任何需要公开的内容。 Xcode将在后台编译一个由Objective-C生成的Header文件,我们可以在调用Swift函数的C ++包装器中使用该文件。
*请注意,在Xcode 9+中,您必须使用@objc标志明确标记所有函数和属性**
您可以在“派生数据”文件夹中查看swift文件的已编译Objective-C标头→在“派生数据”中的Objective-C标头→找到“派生源”文件夹。 您将看到一个文件“ ReplayKitUnityBridge-Swift.h ”文件。 此文件具有@objc公开的函数和属性的Objective-C界面。
2.声明一个回调目标,该目标与Unity中将存在的C#类的名称完全相同,并负责与本机iOS代码进行通信。
让kCallbackTarget =“ ReplayKitUnity”
3.使用UnitySendMessage函数将消息传递到Unity
// UnitySendMessage(kCallbackTarget,“ OnStartRecording”,“”)
将文件带入Unity时,请取消注释。
您的Swift文件很好用。
第2步:添加一个新的Objective-C ++文件(.mm),并将其命名为“ ReplayKitBridge”
- 右键单击“源”文件夹
- 点击“新文件”
- 选择底部的“空”并将文件命名为“ ReplayKitBridge”
4.现在,在左侧的项目树中,双击ReplayKitBridge文件,将其重命名:
ReplayKitBridge.mm
将以下代码添加到新的Objective-C ++文件中
#import
#include“ ReplayKitUnityBridge-Swift.h”
#pragma mark-C接口
extern“ C” {
void _rp_startRecording(){
[[ReplayKitNative共享] startScreenCapture];
}
}
#include“ ReplayKitUnityBridge-Swift.h”
- 该行允许您调用Swift文件中标记的所有公开函数和属性。 这是非常重要的。
这个文件是用C写的; 但是,通过将其标记为.mm文件,Xcode会将其编译为Objective C ++文件,从而允许Unity直接与其通信。 它负责侦听请求并将其转发到Swift文件。
现在,您有了一个Objective-C ++文件,该文件公开了在swift文件中创建的函数和属性。
步骤3:建立桥接标题
右键单击源文件夹>新建文件>头文件>将其命名为“ ReplayKitUnityBridge-Bridging-Header”
Xcode要求桥接头始终设置为跟随者格式:[PROJECTNAME-Bridging-Header]
添加以下内容:
# 导入
# 导入
//# 导入 “ UnityInterface.h”
在您的Xcode的当前状态下,该项目将不会生成。 这是因为缺少Unity文件。 注释掉这些行,直到我们将文件导入到Unity项目中。 必须有一种更有效的方法,但是出于本教程的目的,我们将使其尽可能简单。
步骤4:现在打开Unity并创建一个新项目
- 创建一个文件夹>“插件”>“ iOS”
- 创建一个文件夹“ ReplayKitUnityBridge”
- 在那个文件夹里
- 创建一个名为“ Editor”的子文件夹
- 创建另一个名为“ Source”的子文件夹
- 在“源”文件夹中,将“ ReplayKitNative.Swift”,“ ReplayKitBridge.mm”,“ ReplayKitUnityBridge-Bridging-Header.h”文件拖到Unity中
4.在Source文件夹中,创建一个新的C#脚本,并将其命名为“ ReplayKitUnity ”
*这与您在ReplayKitNative.Swift类中设置的kCallbackTarget名称相同*
使用UnityEngine;
使用System.Runtime.InteropServices;
公共类ReplayKitUnity:MonoBehaviour {
#region声明外部C接口
#if UNITY_IOS &&!UNITY_EDITOR
[DllImport(“ __ Internal”)]
私有静态外部无效_rp_startRecording();
#万一
#endregion
#region包装的方法和属性
公共静态无效StartRecording(){
#if UNITY_IOS &&!UNITY_EDITOR
_rp_startRecording();
#万一
}
让我们分解一下C#脚本
- 使用 System.Runtime.InteropServices;
这允许Unity调用其他语言的函数
要了解有关interopservices的更多信息,请访问此站点。
[ DllImport(“ __ Internal”) ] 私有 静态 外部 无效 _rp_startRecording();
[DllImport(“ __ Internal”)]告诉编译器转发或互操作此函数。 您需要在此声明您希望C#脚本使用的所有函数和属性。
公共静态无效StartRecording(){
#if UNITY_IOS &&!UNITY_EDITOR
_rp_startRecording();
#万一
}
这是Unity项目中所有其他脚本和游戏对象都可以调用的公共方法。 它将方法签名转发到您在其上方声明的DllImport变量,然后将其转发到C ++文件。
好的,您现在可以将消息从Unity发送到本机iOS。 呜呜呜!
步骤5:将消息从iOS发送到Unity
我们将在这里使用委托,并从iOS调用消息到Unity。
在您的ReplayKitUnity.cs脚本中添加以下内容:
#region Singleton实现
私有静态ReplayKitUnity _instance;
公共静态ReplayKitUnity实例{
得到{
如果(_instance == null){
var obj = new GameObject(“ ReplayKitUnity”);
_instance = obj.AddComponent ();
}
返回_instance;
}
}
无效Awake(){
如果(_instance!= null){
销毁(gameObject);
返回;
}
DontDestroyOnLoad(gameObject);
}
#endregion
#region代表
public System.Action onStartScreenCapture;
public System.Action onStopScreenCaptureWithFile;
公共无效OnStartRecording(){
如果(onStartScreenCapture!= null){
onStartScreenCapture.Invoke();
}
}
我们声明ReplayKitUnity脚本的单例实例。 这允许创建对象实例,并允许iOS将消息发送到Unity项目中的活动对象。
这里要注意的最重要部分是OnStartRecording()的公共声明
如果我们回顾一下ReplayKitNative.swift文件,您将看到以下行:
self.screenRecorder.startRecording {(错误)在
UnitySendMessage(kCallbackTarget,“ OnStartRecording”,“”)
}
这将触发一条消息发送到Unity。
在Unity项目中,您可以通过订阅委托→public System.Action onStartScreenCapture;来观察回调。
就是这样!
步骤6:将属性从iOS传递到Unity
如果要将属性从iOS传递回Unity,则需要从iOS发送带有属性的消息:
在ReplayKitNative.Swift中,添加要传递给Unity的字符串。
UnitySendMessage(kCallbackTarget,“ OnStopRecording”,file.absoluteString)
在ReplayKitUnity.cs中
public System.Action onStopScreenCaptureWithFile;
公共无效OnStopRecording(字符串文件){
如果(onStopScreenCaptureWithFile!= null){
onStopScreenCaptureWithFile.Invoke(file);
}
}
步骤7:最后一步–后期处理构建清理
我们需要告诉Unity建立一个Xcode项目,该项目引用上面创建的ReplayKutUnityBridge-Swift.h文件和bridged-header文件。 这使您编写的带有@objc标志的Swift代码可以公开公开
在Unity中
- 转到插件> iOS> ReplayKitBridge>编辑器文件夹
- 创建一个C#脚本并将其命名为“ SwiftPostProcessor”
使用UnityEngine ;
使用UnityEditor ;
使用UnityEditor 。 回调 ;
使用UnityEditor .iOS。 Xcode ;
使用系统 。 收藏 ;
使用系统 。 集合 。 通用 ;
使用系统 。 诊断 ;
使用系统 。 IO ;
使用系统 。 临q ;
公共 静态 类 SwiftPostProcessor {
[ PostProcessBuild ]
公共 静态无效OnPostProcessBuild ( BuildTarget buildTarget,字符串buildPath){
如果 (buildTarget == BuildTarget .iOS){
//我们需要构建自己的PBX项目路径,该路径正确地引用Bridging标头
// var projPath = PBXProject.GetPBXProjectPath(buildPath);
var projPath = buildPath +“ /Unity-iPhone.xcodeproj/project.pbxproj”;
var proj = new PBXProject ();
项目 ReadFromFile (projPath);
var targetGuid = proj。 TargetGuidByName ( PBXProject。GetUnityTargetName ());
////配置构建设置
项目 SetBuildProperty (targetGuid,“ ENABLE_BITCODE”,“否”);
项目 SetBuildProperty (targetGuid,“ SWIFT_OBJC_BRIDGING_HEADER”,“库/插件/ iOS / ReplayKitBridge /源/ReplayKitUnityBridge-Bridging-Header.h”);
项目 SetBuildProperty (targetGuid,“ SWIFT_OBJC_INTERFACE_HEADER_NAME”,“ ReplayKitUnityBridge-Swift.h”);
项目 AddBuildProperty (targetGuid,“ LD_RUNPATH_SEARCH_PATHS”,“ @ executable_path / Frameworks”);
项目 WriteToFile (projPath);
}
}
}
结论
这个过程既棘手又复杂。 有很大的自动化空间,可以创建易于创建的工具。 虽然这可能是一个临时解决方案,但我希望它可以帮助您找到将本机iOS代码带入Unity体验的方法!