2018-02-05unity3D 插件plugins

Unity中的插件機制JUL 25TH, 2015 12:01 PM 1. 介紹Unity有兩類插件: Managed plugins和Native plugin。Managed plugins是托管式.NET代碼,因為只有.NET代碼,也就是說不能使用.NET庫不支持的功能。Native plugins是平臺專門的原生代碼庫,可以用來訪問操作系統調用或者第三方的庫。在Unity5之前,通過插件存放的目錄來區分支持的目標平臺;然而Unity5可以把插件放在任何目錄,通過Plugin Inspector設置相關屬性就可以了,但為了兼容以前的版本,Unity5也會支持插件存放的目錄,進行默認的插件設置。規則如下:文件夾默認插件設置Assets/**/Editor 只兼容Editor Assets/**/Editor/(x86 or x86_64 or x64) 只兼容Editor,如果子文件夾存在,用于匹配目標CPU Assets/Plugins/x86_64(or x64) x64兼容 Assets/Plugins/x86 x86兼容 Assets/Plugins/Android/(x86 or armeabi or armeabi-v7a) 只跟Android兼容,如果子文件夾存在,用于匹配目標CPU Assets/Plugins/iOS 只跟iOS兼容 2. 托管式插件通常情況下,我們直接使用腳本實現相關功能,然后由Unity編譯成目標可執行文件。但有時我們不能不在外部把腳本編譯成DLL,然后放在Unity中使用。這個DLL就是這里所說的托管式插件,兼容.NET二進制。 2.1 創建一個DLL如果制作的DLL依賴Unity本身的DLL(UnityEngine.dll和UnityEditor.dll),還需要使編譯器能訪問它們。 Mac系統,它們存放在/Applications/Unity/Unity.app/Contents/Frameworks/Managed/, Windows下,存放在C:\Program Files\Unity\Editor\Data\Managed如果使用Mono C#編譯器mcs編譯,命令大體如下:mcs -r:/Applications/Unity/Unity.app/Contents/Frameworks/Managed/UnityEngine.dll -target:library ClassesForDLL.cs 2.2 使用DLL如同其它資源一樣,直接拖放到Unity項目里。繼承于MonoBehaviour的類可以直接拖到GameObject上,像普通腳本一樣;非MonoBehaviour類可以在其它腳本中被直接使用。 2.3 為DLL設置調試功能在MonoDevelop, 把生成的/bin/Debug/DLLTst.dll.mdb拷貝到Assets/Plugins文件夾下。在Visual Studio, 執行Program Files\Unity\Editor\Data\Mono\lib\mono\2.0\pdb2mdb.exe,按照提示傳入\bin\Debug\DLLTest.pdb,然后把生成的mdb文件放到Assets/Plugins文件夾下。接下來,確保Mono軟調試器開啟,Mac下是在MonoDevelop的MonoDevelop-Unity > Add-in Manager > Installed tab > Unity > select Mono Soft Debugger Support for Unity > Enable然后就可以單步跟進DLL腳本里。 3. 原生插件原生插件一般采用C,C++,Objective-C等等編寫,Unity允許游戲代碼來訪問這些原生插件中的函數,允許Unity和一些中間件庫或者已有的C/C++進行整合和。 3.1 實例一個簡單函數:float FooPluginFunction () { return 5.0F; } 為了能再Unity中可以訪問這簡單函數,需要這么用:using UnityEngine;using System.Runtime.InteropServices;class SomeScript : MonoBehaviour { #if UNITY_IPHONE || UNITY_XBOX360 // On iOS and Xbox 360 plugins are statically linked into // the executable, so we have to use __Internal as the // library name. [DllImport ("__Internal")] #else // Other platforms load plugins dynamically, so pass the name // of the plugin's dynamic library. [DllImport ("PluginName")] #endif private static extern float FooPluginFunction (); void Awake () { // Calls the FooPluginFunction inside the plugin // And prints 5 to the console print (FooPluginFunction ()); }}需要主要原生函數的name mangling問題,如果FooPluginFunction是用C++的代碼,那么需要這樣聲明:extern "C" { float FooPluginFunction ();} 4. Android平臺 4.1 C/C++插件做法跟上面的3.1類似,只是在編譯庫的時候需要依賴Android NDK 4.2 Java插件可以把預編譯的Android庫項目扔到Assets/Plugins/Android文件夾。預編譯的意思是所有.java文件必須已被編譯成java存放在bin/或者libs文件夾下,當項目編譯的時候這些文件夾下的AndroidManifest.xml會被自動合并到主manifest文件。Unity期望Java插件使用JDK v1.6編譯。如果使用v1.7,需要在命令參數中包含-source 1.6 -target 1.6 4.3 原生代碼訪問Java插件一旦你生成了.jar文件,你需要把它拷貝到Assets/Plugins/Android文件夾下。然后通過JNI訪問。為了能再原生端訪問java代碼,你需要先訪問Java虛擬機,代碼如下:jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* jni_env = 0; vm->AttachCurrentThread(&jni_env, 0); return JNI_VERSION_1_6;}然后可以創建新的對象實例:jobject createJavaObject(JNIEnv* jni_env) { jclass cls_JavaClass = jni_env->FindClass("com/your/java/Class"); // find class definition jmethodID mid_JavaClass = jni_env->GetMethodID (cls_JavaClass, "", "()V"); // find constructor method jobject obj_JavaClass = jni_env->NewObject(cls_JavaClass, mid_JavaClass); // create object instance return jni_env->NewGlobalRef(obj_JavaClass); // return object with a global reference} 4.4 C#訪問Java插件Unity提供了API類AndroidJNIHelper和AndroidJNI簡化JNI的訪問,也提供了AndroidJavaObject、AndroidJavaClass和java.lang.Object、java.lang.class對應。可以方便地:? 調用方法? 訪問類成員變量? 設置類成員變量Call分成兩類:? 調用沒有返回值(即返回void)的方法? 調用有返回值的例子如下://The comments describe what you would need to do if you were using raw JNIAndroidJavaObject jo = new AndroidJavaObject("java.lang.String", "some_string"); // jni.FindClass("java.lang.String"); // jni.GetMethodID(classID, "", "(Ljava/lang/String;)V"); // jni.NewStringUTF("some_string"); // jni.NewObject(classID, methodID, javaString); int hash = jo.Call("hashCode"); // jni.GetMethodID(classID, "hashCode", "()I"); // jni.CallIntMethod(objectID, methodID);不用額外插件,通過UnityPlayer獲得當前應用的cache目錄: AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); // jni.FindClass("com.unity3d.player.UnityPlayer"); AndroidJavaObject jo = jc.GetStatic("currentActivity"); // jni.GetStaticFieldID(classID, "Ljava/lang/Object;"); // jni.GetStaticObjectField(classID, fieldID); // jni.FindClass("java.lang.Object"); Debug.Log(jo.Call("getCacheDir").Call("getCanonicalPath")); // jni.GetMethodID(classID, "getCacheDir", "()Ljava/io/File;"); // or any baseclass thereof! // jni.CallObjectMethod(objectID, methodID); // jni.FindClass("java.io.File"); // jni.GetMethodID(classID, "getCanonicalPath", "()Ljava/lang/String;"); // jni.CallObjectMethod(objectID, methodID); // jni.GetStringUTFChars(javaString);上面代碼只是舉例說明,現在可以直接通過Application.temporaryCachePath和Application.persistentDataPath獲得cache目錄。下面的例子演示使用UnitySendMessage從Java層把數據傳遞到C#:using UnityEngine; public class NewBehaviourScript : MonoBehaviour { void Start () { AndroidJNIHelper.debug = true; using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) { jc.CallStatic("UnitySendMessage", "Main Camera", "JavaMessage", "whoowhoo"); } } void JavaMessage(string message) { Debug.Log("message from java: " + message); }} 4.5 擴展UnityPlayerActivity可以創建一個新的Activity繼承于UnityPlayerActivity(UnityPlayerActivity.java放在Mac的/Applications/Unity/Unity.app/Contents/PlaybackEngines/AndroidPlayer/com/unity3d/player或者Windows的C:\Program Files\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\src\com\unity3d\player)。首先,把classes.jar(Mac的/Applications/Unity/PlaybackEngines/AndroidPlayer/bin或者Windows下的C:\Program Files\Unity\Editor\Data)添加到classpath,用于編譯新的Activity。生成.class打包成.jar文件,放到Assets/Plugins/Android文件夾;創建新的AndroidManifest.xml,指定啟動的Activity,并把它放到Assets/Plugins/Android。新的Acitivy,如下:package com.company.product;import com.unity3d.player.UnityPlayerActivity;import android.os.Bundle;import android.util.Log;public class OverrideExample extends UnityPlayerActivity { protected void onCreate(Bundle savedInstanceState) { // call UnityPlayerActivity.onCreate() super.onCreate(savedInstanceState); // print debug message to logcat Log.d("OverrideActivity", "onCreate called!"); } public void onBackPressed() { // instead of calling UnityPlayerActivity.onBackPressed() we just ignore the back button event // super.onBackPressed(); }}關聯的AndroidManifest.xml如下:?xml version="1.0" encoding="utf-8"? Gingerbread之后引入了UnityPlayerNativeActivity,相比于UnityPlayerActivity,它的輸入延遲效果好。UnityPlayerNativeActivity的touch/motion事件都在原生代碼中處理的,一般情況下Java視圖不會接收到此類事件。Unity的重定向機制允許事件發往DalvikVM,如果使用這種機制,需要修改manifest:?xml version="1.0" encoding="utf-8"?


備注:https://answers.unity.com/questions/988343/plesehelp-meplugin-systemdatadll-is-used-from-seve.html???

? Yan_Sl

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • http://huangyaoshi.me/2015/07/25/plugins-system-in-unity/...
    ysl176閱讀 3,608評論 0 10
  • 《騰訊桌球:客戶端總結》 本次分享總結,起源于騰訊桌球項目,但是不僅僅限于項目本身。雖然基于Unity3D,很多東...
    吳秦閱讀 24,646評論 12 142
  • 這是踐行不抱怨習慣的第9天。今天沒有做到。(目標是1月份做到21天,已做到3天) 晚上在頭馬俱樂部做演講,咱們習慣...
    秦勤老師閱讀 153評論 2 0
  • 朋友圈里有人轉發了一條國外的視頻短片,看到后頗有感觸。 短片的場景是一群大學生新生模樣的孩子們,站在草坪的跑道上準...
    果果媽201612閱讀 344評論 0 0
  • 我的世界 有詩 有畫 有書 還有琴聲典雅 發芽的枝上有蝴蝶與鳥 舉起雙手 可以讓月亮變成太陽 擦亮火柴 可以讓火...
    青鄉閱讀 180評論 0 0