Unity3D Native 插件开发(1)— 原理解析
发表于2016-05-17
这是一个系列教程,主要内容是如何开发 Unity 插件,在理解这个教程之前需要读者有一定的 Unity、iOS、Android 开发知识:
Unity3D Native 插件开发(2)— 小试牛刀
Unity3D Native 插件开发(3)— 理解 IL2CPP 机制
Unity3D Native 插件开发(4)— 异步与回调
Unity3D Native 插件开发(5)— Android 生命周期处理
Unity3D Native 插件开发(2)— 小试牛刀
Unity3D Native 插件开发(3)— 理解 IL2CPP 机制
Unity3D Native 插件开发(4)— 异步与回调
Unity3D Native 插件开发(5)— Android 生命周期处理
背景
随着手游快速的发展,有着更好的视觉体验的3D游戏更加被玩家所喜爱,Unity3D作为市面上最主流的开发引擎,使用U3D开发的有些越来越多。开发过程中,不免遇到需要调用Android/iOS原生(Native)方法的情况,本系列教材针对性介绍U3D调用Android/iOS Native代码方式方法。
调用方式简介
U3D调用Native代码的原理,简单来说就是通过中间跨语言调用机制,来实现Native代码调用
Android调用原理
代码调用AndroidNative代码,是基于JNI的机制实现的,好在Unity实现了一套帮助类,可以帮助开发者更简便的调用Android代码,主要的帮助类:
1、AndroidJNI
Unity的JNI底层接口,主要用于实现跟Android虚拟Dalvik之间的方法调用,主要包括:
C#与Java基础类型数据转换
Java类基本操作,包括构造、赋值等
Java方法调用
该类属于较底层的类,在特殊场合下用的到
2、AndroidJNIHelper
JNI的帮助类,封装了几个常见的方法,如数组转换、构造Java参数列表、获取Java方法ID、签名等,比较少用到
3、AndroidJavaObject
对应Java的基类Object,通过这个类,可以在Unity中直接通过类名构造Android中的Java类
一般我们使用该类进行Android代码调用,主要的方法:
构造方法,可以通过类名直接构造,如:
AndroidJavaObject jo = new AndroidJavaObject("java.lang.String", "some string");
获取和设定成员变量,包括成员变量和静态变量两种:
int m = jo.Get ("member");
jo.Set ("member", 1);
int m = jo.GetStatic ("member");
jo.SetStatic ("member", 1);
方法调用,包含成员方法和静态方法两种,返回值类型在“<>”中制定,如果返回值为空,无需“<>”
string substring = jo.Call ("substring", 1, 3);
int i = jo.CallStatic ("valueOf", 1);
注意:返回值类型只能是基础数据类型,如int、string及数组,Android的类可以用AndroidJavaObject来接;复杂类型,如Dictionary等是没有办法直接从Java类直接转成C#类的
4、AndroidJavaClass
这个类很好理解,继承于AndroidJavaObject,与其之间的关系等价于Java中Object与Class的关系,一个是类的实例,一个是类的类型
5、AndroidJavaException
官方文档中查不到,其实很简单,继承于C#的Exception,用于捕获处理Android代码时抛出的异常,可以通过try/catch来捕获Android层的异常
6、AndroidJavaProxy
这个类主要用于在C#环境实例化Java的Interface接口,需要特别注意其语法,参考:
http://docs.unity3d.com/ScriptReference/AndroidJavaProxy.html
7、AndroidJavaRunnable
这个类与Java中的Runtime对应,用来定义一个可执行类
iOS调用原理
C#调用iOS的代码,实际上是C#提供了一种调用C(非C++)代码的机制,而在iOS环境中,C代码是可以与苹果的Objective-C代码进行混合编译的,这样,就实现了C#调用iOS代码的功能
1、语法说明
非常简单,在Unity的C#的代码中做声明,在C语言中实现具体类容。
Unity中的声明可以是如下形式:
[DllImport ("__Internal")]
private static extern string SomeFunction();
在C语言环境中的实现可以是如下形式:
extern 'C' {
char* SomeFunction() {
char* retString = (char*)malloc(4);
memset(retString, 0, 4);
strncpy(retString, "abc", 4);
return retString;
}
}
如此,就可以实现函数间的对应关系
2、传参说明
由于是C语言,支持的参数及其数据类型是非常有限的,诸如int、float、double、char等这类两种语言中都存在的基础数据类型,是可以实现直接映射的,但是C#中的string对应到C中,就是char*了
工程结构
Unity在4.X版本以前,对Native的代码调用支持比较有限,只能说是够用;但是到了5.X的版本,Unity对着一块儿增加了很多支持,特别是iOS,比起4.X已经有很大的改善
1、Unity插件支持
Unity中,对于这一类的调用归属到插件(Plugins)的范畴,所以,Android/iOS的相关代码或Library都放在Assets/Plugins目录下,关于Unity特殊目录结构说明,可以参考:http://docs.unity3d.com/Manual/SpecialFolders.html
2、Android工程结构
说到在Unity的插件的工程结构,需要先了解Android本身的工程结构,Unity中采用的还是老式的ADT的目录结构,一般结构如下:
ProjectDir
--assets/*
--libs/*
--res/*
--src/*
project.properties
AndroidManifest.xml
其中,assets是Android下的资源文件;libs下面放jar包或者动态库.so;res下面放资源文件;src目录下放源码
Android的插件一般放在Assets/Plugins/Android目录下。该目录可以理解为Unity的主工程目录,可以按照标准ADT目录结构自行放置文件
如果遇到比较复杂的Android插件,需要依赖一个完整的工程,则可以将整个工程按上面结构整体放在Android目录下,这样,Unity就会将该目录识别为一个工程依赖
3、iOS工程结构
同Android一样,iOS也是Native代码作为插件处理,不过只支持C语言的文件,Objectiv-C特性的文件均不支持,如framework、bundle文件
所以,iOS一般来讲会用插件来处理,主要有两种:
Xcode Editor For Unity,https://github.com/dcariola/XCodeEditor-for-Unity
XUPorter,基于XCodeEditor开发,https://github.com/onevcat/XUPorter