次は、Unity側の作業です。
まず、[Project]ウィンドウにおいて、先ほど追加したHelloWorldJava.jarとlibjni.soが「/Plugins/Android」フォルダに表示されていることを確認してください(図5)。
次に、Javaクラスを呼び出すためのC#用ヘルパークラスのファイル「JavaVM.cs」「JNI.cs」を「Plugins」フォルダに登録します(図6)。
以上でJavaクラスを呼び出すための準備は完了です。後は、クラスを呼び出して関数を実行するスクリプトを記述します。
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によってビルドされたアプリは、開発者が開発するUnityプログラム自体と、そのプログラムを実行させる「UnityPlayer」と呼ばれる実行プログラムから構成されています。UnityPlayer自体が前回簡単に紹介したように複数のOSに向けて提供されており、結果Unityアプリケーションが複数のOS上で動作します
UnityがAndroid用にアプリをビルドする際、下記のようにプログラムが構成されます。
APK内に「UnityPlayerActivity」というActivityを継承したクラスが1つ組み込まれ、その中でUnityPlayerクラスがロードされ、その上で開発者が作成するUnityコンテンツが再生されます。
つまり、Android Frameworkから見ると、通常のAndroidアプリのように、「UnityPlayerActivity」という名前のActivityが実行され、Android Frameworkとの間でライフサイクルマネジメントが行われています。
Unityでは、このUnityPlayerActivityクラスのソースコードを公開しており、開発者がActivityにカスタマイズを加えることが可能です。UnityPlayerActivityのソースコード自体は下記のパスで確認できます。
/Applications/Unity/Unity.app/Contents/PlaybackEngines/AndroidPlayer/src/com/unity3d/player/UnityPlayerActivity.java
このUnityPlayerActivityクラスを継承したクラスを実装、あるいは同等のクラスを実装し、差し替えてビルドすることで例えば、以下のように振る舞いをいろいろカスタマイズ可能になります。
Unityでは、デフォルトで追加・ロードされるUnityPlayerActivityの差し替えやAndroidManifest.xmlの変更を行える方法を提供しています。
次ページではEclipseとUnityを用いた場合の手順について解説します。Unityのサイトでは「Unity - Integrating Unity with Eclipse」で紹介されています。
手順は大まかに下記の通りです(下記リストはインデックスになっています)。
Copyright © ITmedia, Inc. All Rights Reserved.