91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

[unity3d]Unity3D與android交互----

發布時間:2020-03-02 08:34:05 來源:網絡 閱讀:864 作者:蓬萊仙羽 欄目:游戲開發

原文地址:Building Plugins for Android


為android構建一個插件


要創建一個android插件,首先要有 Android NDK 并熟悉使用ndk構建共享庫的方法。

如果用C++來實現庫,必須聲明成用C語言的鏈接方式,以避免Name Mangling問題。

[cpp] view plaincopy
  1. extern "C"   
  2. {  
  3.   float FooPluginFunction ();  
  4. }   

通過C#腳本使用插件

構建了共享庫后,必須把共享庫復制到unity3d工程中的Assets->Plugins->Android目錄下。(沒有該目錄的話,自己依次創建。)

當你在unity3d中在C#腳本中定義如下的函數時,unity3d就能通過名稱找到共享庫

[csharp] view plaincopy
  1. [DllImport ("PluginName")]  
  2. private static extern float FooPluginFunction ();   

注意PluginName不要包含共享庫文件名中的“lib”前綴和“.so”后綴。建議所有的native代碼方法都用C#代碼封裝一層,并在C#代碼中檢查Application.platform變量,以保證只有app運行在正確的設備上時,才去調用native方法。當在Editor環境下運行時,可以在C#代碼中返回空值。

當然也可以用平臺宏定義的方法,來控制與平臺相關的代碼的編譯。


部署

對于要部署到多個平臺的項目,項目工程中必須包含各個平臺所需要的插件(例如:libPlugin.so用于android平臺,Plugin.bundle用于mac平臺,Plugin.dll用于windows平臺)。unity3d會自動為目標平臺選擇正確的插件。


使用java插件

android插件機制同樣允許使用java來與android系統進行交互。


為android構建一個java插件

有好幾種方法來構建java插件,最終結果都是生成包含.class文件的.jar包。一種方法是下載 JDK,在命令行下用javac命令編譯,用jar命令打包成jar文件;另一種方法是 Eclipse+ADT。


在native代碼中使用java插件

構建好了java插件后,將java插件(.jar)復制到 unity3d工程中的Assets->Plugins->Android文件夾下面,unity3d會將你的.class文件和其余的java代碼打包,并通過Java Native Interface (JNI)來訪問這些代碼。JNI既可以用于java代碼調用native代碼,也可用于native代碼與java(java虛擬機)的交互。


要找到你的java代碼,必須要能訪問到java虛擬機。幸運的是,可以通過在c/c++代碼中添加如下函數來很容易的實現這種訪問:

[cpp] view plaincopy
  1. jint JNI_OnLoad(JavaVM* vm, void* reserved)   
  2. {  
  3.   JNIEnv* jni_env = 0;  
  4.   vm->AttachCurrentThread(&jni_env, 0);  
  5. }   

這個是從c/c++調用java所必需的。JNI超越了本文檔的范疇,不做詳細解釋。通常情況下,先找到類的定義,然后解析類的構造方法(<init>)并創建類的實例,如下面例子所示:

[cpp] view plaincopy
  1. jobject createJavaObject(JNIEnv* jni_env)   
  2. {  
  3.   jclass cls_JavaClass = jni_env->FindClass("com/your/java/Class");          // 找到類定義  
  4.   jmethodID mid_JavaClass = jni_env->GetMethodID (cls_JavaClass, "<init>",  "()V");        // 找到構造方法  
  5.   jobject obj_JavaClass = jni_env->NewObject(cls_JavaClass, mid_JavaClass);      // 創建對象實例  
  6.   return jni_env->NewGlobalRef(obj_JavaClass);                       // return object with a global reference  
  7. }   

通過幫助類來使用java插件

使用AndroidJNIHelper 和AndroidJNI會減輕些使用原始JNI的痛苦。


AndroidJNIHelper 和AndroidJNI自動完成了很多任務(指找到類定義,構造方法等),并且使用緩存使調用java速度更快。AndroidJavaObjectAndroidJavaClass基于AndroidJNIHelper 和AndroidJNI創建,但在處理自動完成部分也有很多自己的邏輯,這些類也有靜態的版本,用來訪問java類的靜態成員。


你可以選擇任意你喜歡的方式來替代這種原始JNI的做法,可以通過 AndroidJNI類,也可以通過AndroidJNIHelperAndroidJNI 最后也可以使用 AndroidJavaObject/AndroidJavaClass,這樣會有最大程度的自動完成和最大的便利性。


UnityEngine.AndroidJNI是對那些c代碼可用的JNI調用的封裝,該類中的所有方法都是靜態的并且一一對應到JNI。

UnityEngine.AndroidJNIHelper通過public方法提供了一些不常用的輔助功能,在某些特殊情況下會比較有用處。


在java端,UnityEngine.AndroidJavaObject和UnityEngine.AndroidJavaClass的實例分別一一對應于 java.lang.Object和java.lang.Class (或它的子類)的實例。它們提供了3種與java端交互的方法:

  • Call方法
  • Get域的值
  • Set域的值

    Call分為兩類,調用void方法和調用非void返回類型的方法,會使用一個泛型類型來表示這些非void返回類型的方法的返回類型;Get和Set也經常帶一個泛型類型用以表示域的類型。


    例子1:

    [cpp] view plaincopy
    1. //注釋表示是使用原始JNI方法必須做的工作  
    2.  AndroidJavaObject jo = new AndroidJavaObject("java.lang.String""some_string");   
    3.  // jni.FindClass("java.lang.String");   
    4.  // jni.GetMethodID(classID, "<init>", "(Ljava/lang/String;)V");   
    5.  // jni.NewStringUTF("some_string");   
    6.  // jni.NewObject(classID, methodID, javaString);   
    7.  int hash = jo.Call<int>("hashCode");   
    8.  // jni.GetMethodID(classID, "hashCode", "()I");   
    9.  // jni.CallIntMethod(objectID, methodID);  
    這個例子中,我們創建了一個 java.lang.String的實例,并用我們自定義的一個字符串初始化它,最后我們得到該字符串的哈希值。


     AndroidJavaObject的構造方法至少需要一個參數----你想要實例化的類的名稱。類名之后的參數會被對象的構造函數所使用,如上例種的字符串“
    some_string”,隨后的對hashCode方法的Call會返回一個int型值,這也是為什么我們會傳一個泛型參數給Call方法。


    注意:不能使用點.來初始化一個嵌套類型,內部類必須使用$分隔符,在斜線/或點.分隔的類名中都可以使用。所以當類LayoutParams嵌套在ViewGroup類中時,android.view.ViewGroup$LayoutParams或者android/view/ViewGroup$LayoutParams,這兩種方式都是可行的。


    例子2:

    上面有個插件的例子是說獲取當前程序的緩存目錄的,下面這個例子直接用c#代碼做同樣的事情,而不需要任何插件:

    [csharp] view plaincopy
    1. AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");   
    2. // jni.FindClass("com.unity3d.player.UnityPlayer");   
    3. AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");   
    4. // jni.GetStaticFieldID(classID, "Ljava/lang/Object;");   
    5. // jni.GetStaticObjectField(classID, fieldID);   
    6. // jni.FindClass("java.lang.Object");   
    7.   
    8. Debug.Log(jo.Call<AndroidJavaObject>("getCacheDir").Call<string>("getCanonicalPath"));   
    9. // jni.GetMethodID(classID, "getCacheDir", "()Ljava/io/File;"); // or any baseclass thereof!   
    10. // jni.CallObjectMethod(objectID, methodID);   
    11. // jni.FindClass("java.io.File");   
    12. // jni.GetMethodID(classID, "getCanonicalPath", "()Ljava/lang/String;");   
    13. // jni.CallObjectMethod(objectID, methodID);   
    14. // jni.GetStringUTFChars(javaString);  

    這個例子中,我們沒有首先使用AndroidJavaObject,而是AndroidJavaClass ,因為我們想獲取類com.unity3d.player.UnityPlayer的一個靜態成員,而不是去創建一個新的對象(Android UnityPlayer會自動創建一個實例)。我們訪問其靜態域"currentActivity" ,這個時候我們用的是AndroidJavaObject作為泛型參數,這是因為實際類型(android.app.Activity)是類java.lang.Object的子類,任意非基本類型都必須作為AndroidJavaObject來訪問。有一個例外就是字符串,字符串可以直接訪問,盡管它在java中并不是基本類型。


    之后就是調用的Activity的getCacheDir()得到緩存目錄的文件對象,再調用getCanonicalPath()方法獲取緩存目錄路徑的字符串表示。


    當然,現在已經不需要通過這種方式來獲取緩存目錄了,因為unity3d提供了接口用以訪問程序的緩存目錄和數據目錄,也就是Application.temporaryCachePath and Application.persistentDataPath。


    例子3:

    最后,是一個通過UnitySendMessage方法從java代碼向腳本代碼傳遞數據的小竅門。

    [csharp] view plaincopy
    1. using UnityEngine;   
    2. public class NewBehaviourScript : MonoBehaviour   
    3. {   
    4.   
    5. <span style="white-space:pre">  </span>void Start ()   
    6. <span style="white-space:pre">  </span>{   
    7.     <span style="white-space:pre">  </span>JNIHelper.debug = true;   
    8.     <span style="white-space:pre">  </span>using (JavaClass jc = new JavaClass("com.unity3d.player.UnityPlayer"))   
    9. <span style="white-space:pre">      </span>{   
    10. <span style="white-space:pre">  </span>     jc.CallStatic("UnitySendMessage""Main Camera""JavaMessage""whoowhoo");   
    11.     <span style="white-space:pre">  </span>}   
    12.     }   
    13.   
    14.     void JavaMessage(string message)   
    15. <span style="white-space:pre">  </span>{   
    16.         Debug.Log("message from java: " + message);   
    17.     }  
    18. }   


    com.unity3d.player.UnityPlayer現在有一個靜態方法UnitySendMessage,與iOS中native端的UnitySendMessage一樣,可用來在java中向腳本傳遞數據。


    這里我們直接從腳本中調用的,但它確實是在java端發送的消息,它會調回到unity3d的native代碼,傳遞消息到名為"Main Camera"的游戲對象上去,該對象上綁定的某個腳本中包含有名為"JavaMessage"的方法。


    在unity3d中使用java插件的最佳實踐
    這一節主要針對那些沒有足夠jni,java和android經驗的人。假設我們在unity3d中使用AndroidJavaObject/AndroidJavaClass來與java交互。


    首先就是要注意對AndroidJavaObject/AndroidJavaClass的任何操作都是很費時的(是通過JNI來進行的)。因此為了代碼性能和代碼清晰性,我們強烈建議托管代碼與native/java代碼間的轉換次數保持在最小數量。


    你可以定義一個java方法完成所有的事情,然后我們通過AndroidJavaObject/AndroidJavaClass來與這個方法通信和獲取結果,我們的JNI幫助類會盡可能多的緩存數據已提高性能。

    [csharp] view plaincopy
    1. //第一次像這樣調用java函數  
    2. AndroidJavaObject jo = new AndroidJavaObject("java.lang.String""some_string");  // 有點費時  
    3. int hash = jo.Call<int>("hashCode");  //第一次 - 費時  
    4. int hash = jo.Call<int>("hashCode");  // 第二次 - 不那么費時, 因為我們已經知道了這個java方法,可以直接調用它。  

    在使用過后,Mono垃圾回收器會釋放所有創建的AndroidJavaObjectAndroidJavaClass實例,但我們還是建議把它們放到using(){}塊中,以保證它們能被盡快的清除掉。除此之外,你無法保證它們會被銷毀掉。如果你設置了AndroidJNIHelper.debug為true,你會在log輸出中看到垃圾回收器的活動記錄。

    [csharp] view plaincopy
    1. //獲取系統語言的安全方法  
    2. void Start ()   
    3. {   
    4.     using (AndroidJavaClass cls = new AndroidJavaClass("java.util.Locale"))   
    5. <span style="white-space:pre">  </span>{   
    6.         using(AndroidJavaObject locale = cls.CallStatic<AndroidJavaObject>("getDefault"))   
    7. <span style="white-space:pre">      </span>{   
    8.             Debug.Log("current lang = " + locale.Call<string>("getDisplayLanguage"));   
    9.   
    10.         }   
    11.     }   
    12. }  


    也可以直接調用.Dispose()方法確保沒有java對象殘留,c#對象會存活長一點,最終還是會被mono的垃圾回收器回收。

    繼承UnityPlayerActivity java代碼


    在Unity Android上,我們可以繼承標準的UnityPlayerActivity類(android上Unity Player的主要java類,類似于Unity iOS上的AppController.mm)。


    應用程序可以覆寫android系統與Unity Android之間的任意交互方法,只要新建一個Activity繼承UnityPlayerActivity就可以實現。(在mac系統上,UnityPlayerActivity.java在/Applications/Unity/Unity.app/Contents/PlaybackEngines/AndroidPlayer/src/com/unity3d/player目錄下;在windows系統中,它通常在C:\Program Files\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\src\com\unity3d\player目錄下)


    首先定位Unity Android的classes.jar文件,可以在Unity3d的安裝目錄(windows下通常是C:\Program Files\Unity\Editor\Data,mac下是/Applications/Unity)下的子文件夾PlaybackEngines/AndroidPlayer/bin中找到,將它添加到你編譯activity的classpath中。最終編譯出來的.class文件,需要打包成.jar文件,放到工程中的Assets->Plugins->Android目錄下。因為android中manifest文件指明了啟動哪個Activity,因此我們也需要重新寫一個AndroidManifest.xml文件,也需要將它放到Assets->Plugins->Android目錄下。


    繼承UnityPlayerActivity的一個例子,OverrideExample.java:

    [java] view plaincopy
    1. package com.company.product;  
    2.   
    3. import com.unity3d.player.UnityPlayerActivity;  
    4.   
    5. import android.os.Bundle;  
    6. import android.util.Log;  
    7.   
    8. public class OverrideExample extends UnityPlayerActivity {  
    9.   
    10.   protected void onCreate(Bundle savedInstanceState) {  
    11.   
    12.     // call UnityPlayerActivity.onCreate()  
    13.     super.onCreate(savedInstanceState);  
    14.   
    15.     // print debug message to logcat  
    16.     Log.d("OverrideActivity""onCreate called!");  
    17.   }  
    18.   
    19.   public void onBackPressed()  
    20.   {  
    21.     // instead of calling UnityPlayerActivity.onBackPressed() we just ignore the back button event  
    22.     // super.onBackPressed();  
    23.   }  
    24. }   

    相關的AndroidManifest.xml文件如下:

    [html] view plaincopy
    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.company.product">  
    3.   <application android:icon="@drawable/app_icon" android:label="@string/app_name">  
    4.     <activity android:name=".OverrideExample"  
    5.               android:label="@string/app_name"  
    6.               android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen">  
    7.         <intent-filter>  
    8.             <action android:name="android.intent.action.MAIN" />  
    9.             <category android:name="android.intent.category.LAUNCHER" />  
    10.         </intent-filter>  
    11.     </activity>  
    12.   </application>  
    13. </manifest>   


    UnityPlayerNativeActivity

    同樣我們可以創建UnityPlayerNativeActivity的子類,這與創建UnityPlayerActivity的子類具有相同的效果,但是會有較小的輸入延遲。但是,需要明白的是,NativeActivity是在Gingerbread中引入的(即android 2.3),老的android版本沒有這個特性,因為在NativeActivity中,觸摸事件都是在native代碼中處理的,java視圖正常情況下是無法獲取這些事件的,不過在unity3d中,有允許將事件傳到DalvikVM的轉發機制,要應用這個轉發機制,必須修改manifest文件如下:

    [html] view plaincopy
    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.company.product">  
    3.   <application android:icon="@drawable/app_icon" android:label="@string/app_name">  
    4.     <activity android:name=".OverrideExampleNative"  
    5.               android:label="@string/app_name"  
    6.               android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen">  
    7.   <meta-data android:name="android.app.lib_name" android:value="unity" />  
    8.   <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="true" />  
    9.         <intent-filter>  
    10.             <action android:name="android.intent.action.MAIN" />  
    11.             <category android:name="android.intent.category.LAUNCHER" />  
    12.         </intent-filter>  
    13.     </activity>  
    14.   </application>  
    15. </manifest>   

    要注意activity元素中的.OverrideExampleNative屬性,還有兩條meta-data元素,第一條meta-data元素指明使用unity3d庫libunity.so,第二條meta-data元素使事件能傳遞到你創建的UnityPlayerNativeActivity子類中。


    例子


    native插件例子

    這里有一個簡單的使用native插件的例子。

    這個例子演示了如果從unity3d android程序中來調用c代碼,包中包含了一個通過native插件計算出來的兩個數之和的場景,要注意,你必須用Android NDK來編譯這個插件。


    java插件例子

    這里有一個簡單的使用java代碼的例子。


    這個例子演示了怎么用java代碼與android系統進行交互,以及如何用c++來將c#和java溝通起來,包中的場景顯示了一個按鈕,點擊該按鈕,會顯示出程序在android系統中的緩存目錄路徑。需要JDK和 Android NDK來編譯這個插件。


    這里有一個相似的例子,但是是基于預先編譯好的JNI庫,來封裝native代碼,供c#調用。


  • 向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    龙游县| 正镶白旗| 石泉县| 宽甸| 运城市| 汉源县| 瑞金市| 科技| 上蔡县| 隆德县| 常州市| 邹平县| 四川省| 资源县| 乐东| 天水市| 孟津县| 自治县| 通渭县| 正宁县| 弥勒县| 荔波县| 庆云县| 依兰县| 岫岩| 金沙县| 兖州市| 五寨县| 大荔县| 明光市| 离岛区| 湖北省| 图木舒克市| 漾濞| 濉溪县| 仁化县| 河间市| 宜城市| 同心县| 江山市| 乐平市|