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”,“”) 
}
}

让我们回顾一下上面的代码:

  1. 使用@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”

  1. 右键单击“源”文件夹
  2. 点击“新文件”
  3. 选择底部的“空”并将文件命名为“ 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并创建一个新项目

  1. 创建一个文件夹>“插件”>“ iOS”
  2. 创建一个文件夹“ ReplayKitUnityBridge”
  3. 在那个文件夹里
  4. 创建一个名为“ Editor”的子文件夹
  5. 创建另一个名为“ Source”的子文件夹
  6. 在“源”文件夹中,将“ 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#脚本

  1. 使用 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中

  1. 转到插件> iOS> ReplayKitBridge>编辑器文件夹
  2. 创建一个C#脚本并将其命名为“ SwiftPostProcessor”
 使用UnityEngine ; 
使用UnityEditor ;
使用UnityEditor回调 ;
使用UnityEditor .iOS。 Xcode ;
使用系统收藏 ;
使用系统集合通用 ;
使用系统诊断 ;
 使用系统IO ; 
使用系统临q ;

公共 静态 SwiftPostProcessor {
[ PostProcessBuild ]
公共 静态无效OnPostProcessBuildBuildTarget 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。 TargetGuidByNamePBXProject。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体验的方法!