Javaクラス呼び出し用C#スクリプト
次は、Unity側の作業です。
Unity側でのファイルの準備
まず、[Project]ウィンドウにおいて、先ほど追加したHelloWorldJava.jarとlibjni.soが「/Plugins/Android」フォルダに表示されていることを確認してください(図5)。
次に、Javaクラスを呼び出すためのC#用ヘルパークラスのファイル「JavaVM.cs」「JNI.cs」を「Plugins」フォルダに登録します(図6)。
以上でJavaクラスを呼び出すための準備は完了です。後は、クラスを呼び出して関数を実行するスクリプトを記述します。
C#スクリプトを書いて実行
C#スクリプトファイルとして「CallJavaCode.cs」をルートフォルダに作成し、エディタで開きます。
using UnityEngine; using System .Collections; using System .Runtime.InteropServices; using System ; public class CallJavaCode : MonoBehaviour { private IntPtr HelloWorldJavaClass; private int ptr_getStaticHello; private int ptr_getHello; private string announceString; void Start (){ // attach our thread to the java vm; obviously the main thread is already attached but this is good practice //……[1] JavaVM.AttachCurrentThread(); // create reference of HelloWorldJava class //……[2] IntPtr cls_HelloWorldJavaClass = JNI.FindClass("com/example/java/helloworld/HelloWorldJava"); int mid_HelloWorldJavaClass = JNI.GetMethodID(cls_HelloWorldJavaClass, "", "()V"); IntPtr obj_HelloWorldJavaClass = JNI.NewObject(cls_HelloWorldJavaClass, mid_HelloWorldJavaClass); HelloWorldJavaClass = JNI.NewGlobalRef(obj_HelloWorldJavaClass); // create references of HelloWorldJava class methods//……[3] ptr_getStaticHello = JNI.GetStaticMethodID(cls_HelloWorldJavaClass, "getStaticHello", "()Ljava/lang/String;"); ptr_getHello = JNI.GetMethodID(cls_HelloWorldJavaClass, "getHello", "()Ljava/lang/String;"); announceString = "Sample Started"; } //getStaticHello() //……[4] private String getStaticHello(){ IntPtr str_GetStaticHello = JNI.CallStaticObjectMethod(HelloWorldJavaClass, ptr_getStaticHello); Debug.Log ("str_GetStaticHello = " + str_GetStaticHello); IntPtr stringPtr = JNI.GetStringUTFChars(str_GetStaticHello, 0); Debug.Log ("stringPtr = " + stringPtr); String staticHello = Marshal.PtrToStringAnsi(stringPtr); JNI.ReleaseStringUTFChars(str_GetStaticHello, stringPtr); Debug.Log ("return value is = " + staticHello); return staticHello; } //getHello()//……[5] private string getHello(){ IntPtr str_GetHello = JNI.CallObjectMethod(HelloWorldJavaClass, ptr_getHello); Debug.Log ("str_GetHello = " + str_GetHello); IntPtr stringPtr = JNI.GetStringUTFChars(str_GetHello, 0); Debug.Log ("stringPtr = " + stringPtr); String hello = Marshal.PtrToStringAnsi(stringPtr); JNI.ReleaseStringUTFChars(str_GetHello, stringPtr); Debug.Log ("return value is = " + hello); return hello; } void OnGUI (){ resetButton(); if(makeButton("getStaticHello")){ string message = "Message From HelloWorldJava(getStaticHello()): " + getStaticHello(); //……[6] announceString = message; _log(message); } if(makeButton("getHello")){ string message = "Message From HelloWorldJava(getHello()): " + getHello(); //……[7] announceString = message; _log(message); } showMessage(announceString); } int buttonX = 0; int buttonY = 0; void resetButton(){ buttonX = 0; buttonY = 0; } void showMessage(string message){ int labelW = 400; int labelH = 50; GUI.Label(new Rect(10,80,labelW,labelH), message); } bool makeButton(string label){ int buttonW = 150; int buttonH = 50; int buttonsInRow = 2; bool b = GUI.Button(new Rect(10+buttonX*(buttonW+5), 160+buttonY*(buttonH+5), buttonW, buttonH), label); buttonX++; if(buttonX==buttonsInRow){ buttonX = 0; buttonY++; } return b; } void _log(string logstring){ Debug.Log (logstring); } }
[1]では、JavaVMにスレッドをアタッチし、JNIアクセスができる状態にしています。
[2]では、HelloWorldJavaクラスを探し、新しいオブジェクトとして生成します。JNI.FindClass()に今回利用するJavaクラス「com.example.java.helloworld.HelloWorldJava」を指定してアクセス先クラスを指定しています。
[3]では、[2]で取得したクラスオブジェクトから参照したい関数(「getStaticHello()」「getHello()」)へのポインタを引き出します。静的メソッドに対しては、「GetStaticMethodID()」関数、インスタンスメソッドに対しては「GetMethodID()」関数で取得できます。
[4]は、「getStaticHello()」関数の呼び出しと、取得した文字列データをUnityで扱えるString型への変換を行う内部関数です。[5]では、[4]と同じ処理を「getHello()」関数に対して行っています。
[6]では、ボタンをクリックした際に「getStaticHello()」で取得した文字列を出力します。
[7]では、ボタンをクリックした際に「getHello()」で取得した文字列を出力します。
以上で、Javaで書いたクラスへUnityからアクセスできました。
さらに、ネイティブ部分をカスタマイズしていきたい場合は、Unityを実行しているActivity自体のカスタマイズも可能です。
まず、その方法を説明する前に、UnityがAndroid上でどのように動作しているかを簡単に説明します。
UnityはAndroid上で、どのように動作しているのか
Unityによってビルドされたアプリは、開発者が開発するUnityプログラム自体と、そのプログラムを実行させる「UnityPlayer」と呼ばれる実行プログラムから構成されています。UnityPlayer自体が前回簡単に紹介したように複数のOSに向けて提供されており、結果Unityアプリケーションが複数のOS上で動作します
UnityがAndroid用にアプリをビルドする際、下記のようにプログラムが構成されます。
APK内に「UnityPlayerActivity」というActivityを継承したクラスが1つ組み込まれ、その中でUnityPlayerクラスがロードされ、その上で開発者が作成するUnityコンテンツが再生されます。
つまり、Android Frameworkから見ると、通常のAndroidアプリのように、「UnityPlayerActivity」という名前のActivityが実行され、Android Frameworkとの間でライフサイクルマネジメントが行われています。
UnityPlayerActivityクラスをカスタマイズ
Unityでは、このUnityPlayerActivityクラスのソースコードを公開しており、開発者がActivityにカスタマイズを加えることが可能です。UnityPlayerActivityのソースコード自体は下記のパスで確認できます。
/Applications/Unity/Unity.app/Contents/PlaybackEngines/AndroidPlayer/src/com/unity3d/player/UnityPlayerActivity.java
カスタマイズでできる、あんなこと、こんなこと
このUnityPlayerActivityクラスを継承したクラスを実装、あるいは同等のクラスを実装し、差し替えてビルドすることで例えば、以下のように振る舞いをいろいろカスタマイズ可能になります。
- Activity自体にイベントハンドラを追加
- Activityの構成を変更
- 他のActivityからIntentを受け取る
- 他のActivityの呼び出しし、終了時のコールバックの受け取り
- 「Activityを追加したい」などの要求があり、ActivityクラスやAndroidManifest.xmlを改変
UnityでAndroidのActivityを拡張するには
Unityでは、デフォルトで追加・ロードされるUnityPlayerActivityの差し替えやAndroidManifest.xmlの変更を行える方法を提供しています。
次ページではEclipseとUnityを用いた場合の手順について解説します。Unityのサイトでは「Unity - Integrating Unity with Eclipse」で紹介されています。
手順は大まかに下記の通りです(下記リストはインデックスになっています)。
Copyright © ITmedia, Inc. All Rights Reserved.