JAR (Java Archive) プラグインは主に、 Android OS とのインタラクションを可能にしたり、 Java で書かれたメソッドを C# スクリプト内から呼び出すために使用されます。
JAR プラグインは Java コードしか含むことができないため (例えば Android リソースは格納できません)、その用途は非常に限定的です。JAR プラグインをプロジェクトに加えるには、任意のプロジェクトフォルダーに .jar ファイルをコピーし、Unity 上でそれを選択し、Inspector ウィンドウの Import Settings (インポート設定) を開いてください。この .jar ファイルを Android と互換性を持つファイルとしてマーキングするには、Android のチェックボックスにチェックを入れます。
Java プラグインの使用 Unity は、 Java からコードを呼び出す場合にも、またネイティブコードや C# スクリプトから Java や Java VM (Virtual Machine) とインタラクトする場合にも、 Java Native Interface (JNI) を使用します。
注意: このセクションの内容を理解するには、Android Java Native Interface (JNI) に関する高度な知識が必要です。
C や C++ のプラグインから Java コードにアクセスするためには、 Java VM にアクセスする必要があります。 Java VM にアクセスするには、以下のメソッドを C/C++ コードに追加してください。
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* jni_env = 0;
vm->AttachCurrentThread(&jni_env, 0);
return JNI_VERSION_1_6;
}
JNI を完全に説明することを、ここではしません。しかし、下の例で示すように、このメソッドは通常、クラスの定義を検索し、コンストラクター (<init>) のメソッドを解決し、新しいオブジェクトインスタンスを作成することに関わっています。
jobject createJavaObject(JNIEnv* jni_env) {
jclass cls_JavaClass = jni_env->FindClass("com/your/java/Class"); // クラスの定義を検索する
jmethodID mid_JavaClass = jni_env->GetMethodID (cls_JavaClass, "<init>", "()V"); // コンストラクターのメソッドを検索する
jobject obj_JavaClass = jni_env->NewObject(cls_JavaClass, mid_JavaClass); // オブジェクトのインスタンスを作成する
return jni_env->NewGlobalRef(obj_JavaClass); // オブジェクトをグローバル参照とともに返すreturn object with a global reference
}
JNI に関する詳細は Android 開発者向けドキュメンテーションの JNI に関する項 をご参照ください。
注意: このセクションの内容を理解するには、Android Java Native Interface (JNI) に関する高度な知識が必要です。
Unity API クラス AndroidJNIHelper
および AndroidJNI
は、「raw (生)」 の JNI インターフェースのラッパーとして使用されます。
Unity API クラスである AndroidJavaObject と AndroidJavaClass は、JNI コールの使用時に、多くのタスクを自動化します。また Java の呼び出しを速くするためにキャッシングを利用します。AndroidJavaObject
と AndroidJavaClass
の組み合わせは AndroidJNI
と AndroidJNIHelper
に加える形で作成されますが、さらにいくつかの追加機能も持っています。 またこれらのクラスは静的メソッドも持っており、これは Java クラスの静的メソッドへのアクセスに使用されます。
C# スクリプトから JNI の呼び出しを行う方法は 3 つあります。
AndroidJNI
メソッドで raw JNI を呼び出すAndroidJNIHelper
クラスと AndroidJNI
の併用AndroidJavaObject
クラスおよび AndroidJavaClass
クラスUnityEngine.AndroidJNI は前述の通り、 C で利用可能な JNI コールのラッパーです。このクラスのメソッドは全て静的で、 Java Native Interface に 1 対 1 でマッピングされます。
UnityEngine.AndroidJNIHelper は次レベルによって使用されるヘルパー機能を提供します。これはパブリックメソッドとしてアクセス可能で、特殊な状況において役立つ場合があります。
UnityEngine.AndroidJavaObject と UnityEngine.AndroidJavaClass のインスタンスは、 Java 側の java.lang.Object と java.lang.Class (あるいはこれらのサブクラス) のインスタンスにそれぞれ 1 対 1 でマッピングされます。これらは、Java 側とのインタラクションに関して基本的に 3 種類の方法を提供します。
メソッドを呼び出す
フィールドの値を取得する
フィールドの値を設定する
呼び出しは、 void メソッドの呼び出しと、非 void 型の戻り値を返すメソッドの呼び出しの 2 種類に分けられます。非 void 型を返すメソッドの戻り値は、ジェネリック型によって表されます。 Get と Set は常にフィールドの型を表すジェネリック型を使用します。
AndroidJavaObject jo = new AndroidJavaObject("java.lang.String", "some_string");
// jni.FindClass("java.lang.String");
// jni.GetMethodID(classID, "<init>", "(Ljava/lang/String;)V");
// jni.NewStringUTF("some_string");
// jni.NewObject(classID, methodID, javaString);
int hash = jo.Call<int>("hashCode");
// jni.GetMethodID(classID, "hashCode", "()I");
// jni.CallIntMethod(objectID, methodID);
この例では、文字列 とともに初期化された java.lang.String のインスタンスをを作成し、その文字列の hash value を回収します。
AndroidJavaObject
コンストラクターは最低 1 つのパラメーター(インスタンスを作成するクラスの名前)を必要とします。そのクラス名に続くその他のパラメーターは全て、オブジェクトのコンストラクターの呼び出しです。ここでは “some_string” がそれに当たります。 続く hashCode() の呼び出しは ‘int’ を返します。この ‘int’ は、この参考例では、呼び出しメソッドのジェネリック型パラメーターとして使用されています。
(注) 入れ子になった Java クラスはドット表記法を使ってインスタンス化することができません。内側に入ったクラスは $ セパレーターを使わなければなりません。 LayoutParams クラスが ViewGroup クラスの内側に入り子になっている場合は、 android.view.ViewGroup$LayoutParams
またはandroid/view/ViewGroup$LayoutParams
のように使います。
この例では、現在のアプリケーションのキャッシュディレクトリを、プラグインを使用せずに C# で取得する方法をご確認いただけます。
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
// jni.FindClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject jo = jc.GetStatic AndroidJavaObject>("currentActivity");
// jni.GetStaticFieldID(classID, "Ljava/lang/Object;");
// jni.GetStaticObjectField(classID, fieldID);
// jni.FindClass("java.lang.Object");
Debug.Log(jo.Call AndroidJavaObject>("getCacheDir").Call<string>("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);
この例は、 AndroidJavaObject
ではなく AndroidJavaClass
で始まっています。これは、新しいオブジェクトを作成するのではなく com.unity3d.player.UnityPlayer
の静的メンバーにアクセスするためです。その後、静的フィールド “currentActivity” にアクセスが行われますが、ここではジェネリックパラメーターとして AndroidJavaObject
が使用されています。これは何故かというと、 実際のフィールド型 android.app.Activity は java.lang.Object
のサブクラスであり、また全ての 非プリミティブ型 は AndroidJavaObject
としてアクセスされなければならないためです。この規則が当てはまらないのは文字列です。文字列はたとえ Java でプリミティブ型でなくても直接アクセスが可能です。
上記を行った上で、 getCacheDir()
を Activity オブジェクトに呼び出すことにより、キャッシュディレクトリを示す File オブジェクトを取得できます。その後、 getCanonicalPath()
を呼び出して文字列を取得します。
Unity では、 Application.temporaryCachePath
および Application.persistentDataPath
API によって、アプリケーションのキャッシュとファイルディレクトリにアクセスできます。
この例では、UnitySendMessage
を使ってデータを Java から Unity に渡す方法をご確認いただけます。
public class NewBehaviourScript : MonoBehaviour {
void Start () {
AndroidJNIHelper.debug = true;
using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) {
jc.CallStatic("UnitySendMessage", "Main Camera", "JavaMessage", "NewMessage");
}
}
void JavaMessage(string message) {
Debug.Log("message from java: " + message);
}
}
Java クラス com.unity3d.player.UnityPlayer
には、 iOS メソッド UnitySendMessage
に相当する静的メソッド UnitySendMessage
があります。これは、Java でデータを Unity に渡すために使用されます。
UnitySendMessage
は Unity 内から呼び出されますが、 Java を使ってメッセージを伝えます。それから Java がネイティブあるいは Unity のコードにコールバックして “Main Camera” という名前のオブジェクトにメッセージを伝達します。このオブジェクトには JavaMessage
というメソッドを含むスクリプトが添付されています。
AndroidJavaObject
と AndroidJavaClass
は計算に高い負荷の掛かるメソッドです。(これは raw JNI を使用する他の多くのメソッドも同様です。)より良いパフォーマンスとコードの明瞭化のために、マネージコードとネイティブ(Java)コードの間の切り替えの数を最小限に抑えるようにしましょう。
//Java メソッドの初回呼び出し
AndroidJavaObject jo = new AndroidJavaObject("java.lang.String", "some_string"); //少々負荷が高い
int hash = jo.Call<int>("hashCode"); // 初回―負荷が高い
int hash = jo.Call<int>("hashCode"); // 2 回目―この java メソッドを既に使用済みであり直接呼び出せるため、初回よりは負荷が低い
Mono ガベージコレクターは、作成された AndroidJavaObject
と AndroidJavaClass
のインスタンス全てを、使用後には開放します。ただし、確実にできるだけ早く削除されるようにするために、これらは using(){}
ステートメント内に入れておくことをお勧めします。そうしないと、いつ破棄されるかが把握できません。 AndroidJNIHelper.debug
を True に設定すると、デバッグ出力でガベージコレクタの処理記録を確認することができます。
//システムからのメッセージを安全に取得
void Start () {
using (AndroidJavaClass cls = new AndroidJavaClass("java.util.Locale")) {
using(AndroidJavaObject locale = cls.CallStatic<AndroidJavaObject>("getDefault")) {
Debug.Log("current lang = " + locale.Call<string>("getDisplayLanguage"));
}
}
}
2017–05–18 Page published with no editorial review - Leave page feedback
5.5 のアップデート機能