unity 与第三方库的交互

来源:互联网 发布:表格管理系统源码 编辑:程序博客网 时间:2024/05/16 18:35

什么是动态库、静态库

库是共享程序代码的方式,一般分为静态库和动态库

* 静态库:链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝 * 动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存。

Linux、Android、Unix

静态库为.a文件,动态库为.so文件

Windows

静态库为.lib文件,动态库为.dll文件

iOS

* 静态库分为两种:.a和.framework * 动态库也有两种:.dylib和.framework * 系统的.framework是动态库,我们自己建立的.framework是静态库 * .a + .h + sourceFile = .framework。


Unity中动态库的使用

动态库是在运行时期间被使用到,如果dll文件是C#代码组成的,那就直接把dll文件直接放到plugin目录下即可,在代码中就可以直接使用dll文件中所包含的类了。另一种情况是dll文件是由C/C++组成,这种情况想要使用dll文件中的函数就需要用到DllImport了。

DllImport

- C/C++导出代码

extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API SetTextureFromUnity(void* textureHandle, int w, int h){    // A script calls this at initialization time; just remember the texture pointer here.    // Will update texture pixels each frame from the plugin rendering event (texture update    // needs to happen on the rendering thread).    g_TextureHandle = textureHandle;    g_TextureWidth = w;    g_TextureHeight = h;}

其中宏UNITYINTERFACEEXPORT为__declspec(dllexport),标记SetTextureFromUnity函数将会被导出成dll库

-Unity使用代码

#if UNITY_IPHONE && !UNITY_EDITOR    [DllImport ("__Internal")]#else    [DllImport ("RenderingPlugin")]#endif    private static extern void SetTimeFromUnity(float t);

- DLL文件必须位于程序当前目录或系统定义的查询路径中(即:系统环境变量中Path所设置的路径)。 - DLLImport会按照顺序去查找DLL文件(程序当前目录>System32目录>环境变量Path所设置路径)。 - 返回类型变量、方法名称、参数列表一定要与DLL文件中的定义相一致。

如果被调用的库函数是带返回的,将会有以下几种情况:

  • 返回的数据类型是系统已定义好的数据类型通常C#和C/C++之间有一个数据的映射关系,如int、float、char、函数指针。
  • 返回数据类型是自定义的指针变量那C#中统一是用IntPtr接收,在C#中使用指针操作时需要加上unsafe关键字,通常还需要配合fixed关键字使用。
  • 另外还有一种特殊情况是希望传递的数据类型是Struct,需要在C#中定义一个相同Struct类型,且在C#层以引用方式传入,在dll中进行赋值。

-dll中定义的struct

struct Bar{public :    int id;    char* name;};EXPORT_DLL void GetBar(Bar& bar){    //Bar b;    bar.id = 10;    bar.name = "hi bar 中文了";}

- C#中定义对应的struct

    [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]    public struct Bar    {         /// int        public int id;         /// char*        [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]        public string name;    }        class Program    {         [DllImport("CppDll.dll")]        extern static void GetBar(ref Bar bar);          static void Main(string[] args)        {            Bar b = new Bar();            GetBar(ref b);    }

System.Runtime.InteropServices包下的几个重要的类:

  Marshal:类提供了一个方法集,这些方法用于分配非托管内存、复制非托管内存块、将托管类型转换为非托管类型,此外还提供了在与非托管代码交互时使用的其他方法。

[link](http://www.cnblogs.com/DragonX/p/3474251.html)

GCHandle:获取托管对象的地址,同时“盯”住该对象

[link](https://msdn.microsoft.com/zh-cn/library/system.runtime.interopservices.gchandle.aspx)

Android中动态库的使用

Android中动态库的表现形态问.so文件,直接调用System.loadLibrary("abc")函数就可以加载名为libabc.so的库了。

  • C/C++导出代码

    #include <jni.h>#define LOG_TAG "HelloWorld"#include <utils/Log.h>/* Native interface, it will be call in java code */JNIEXPORT jstring JNICALL Java_com_zhangyi_HelloWorld_printJNI(JNIEnv *env, jobject obj){  LOGI("dufresne Hello World From libhelloworld.so!");}/* This function will be call when the library first be load.* You can do some init in the libray. return which version jni it support.*/jint JNI_OnLoad(JavaVM* vm, void* reserved){  void *venv;  LOGI("dufresne----->JNI_OnLoad!");  if ((*vm)->GetEnv(vm, (void**)&venv, JNI_VERSION_1_4) != JNI_OK) {    LOGE("dufresne--->ERROR: GetEnv failed");    return -1;  }  return JNI_VERSION_1_4;}

    ```

  • Java调用库的代码

    package com.zhangyi;import android.app.Activity;import android.os.Bundle;import android.util.Log;public class HelloWorld extends Activity {/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.main);  Log.v("dufresne", printJNI("I am HelloWorld Activity"));}  static  {    //加载库文件    System.loadLibrary("HelloWorldJni");  }   //声明原生函数 参数为String类型 返回类型为String  private native String printJNI(String inputStr);}



原创粉丝点击