unity 与第三方库的交互

什么是动态库、静态库

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

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

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. */
    @Override
    public 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);
    }



猜你喜欢

转载自blog.csdn.net/gtofei013/article/details/73867970