如何为 iOS 构建 Unity3d 插件 [英] How to build Unity3d Plugin for iOS

查看:55
本文介绍了如何为 iOS 构建 Unity3d 插件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个为 iOS 构建的非常小的 Objective-C 库,我想将它导出到 Unity.我了解编写将所有调用编组到本机库的 csharp 包装器的基本过程,但我完全不知道从哪里开始.任何人都可以逐步解释如何使用我的库创建统一包,以便我也可以将其分发给其他开发人员.

I have a very tiny Objective-C library built for iOS and I want to export it to Unity. I understand the basic process of writing a csharp wrapper that marshals all the invocations to native library, but I completely have no idea where to start. Could anyone please explain step-by-step how to create a unity package with my library so I could also distribute it to other developers.

Unity3d 文档非常简短,没有解释任何内容.

Unity3d documentation is pretty brief and does not explain anything.

谢谢.

推荐答案

好吧,在 Mac 上玩了几天 Unity3d 后,我终于弄明白了.本指南中的所有代码都是虚拟的.我在 15 分钟左右写了这些东西,所以不要被错误和错别字困扰.

Okay, after playing few days with Unity3d on Mac I finally figured it out. All the code in this guide is dummy. I have written this stuff in 15 minutes or so, so don't be bothered by mistakes and typos.

1) 打开 Unity,创建新项目(File -> New Project)并将其保存在某处

1) Open Unity, create new project (File -> New Project) and save it somewhere

2) 当项目生成时,它具有以下结构:

2) When the project is generated it has the following structure:

  • ProjectName/Assets(这就是你需要的)
  • ProjectName/Library(不管那里有什么)
  • ProjectName/ProjectSettings(你不关心)
  • ProjectName/ProjectName.sln(MonoDevelop 项目)
  • ProjectName/Assets (That's what you need)
  • ProjectName/Library (Nevermind what's there)
  • ProjectName/ProjectSettings (You don't care about it)
  • ProjectName/ProjectName.sln (MonoDevelop project)

3) 转到 ProjectName/Assets 并创建以下文件夹:Plugins/iOS,因此最终您将拥有这样的文件夹结构:项目名称/资产/插件/iOS

3) Go to ProjectName/Assets and create the following folders: Plugins/iOS, so in the end you'll have a folder structure like this: ProjectName/Assets/Plugins/iOS

4) 将编译后的库 (.a) 文件和必要的头文件放在 ProjectName/Assets/Plugins/iOS 中,或将库的源代码复制到那里(.mm、.h、.米,等等).请记住,通常您只能从 C# 访问 C 函数,因此您必须以某种方式将 Objective-C 的东西包装在 C 代码中,在我的情况下,所有的 Objective-C 对象都是以单例形式实现的,所以它不是'很难制作一个 C 风格的包装器,例如:

4) Put your compiled library (.a) file and necessary headers inside of ProjectName/Assets/Plugins/iOS or copy the source code of your library there (.mm, .h, .m, etc..). Remember, normally you can only access C-functions from C#, so you'll have to wrap your Objective-C stuff in C-code somehow, in my case all Objective-C objects were implemented in a form of Singleton so it wasn't hard to make a C-style wrapper around, for instance:

CWrapper.h:

extern "C" void MySDKFooBarCFunction();

CWrapper.mm

#import "CWrapper.h"
#import "MyObjectiveCLibrary.h" // your actual iOS library header

void MySDKFooBarCFunction() {
    [MyObjectiveCLibrary doSomeStuff];
}

5) 然后转到ProjectName/Assets 并为 CSharp 包装器类创建一个文件夹,随意命名,例如:ProjectName/Assets/MySDK

5) Then go to ProjectName/Assets and create a folder for CSharp wrapper class(es), call it whatever you want, for example: ProjectName/Assets/MySDK

6) 在 MySDK 文件夹内创建 MySDK.cs 文件,C# 包装器的虚拟示例如下所示:

6) Inside of MySDK folder create MySDK.cs file, the dummy example of C# wrapper would look like this:

using UnityEngine;
using System;
using System.Runtime.InteropServices;

public class MySDK
{
    // import a single C-function from our plugin
    [DllImport ("__Internal")]
    private static extern void MySDKFooBarCFunction();

    // wrap imported C-function to C# method
    public static void FooBarCFunction() {
        // it won't work in Editor, so don't run it there
        if(Application.platform != RuntimePlatform.OSXEditor) {
            MySDKFooBarCFunction();
        }
    }
}

7) 创建一个 shell 脚本将这些东西打包到 .unitypackage 中,并将它放在你的项目文件夹旁边(不是里面).根据您的需要调整脚本中的 EXPORT_PATHPROJECT_PATH 变量.

7) Create a shell script to pack this stuff into .unitypackage and put it next to your project folder (not inside). Adjust EXPORT_PATH and PROJECT_PATH variables in the script for your needs.

#!/bin/sh

WORKDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
UNITY_BIN="/Applications/Unity/Unity.app/Contents/MacOS/Unity"
EXPORT_PATH="${WORKDIR}/ProjectName.unitypackage"
PROJECT_PATH="${WORKDIR}/ProjectName"
ASSETS_PATH="Assets"

$UNITY_BIN -batchmode -quit 
-logFile export.log 
-projectPath $PROJECT_PATH 
-exportPackage $ASSETS_PATH $EXPORT_PATH

8) 运行创建的 bash 脚本来构建你的包.当您通过 Unity 编辑器中的 File -> Build Settings 生成它时,Assets 中的所有内容都将包含在您的 Unity 项目的 XCode 项目中.您可以使用生成的包将您的代码分发给其他开发人员,以便他们只需双击包文件即可将您的库包含到他们的 Unity 项目中.

8) Run the created bash script to get your package build. All stuff from Assets will be included in XCode project for your Unity Project when you generate it via File -> Build Settings in Unity Editor. You can use generated package to distribute your code to other developers so they can simply include your library to their Unity projects by double clicking on the package file.

运行此脚本时不要忘记关闭Unity Editor,否则可能无法构建包.

如果你有一些问题并且包没有显示出来,这个脚本总是将日志打印到 export.log

仅当您想为您的库制作 Demo unity 项目时,后续步骤才有意义(至少适合测试)

9) 您可以将创建的 Unity 项目 (ProjectName.unity) 放到 Assets/MySDKDemo 中,这样您的包中就有了一个演示.

9) You can put created Unity project (ProjectName.unity) to Assets/MySDKDemo so you have a demo inside of your package.

10) 在 Assets/MySDKDemo/MySDKDemo.cs 为您的 Demo Unity3d 场景创建一个简单的脚本,例如:

10) Create a simple script for your Demo Unity3d scene at Assets/MySDKDemo/MySDKDemo.cs, for example:

using UnityEngine;
using System;
using System.Collections;

public class MySDKDemo : MonoBehaviour
{   
    private GUIStyle labelStyle = new GUIStyle();
    private float centerX = Screen.width / 2;

    // Use this for initialization
    void Start ()
    {   
        labelStyle.fontSize = 24;
        labelStyle.normal.textColor = Color.black;
        labelStyle.alignment = TextAnchor.MiddleCenter;
    }

    void OnGUI ()
    {
        GUI.Label(new Rect(centerX - 200, 20, 400, 35), "MySDK Demo", labelStyle);
        if (GUI.Button(new Rect(centerX - 75, 80, 150, 35), "DoStuff"))
        {
            MySDK.FooBarCFunction();
        }
    }

}

11) 转到 Unity 编辑器.在 Unity Editor 的左侧边栏中找到Main Camera",选中它并在 Inspector 面板底部(右侧边栏)点击 AddComponent,选择 Scripts -> MySDKDemo script

11) Go to Unity Editor. Find the "Main Camera" in left sidebar in Unity Editor, select it and in the bottom of Inspector panel (right sidebar) click on AddComponent, select Scripts -> MySDKDemo script

12) 构建 XCode 项目并在设备上运行.

12) Build the XCode project and run on device.

注意事项

1) 插件在 Unity Editor 中不起作用,仅仅是因为它们不是实时编译的,好吧,不确定,但可能直到您在插件中使用 C#,C# 的东西可能会立即链接并在编辑器环境.

1) Plugins don't work in Unity Editor, simply because they're not compiled in the real-time, well, not sure but probably until you use C# in your plugins, probably C# stuff gets linked immidiately and works in Editor environment.

2) 这篇文章不涉及编组,或本机 <-> 托管代码之间的数据/内存管理,因为它有很好的文档记录.

2) This post does not cover marshaling, or data/memory management between native <-> managed code, as it is very well documented.

与原生库互操作@Mono 项目

3) 从 C# 到 C 的回调可以使用 C# 委托传递,在 C 端您使用标准函数声明,在 C# 端您声明具有相同签名的委托.似乎布尔值、整数和字符串(C:char*)被完美地编组(我不谈论内存管理策略以及谁负责释放内存或返回值策略).

3) Callbacks from C# to C can be passed using C# delegates, on C-side you use standard functions declarations, on C# side you declare delegates with the same signature. It seems that booleans, integers and strings (C: char*) are marshalled flawlessly (I don't talk about memory management policy and who's responsible to release memory or return value policies).

然而,由于平台限制,它不能在开箱即用的 iOS 版本上运行,但仍然可以使用 MonoPInvokeCallbackAttribute 实现 C# 到 C 的回调,有关此主题的有用链接:

However it will not work on iOS builds out-of-box due to platform limitations, but C#-to-C callbacks still can be implemented using MonoPInvokeCallbackAttribute, useful links on this topic:

实际上在 Unity 4 中已经实现了 AOT.MonoPInvokeCallbackAttribute,它仅限于可以传递给非托管代码的静态委托,但总比没有好.

Actually in Unity 4 there's AOT.MonoPInvokeCallbackAttribute already implemented, it's limited to static delegates that can be passed to unmanaged code, but still better than nothing.

4) 有一种方法可以使用 UnityGetGLViewController 函数来获取 Unity RootViewController.只需在您的实现文件中声明此函数,即:

4) There's a way to get Unity RootViewController using UnityGetGLViewController function. Just declare this function in your implementation file, i.e.:

extern UIViewController *UnityGetGLViewController();

并在需要访问 RootViewController 时使用 UnityGetGLViewController().

And use UnityGetGLViewController() whenever you need to get an access to RootViewController.

5) 在细节上有更多神奇和丑陋的东西,让你的 C 接口尽可能简单,否则编组可能成为你的噩梦,并且请记住,托管到非托管通常很昂贵.

5) There's much more magic and ugly stuff in details, keep your C interfaces as simple as possible otherwise marshalling can become your nightmare and also keep in mind that managed-to-unmanaged is generally expensive.

6) 您肯定在本机代码中使用了一些框架,并且您不希望出现链接器问题.例如,如果您在库中使用 Keychain,则需要将 Security.framework 包含到 Xcode 项目中.

6) You definitely use some frameworks in your native code and you don't want linker problems. For example, if you use Keychain in your library then you need to include Security.framework into Xcode project.

我建议尝试一下 XUPorter,它有助于 Unity 将任何其他依赖项集成到 Xcode 项目中.

I suggest to give a try to XUPorter, it helps Unity to integrate any additional dependencies into Xcode project.

祝你好运!

这篇关于如何为 iOS 构建 Unity3d 插件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆