Unity3D Native 插件开发(1)— 原理解析

发表于2016-05-17
评论0 8.7k浏览
这是一个系列教程,主要内容是如何开发 Unity 插件,在理解这个教程之前需要读者有一定的 Unity、iOS、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方法调用
  该类属于较底层的类,在特殊场合下用的到
2AndroidJNIHelper
  JNI的帮助类,封装了几个常见的方法,如数组转换、构造Java参数列表、获取Java方法ID、签名等,比较少用到
3AndroidJavaObject
  对应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#类的
4AndroidJavaClass
  这个类很好理解,继承于AndroidJavaObject,与其之间的关系等价于Java中Object与Class的关系,一个是类的实例,一个是类的类型
5AndroidJavaException
  官方文档中查不到,其实很简单,继承于C#的Exception,用于捕获处理Android代码时抛出的异常,可以通过try/catch来捕获Android层的异常
6AndroidJavaProxy
  这个类主要用于在C#环境实例化Java的Interface接口,需要特别注意其语法,参考:
http://docs.unity3d.com/ScriptReference/AndroidJavaProxy.html
7AndroidJavaRunnable
这个类与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已经有很大的改善
1Unity插件支持
  Unity中,对于这一类的调用归属到插件(Plugins)的范畴,所以,Android/iOS的相关代码或Library都放在Assets/Plugins目录下,关于Unity特殊目录结构说明,可以参考:http://docs.unity3d.com/Manual/SpecialFolders.html
2Android工程结构
  说到在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就会将该目录识别为一个工程依赖
3iOS工程结构
  同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

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引