如何创建一个跨平台的移动iOS和Android统一插件

Unity is a great platform for developing VR and AR applications. When developing a cross-platform application there are often native mobile plugins that need to be leveraged or developed.

Unity是用于开发VR和AR应用程序的绝佳平台。 在开发跨平台应用程序时,通常需要利用或开发本机移动插件。

Unity’s documentation around this is limited. This article will serve as an entry point to your native cross-platform mobile plugin’s development.

关于此的Unity文档是有限的。 本文将作为您本机跨平台移动插件开发的切入点。

This tutorial uses a new project from Unity Version 2018.4.19f1, but will also work with newer versions.

本教程使用Unity版本2018.4.19f1中的新项目,但也将使用较新版本。

插件布局示例 (Example Plugin Layout)

This plugin will demonstrate three important concepts:

该插件将演示三个重要概念:

  1. Sync call to native

    将通话同步到本地
  2. Async call to native

    异步调用本地
  3. Call from native to Unity

    从本地通话到Unity

To do this, we will be passing a rectangle’s height and width both sync and async to native. Native will calculate the rectangle’s diagonal, perimeter, and area passing these values back to Unity.

为此,我们将同步和异步传递矩形的高度和宽度到本机。 Native将计算矩形的对角线,周长和面积,并将这些值传回Unity。

所需的Unity构建支持模块 (Required Unity Build Support Modules)

Open your Unity Hub → Click Installs → Click the Three Dots → Add Modules.

打开您的Unity Hub→单击安装→单击三个点→添加模块。

Image for post
Adding Modules to your Unity Installation
将模块添加到Unity安装中

Make sure Android Build Support and iOS Build Support are checked. Click Done to add if not already added the build supports.

确保已选中“ Android构建支持”和“ iOS构建支持”。 如果尚未添加构建支持,请单击Done以添加。

Image for post
Adding Android and iOS Build Support to Unity
将Android和iOS构建支持添加到Unity

Android所需的工具 (Required Tools for Android)

Download and Install Android Studio. It is not required for Unity, but it will make building the plugin a whole lot easier.

下载并安装Android Studio 。 Unity不需要它,但是它将使构建插件变得更加容易。

However, Unity requires Command line tools so at the bottom of the download page make sure you download Command line tools only for your proper platform. Extract the zip and place the tools folder inside of the sdk folder created by Android Studio.

但是,Unity需要Command line tools因此在下载页面的底部,请确保Command line tools only针对适当的平台下载Command line tools only 。 解压缩zip并将tools文件夹放置在Android Studio创建的sdk文件夹内。

Make sure the Android SDK is set in Unity by going to File → Preferences → External Tools → Android SDK.

通过转到文件→首选项→外部工具→Android SDK,确保在Unity中设置了Android SDK。

Image for post
External Tools Preferences
外部工具首选项

Question: How do I fix this error?

问题 :如何解决此错误?

Image for post
Invalid Android SDK directory error
无效的Android SDK目录错误

Solution: Make sure the tools folder is inside the selected Android SDK directory and is spelled properly. The command line tools folder name was changed to build-tools in newer versions of Android Studio and Unity does not recognize this new folder name.

解决方案 :确保tools文件夹位于所选的Android SDK目录中,并且拼写正确。 在较新版本的Android Studio中,命令行工具文件夹名称已更改为build-tools ,而Unity无法识别此新文件夹名称。

iOS所需的工具 (Required Tools for iOS)

  1. Mac OS

    苹果系统
  2. XCode

    XCode

  3. If your plugin package requires capabilities not able to run on a simulator, you will need to have an Apple developer account to run on an iOS device.

    如果您的插件程序包需要无法在模拟器上运行的功能,则需要具有Apple开发人员帐户才能在iOS设备上运行。

资料夹结构 (Folder Structure)

Create a folder inside Assets called Plugins . Inside Plugins create two folders: Android and iOS .

Assets内部创建一个名为Plugins的文件夹。 在Plugins内部创建两个文件夹: AndroidiOS

Image for post
How to Create a Folder in Assets
如何在资产中创建文件夹
Image for post
The directory structure recognized by Unity for native plugins
Unity识别本机插件的目录结构

Files that are added in the Android and iOS folders will automatically be attached to the build.

AndroidiOS文件夹中添加的文件将自动附加到该版本。

桥接脚本 (Bridging Script)

Right click the Plugins folder or inside of the Plugins folder right click the empty space and create a C# script named PluginBridge. This script will be called from external scripts to send and receive data from native scripts.

右键单击Plugins文件夹或内部Plugins文件夹右键单击空白处,创建一个名为C#脚本PluginBridge 。 该脚本将从外部脚本中调用以从本机脚本发送和接收数据。

Image for post
How to Create a C# Script
如何创建C#脚本

NOTE: There must be at least one game object attached to a script to initialize this plugin. This is usually taken care of by the calling script, which we will add an example the next section.

注意:必须至少有一个附加到脚本的游戏对象才能初始化此插件。 通常由调用脚本来解决,我们将在下一部分添加示例。

First we will set up the plugin bridge class:

首先,我们将设置插件桥类:

Setting up the static class to bridge native code
设置静态类以桥接本机代码

Quick notes:

快速说明:

  1. We are using a static class to allow for easy to use calls from Unity.

    我们正在使用静态类,以允许来自Unity的易于使用的调用。
  2. Make sure you take note of the Java object name as it will be used in creating the plugin.

    确保记下Java对象名称,因为它将在创建插件时使用。
  3. iOS requires the native methods used to be explicitly defined. The #if and #endif are required around the DllImport so Android will not throw an error and can use the same class.

    iOS需要用于显式定义的本机方法。 DllImport周围需要#if#endif ,因此Android不会抛出错误,并且可以使用相同的类。

  4. PlatformNotSupportedException is just used for easy debugging when implementing the plugin.

    PlatformNotSupportedException仅在实现插件时用于轻松调试。

Second, we will add the game object to receive messages from native as well as initiate the Java class:

其次,我们将添加游戏对象以接收来自本机的消息并启动Java类:

Setting up game object in static constructor
在静态构造函数中设置游戏对象

Quick notes:

快速说明:

  1. The game object is added for calls from native to Unity can be received. Creating a new game object just for this plugin makes it easy to not have to create an external game object when adding the plugin.

    添加了游戏对象,可以接收从本地到Unity的调用。 仅为此插件创建一个新的游戏对象就可以轻松地在添加插件时不必创建外部游戏对象。
  2. Android needs to instantiate the object. Every argument after the second argument in new AndroidJavaObject() gets passed to the Java object constructor.

    Android需要实例化该对象。 new AndroidJavaObject()第二个参数之后的每个参数都传递给Java对象构造函数。

  3. HandleException callback is used internally by native code to notify Unity of any exceptions.

    HandleException回调由本机代码在内部使用,以将任何异常通知Unity。
  4. The callback handlers can only receive strings as native can only send back strings through its messaging protocol. We will be sending json and then deserializing it into our CalculationResults object.

    回调处理程序只能接收字符串,因为本机只能通过其消息传递协议发送回字符串。 我们将发送json,然后将其反序列化为CalculationResults对象。

Finally, we will add the interface methods:

最后,我们将添加接口方法:

Quick notes:

快速说明:

  1. We are saving the callback locally to be called once we received a message from Native. This works well when there is only one callback set at a time. If multiple callbacks are needed they should be handled externally through the single passed callback.

    收到来自Native的消息后,我们会将回调保存在本地以供调用。 一次仅设置一个回调时,此方法效果很好。 如果需要多个回调,则应通过单个传递的回调在外部进行处理。

调用示例脚本 (Calling Example Script)

Create a new folder under Assets called Scripts . Inside scripts create the script: CallingExample.

Assets下创建一个名为Scripts的新文件夹。 内部脚本创建脚本: CallingExample

Example calling script for our plugin’s methods
插件方法的示例调用脚本

Now we will create a game object in the scene to attach to the CallingExample script.

现在,我们将在场景中创建一个游戏对象以附加到CallingExample脚本。

Right click inside the SampleScene and click Create Empty.

SampleScene内右键单击,然后单击创建空

Image for post
How to Create a new Game Object
如何创建一个新的游戏对象

Right click, rename GameObject to Calling Example. When left clicking it check out the Inspector tab on the right side. Click Add Component and type in CallingExample in the search box. Select the script to add it.

右键单击,将GameObject重命名为Calling Example 。 左键单击时,检出右侧的“ 检查器”选项卡。 单击添加组件CallingExample在搜索框中键入CallingExample 。 选择脚本以添加它。

Image for post
How to Attach a Script to a Game Object
如何将脚本附加到游戏对象

安卓系统 (Android)

Create a new Android Project.

创建一个新的Android项目。

Image for post
Android Project Template for Android Plugin
适用于Android插件的Android项目模板

Select Empty Activity .

选择Empty Activity

Image for post
Android Project Configuration for Android Plugin
适用于Android插件的Android项目配置

Fill in the configuration details. Make sure you take note of the Save location as it will be used later. Also make sure the save location does not have a space in it as it may cause problems with the NDK tools. NDK tools may be needed when compiling low level externally connected devices.

填写配置详细信息。 确保记下“ Save location因为以后将使用它。 另外,请确保保存位置中没有空格,因为这可能会导致NDK工具出现问题。 编译外部低级别连接的设备时可能需要NDK工具。

For this example we will place the Android Plugin in a neighbor folder to the Unity Project folder.

在此示例中,我们将Android插件放置在Unity Project文件夹的邻居文件夹中。

Creating the Android Library

创建Android库

Android studio will automatically create an app folder, but we will not be using it. We will need to create a new Android Library:

Android studio会自动创建一个应用程序文件夹,但我们不会使用它。 我们将需要创建一个新的Android库:

File → New Module:

文件→新模块:

Image for post
Creating a new Module
创建一个新模块
Image for post
Selecting Android Library
选择Android库
Image for post
Selecting Android Library
选择Android库
Image for post
Configuring Android Library
配置Android库

Make sure you use the same Package Name as used inNativeCalculations.cs . The Minimum SDK depends on the capabilities of the package you are going to build. It can be changed later so API 16 is sufficient.

确保使用与NativeCalculations.cs相同的Package Name 。 最低SDK取决于要构建的软件包的功能。 以后可以更改,因此API 16就足够了。

After clicking Finish there will be a new Android library folder in the directory structure.

单击Finish后,目录结构中将出现一个新的Android库文件夹。

Android Dependencies

Android依赖项

Because this library is going to be used inside of Unity, there are specific dependencies that need to be set for proper compilation and runtime.

因为该库将在Unity内部使用,所以需要设置特定的依赖项才能进行正确的编译和运行。

Open the build.gradle for the library and edit the dependencies section as shown below.

打开库的build.gradle并编辑依赖项部分,如下所示。

Image for post
New Android Library’s build.gradle
新的Android库的build.gradle

Some questions you may be having:

您可能遇到的一些问题:

  1. Why can I not find the Unity classes jar location?

    为什么找不到Unity类的jar位置?

You may not have the Android Build Support Module. To add this check out the first section of the article. This jar is required to send messages back to Unity.

您可能没有Android Build支持模块。 要添加此内容,请查看本文的第一部分。 需要这个jar才能将消息发送回Unity。

2. Why is 'androidx.appcompat:appcompat:1.1.0' set as api instead of implementation?

2.为什么将'androidx.appcompat:appcompat:1.1.0'设置为api而不是implementation

The appcompat library is used for dealing with activities, among many things. A common use case would be requesting permissions. The Unity build will error out during runtime saying appcompat does not exist. Changing it to api will allow this library to be shared during runtime of Unity. This example will not go into how to request permissions, but it will be useful to keep this in mind when debugging runtime errors. For more explanation on the different types of dependencies. For official information on different types of dependencies.

appcompat库用于处理许多活动。 一个常见的用例是请求权限。 表示appcompat不存在,Unity构建将在运行期间出错。 将其更改为api将允许在Unity运行时共享该库。 此示例将不涉及如何请求权限,但是在调试运行时错误时记住这一点将非常有用。 有关不同类型的依赖关系的更多说明。 有关不同类型的依赖项的官方信息。

3. Why can’t I just use implementation 'com.google.code.gson:gson:2.8.6'?

3.为什么我不能只使用implementation 'com.google.code.gson:gson:2.8.6'

Unity will error out with:

Unity会出现以下错误:

UnityEngine.AndroidJavaException: java.lang.NoClassDefFoundError: Failed resolution of Lcom/google/gson/Gson;

UnityEngine.AndroidJavaException: java.lang.NoClassDefFoundError: Failed resolution of Lcom/google/gson/Gson;

The library must be including in the aar. An easy way is to just include it in libs.

该库必须包含在aar中。 一种简单的方法是将其包含在库中。

Android Library Class

Android库类

We can now add our implementation. Open up java, right click com.example.nativecalculations→ New → Java Class. We will name it NativeCalculationsPlugin.

现在,我们可以添加实现。 打开Java,右键单击com.example.nativecalculations →新建→Java类。 我们将其命名为NativeCalculationsPlugin

Image for post
Creating a new Java Class
创建一个新的Java类

Quick notes:

快速说明:

  1. UnityPlayer.UnitySendMessage requires the same game object name as well as the method name inside NativeCalculations.cs.

    UnityPlayer.UnitySendMessage需要相同的游戏对象名称以及NativeCalculations.cs的方法名称。

  2. Unity called methods can return basic types (like int, float, boolean), but not class types. Java class types are easiest sent by stringifying into json and then parsing back into a C# class.

    被称为Unity的方法可以返回基本类型(如int,float,boolean),但不能返回类类型。 通过将类化为json然后解析回C#类,可以最轻松地发送Java类类型。

Android Library Build

Android库构建

We will also be adding some code at the bottom of build.gradle to automatically copy the built Android Library into the Unity Android Plugin folder.

我们还将在build.gradle的底部添加一些代码,以自动将构建的Android库复制到Unity Android Plugin文件夹中。

To build the Android Library go to Build → Make Module ‘nativecalculations’.

要构建Android库,请转到构建→使模块为“本机计算”。

Android Unity Build

Android Unity构建

File → Build Settings. Click on Android and click Switch Platform if you have not do so already. Click on Player Settings. Make sure the Package Name is properly set as well as the minimum API level depending on your Android code. For this example API level 16 is sufficient.

文件→构建设置。 单击Android,然后单击切换平台(如果尚未这样做)。 单击播放器设置。 确保根据您的Android代码正确设置了程序包名称以及最低API级别。 对于此示例,API级别16就足够了。

Image for post
Other Settings in Player Settings for Android
Android播放器设置中的其他设置

You can either click Build or Build and Run. You may get a notification that your Android SDK is outdated. In actuality it is newer than expected by Unity. This is fine however for most plugins. Just clicking Use Highest Installed will allow building.

您可以单击BuildBuild and Run 。 您可能会收到有关您的Android SDK已过时的通知。 实际上,它比Unity预期的要新。 不过,对于大多数插件来说,这很好。 只需单击“ Use Highest Installed将允许构建。

Image for post
Android SDK is outdated
Android SDK已过时

Viewing Android Logs

查看Android日志

After the build is complete and the application is running, click Logcat at the bottom. In the search bar you can filter by Regex. Type in Unity.

构建完成并运行应用程序后,单击底部的Logcat。 在搜索栏中,您可以按正则表达式进行过滤。 输入Unity

Image for post
Android Logcat results for example
以Android Logcat结果为例

的iOS (iOS)

Unlike Android where we will create a library in Android Studio and built the filt to be compiled by Unity, iOS requires building/modifying an XCode project. Each subsequent build will override some of the previously edited files in XCode. Therefore any permanent edits to XCode have to be done inside Unity (unless you use my custom script in build post processor).

与Android不同,我们将在Android Studio中创建一个库并构建要由Unity编译的筛选器,而iOS则需要构建/修改XCode项目。 每个后续的构建都将覆盖XCode中一些以前编辑的文件。 因此,任何对XCode的永久性编辑都必须在Unity内部完成(除非您在构建后处理器中使用我的自定义脚本)。

iOS Unity Build

iOS Unity构建

File → Build Settings. Click on iOS and click Switch Platform if you have not do so already. Check Development Build to be able to see the logs.

文件→构建设置。 单击iOS,然后单击切换平台(如果尚未这样做)。 选中“ Development Build以查看日志。

Click on Player Settings.

单击播放器设置。

2. Make sure your Target SDK is set properly. For this demo we will use the Simulator SDK.

2.确保正确设置了目标SDK。 在本演示中,我们将使用模拟器SDK。

Image for post
Other Settings Target
其他设定目标

3. Make sure the Package Name is properly set (as well as the Signing Team ID if your target SDK is the device SDK).

3.确保正确设置了软件包名称(如果目标SDK是设备SDK,则还要设置签名团队ID)。

Image for post
Other Settings Identification
其他设置识别

Build post processor

构建后处理器

Inside the iOS folder create a new folder called Editor. Inside Editor create a new Script called BuildPostProcessor.cs. The Editor folder is a reserved folder in Unity that will run specific scripts and this script must be inside there for the imports to work as well as the script to be executed properly.

在iOS文件夹中,创建一个名为Editor的新文件夹。 在Editor内部,创建一个名为BuildPostProcessor.cs的新脚本。 Editor文件夹是Unity中的一个保留文件夹,它将运行特定的脚本,并且此脚本必须在其中,以便导入工作以及正确执行脚本。

Image for post
Adding BuildPostProcessor.cs
添加BuildPostProcessor.cs

Quick Notes:

快速说明:

  1. Foundation.framework added below is not necessary for the example but a demonstration of how to add system frameworks

    下面添加的Foundation.framework对于该示例不是必需的,而是有关如何添加系统框架的演示

  2. Add specific build properties and flags

    添加特定的构建属性和标志

We will now add a custom script that will automatically copy back edited files in XCode to the source files in Unity.

现在,我们将添加一个自定义脚本,该脚本将自动将XCode中的编辑文件复制回Unity中的源文件。

Why? Any time a project is rebuilt, the Unity project files will override the edited changes in XCode even if the XCode changes are newer. This is prone to errors as many of the editing will take place in XCode because of its IDE capabilities. This shell script will ensure edited files in XCode will be reflected in the Unity source files once a successful run takes place.

为什么? 每当重建项目时,即使XCode更改是较新的,Unity项目文件也将覆盖XCode中已编辑的更改。 这很容易出错,因为XCode的IDE功能会在XCode中进行许多编辑。 一旦成功运行,此shell脚本将确保XCode中编辑的文件将反映在Unity源文件中。

NOTE: If there was no successful run and you want to save your changes, you will need to manually copy the changes back to the original file.

注意 :如果没有成功运行,并且您要保存更改,则需要手动将更改复制回原始文件。

Now we can add our native plugin script. Inside of Plugins/iOS add NativeCalculationsPlugin.mm .

现在,我们可以添加我们的本机插件脚本。 在Plugins / iOS内部,添加NativeCalculationsPlugin.mm

Quick Notes:

快速说明:

  1. extern "C" are the interface methods called from Unity. These functions need to return C types and not Objective C classes. Note we are returning a const char * from copying the NSString with a helper function.

    extern "C"是Unity调用的接口方法。 这些函数需要返回C类型,而不是Objective C类。 请注意,我们通过使用辅助函数复制NSString返回了const char *

  2. The Objective C class is a singleton. The init helper method is used for initialization code similar to the constructor in Java.

    Objective C类是单例。 初始化帮助程序方法用于初始化代码,类似于Java中的构造函数。
  3. When sending JSON it is easiest to make dictionaries and use the utility function to stringify the dictionary.

    发送JSON时,最容易制作字典并使用实用程序函数对字典进行字符串化。

Viewing iOS Logs

查看iOS日志

After the build is complete and the application is running, you can view the logs in XCode.

构建完成并且应用程序运行之后,您可以在XCode中查看日志。

Image for post
iOS log results
iOS记录结果

Check out the full code and be sure to subscribe for more programming intricacies.

查看完整的代码,并确保订阅更多的编程技巧。

翻译自: https://medium.com/swlh/how-to-create-a-cross-platform-mobile-ios-and-android-plugin-for-unity-847b532615cc

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值