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

查看:118
本文介绍了如何为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,创建新项目(文件 - >新建项目)并将其保存在某处

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 ,所以最后你将有一个像这样的文件夹结构: ProjectName / Assets / Plugins / 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 中的文件和必要的标题,或者复制你的库的源代码ere(.mm,.h,.m等)。请记住,通常你只能从C#访问C函数,所以你必须以某种方式将你的Objective-C东西包装在C代码中,在我的例子中,所有Objective-C对象都以Singleton的形式实现,所以它不是'很难做出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_PATH PROJECT_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 Editor中的文件 - >构建设置生成它时,来自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.

Don在运行此脚本时忘记关闭Unity Editor,否则可能无法构建软件包。

如果您遇到一些问题,包没有显示,这个脚本总是打印日志到export.log

只有当你想要一个Demo团结时,下一步才有意义您的图书馆项目(至少适合测试)

9)您可以将创建的Unity项目(ProjectName.unity)放到 Assets / MySDKDemo 所以你的包中有一个demo。

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

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

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版本开箱即用,但C#-to-C回调仍然可以使用MonoPInvokeCallbackAttribute实现,这个主题:

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:

  • Reverse Callbacks @ Xamarin Docs
  • MonoPInvokeCallbackAttribute example @ Xamarin Forums

实际上在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();

并在需要时使用 UnityGetGLViewController()获取对RootViewController的访问权限。

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天全站免登陆