Set域的值
-
- AndroidJavaObject jo = new AndroidJavaObject("java.lang.String", "some_string");
-
-
-
-
- int hash = jo.Call<int>("hashCode");
-
-
這個例子中,我們創建了一個 java.lang.String的實例,并用我們自定義的一個字符串初始化它,最后我們得到該字符串的哈希值。 some_string
android.view.ViewGroup$LayoutParams或者android/view/ViewGroup$LayoutParams,這兩種方式都是可行的。
上面有個插件的例子是說獲取當前程序的緩存目錄的,下面這個例子直接用c#代碼做同樣的事情,而不需要任何插件:
- AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
-
- AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
-
-
-
-
- Debug.Log(jo.Call<AndroidJavaObject>("getCacheDir").Call<string>("getCanonicalPath"));
-
-
-
-
-
-
這個例子中,我們沒有首先使用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代碼向腳本代碼傳遞數據的小竅門。
- using UnityEngine;
- public class NewBehaviourScript : MonoBehaviour
- {
-
- <span style="white-space:pre"> </span>void Start ()
- <span style="white-space:pre"> </span>{
- <span style="white-space:pre"> </span>JNIHelper.debug = true;
- <span style="white-space:pre"> </span>using (JavaClass jc = new JavaClass("com.unity3d.player.UnityPlayer"))
- <span style="white-space:pre"> </span>{
- <span style="white-space:pre"> </span> jc.CallStatic("UnitySendMessage", "Main Camera", "JavaMessage", "whoowhoo");
- <span style="white-space:pre"> </span>}
- }
-
- void JavaMessage(string message)
- <span style="white-space:pre"> </span>{
- Debug.Log("message from java: " + message);
- }
- }
類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幫助類會盡可能多的緩存數據已提高性能。
-
- AndroidJavaObject jo = new AndroidJavaObject("java.lang.String", "some_string");
- int hash = jo.Call<int>("hashCode");
- int hash = jo.Call<int>("hashCode");
在使用過后,Mono垃圾回收器會釋放所有創建的AndroidJavaObject和AndroidJavaClass實例,但我們還是建議把它們放到using(){}塊中,以保證它們能被盡快的清除掉。除此之外,你無法保證它們會被銷毀掉。如果你設置了AndroidJNIHelper.debug為true,你會在log輸出中看到垃圾回收器的活動記錄。 -
- void Start ()
- {
- using (AndroidJavaClass cls = new AndroidJavaClass("java.util.Locale"))
- <span style="white-space:pre"> </span>{
- using(AndroidJavaObject locale = cls.CallStatic<AndroidJavaObject>("getDefault"))
- <span style="white-space:pre"> </span>{
- Debug.Log("current lang = " + locale.Call<string>("getDisplayLanguage"));
-
- }
- }
- }
也可以直接調用.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下是/)下的子文件夾PlaybackEngines/AndroidPlayer/bin中找到,將它添加到你編譯activity的classpath中。最終編譯出來的.class文件,需要打包成.jar文件,放到工程中的Assets->Plugins->Android目錄下。因為android中manifest文件指明了啟動哪個Activity,因此我們也需要重新寫一個AndroidManifest.xml文件,也需要將它放到Assets->Plugins->Android目錄下。
繼承UnityPlayerActivity的一個例子,OverrideExample.java:
- 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) {
-
-
- super.onCreate(savedInstanceState);
-
-
- Log.d("OverrideActivity", "onCreate called!");
- }
-
- public void onBackPressed()
- {
-
-
- }
- }
相關的AndroidManifest.xml文件如下:
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.company.product">
- <application android:icon="@drawable/app_icon" android:label="@string/app_name">
- <activity android:name=".OverrideExample"
- android:label="@string/app_name"
- android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
- </manifest>
UnityPlayerNativeActivity
同樣我們可以創建UnityPlayerNativeActivity的子類,這與創建UnityPlayerActivity的子類具有相同的效果,但是會有較小的輸入延遲。但是,需要明白的是,NativeActivity是在Gingerbread中引入的(即android 2.3),老的android版本沒有這個特性,因為在NativeActivity中,觸摸事件都是在native代碼中處理的,java視圖正常情況下是無法獲取這些事件的,不過在unity3d中,有允許將事件傳到DalvikVM的轉發機制,要應用這個轉發機制,必須修改manifest文件如下:
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.company.product">
- <application android:icon="@drawable/app_icon" android:label="@string/app_name">
- <activity android:name=".OverrideExampleNative"
- android:label="@string/app_name"
- android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen">
- <meta-data android:name="android.app.lib_name" android:value="unity" />
- <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="true" />
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
- </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#調用。