UnityのAndroidJavaProxyってなんぞ
検索してもなかなか資料がありませんが、簡単に言えば、
JavaのinterfaceをC#で実装ができるものです。
最近日本語マニュアルに訳されたものがでましたね。
Unityマニュアル:AndroidJavaProxy
2015/02/26 マニュアルのC#ソース間違ってるので正しいはずのもの載せておきます
using UnityEngine;
using System.Collections;
public class SelectedDate : MonoBehaviour {
public static Date date = System.DateTime.Now;
}
public class DateCallback : AndroidJavaProxy {
public DateCallback()
:base("android.app.DatePickerDialog$OnDateSetListener")
{
}
void onDateSet(AndroidJavaObject view, int year, int monthOfYear, int dayOfMonth) {
SelectedDate.date = new Date(year, monthOfYear + 1, dayOfMonth);
}
}
public class ExampleClass : MonoBehaviour {
void OnGUI() {
if (GUI.Button(new Rect(10, 10, 450, 100), String.Format("{0:yyyy-MM-dd}", SelectedDate.date))) {
AndroidJavaObject activity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity");
activity.Call(
"runOnUiThread",
AndroidJavaRunnable(
new AndroidJavaObject(
"android.app.DatePickerDialog",
activity,
new DateCallback(),
SelectedDate.date.Year,
SelectedDate.date.Month - 1,
SelectedDate.date.Day
).Call("show");
)
);
}
}
}
思ったよりわかりづらかった。
ActivityのListenerを作る
まず、プラグインとなるjarを作ります。
Activityをつくるので、AndroidManifest.xmlも用意しないといけないですが、説明は省略させていただきます。
public interface ExActivityListener
{
public void onRestart();
public void onStart();
public void onResume();
public void onPause();
public void onStop();
public void onActivityResult(int requestCode, int resultCode, Intent data);
}
public class ExActivity extends com.unity3d.player.UnityPlayerActivity
{
private ExActivityListener listener;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
}
public void setListener(ExActivityListener listener)
{
this.listener = listener;
}
@Override
public void onRestart()
{
super.onRestart();
if(listener != null) listener.onRestart();
}
@Override
public void onStart()
{
super.onStart();
if(listener != null) listener.onStart();
}
@Override
public void onResume()
{
super.onResume();
if(listener != null) listener.onResume();
}
@Override
public void onPause()
{
super.onPause();
if(listener != null) listener.onPause();
}
@Override
public void onStop()
{
if(listener != null) listener.onStop();
super.onStop();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
if(listener != null) listener.onActivityResult(requestCode, resultCode, data);
}
}
こんな感じに、Listenerをセットする関数を用意し、
それぞれでListenerの対応した関数を呼びます。
次に、C#からListenerをセットし、コールバックを受け取れるようにします。
その時に使用するのが、AndroidJavaProxy
です。
public class Hoge : MonoBehavior
{
public class ActivityListener : AndroidJavaProxy
{
public ActivityListener()
: base("com.hoge.ExActivityListener")
{
}
public void onRestart()
{
}
public void onStart()
{
}
public void onResume()
{
}
public void onPause()
{
}
public void onStop()
{
}
public void onActivityResult(int requestCode, int resultCode, AndroidJavaObject data)
{
}
}
void Awake()
{
AndroidJavaObject activity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity");
activity.Call("setListener", new ActivityListener());
}
}
C#で作るものは同関数名で、引数もそのまま対応するものにします。
javaのクラスが引数の場合、AndroidJavaObject
を指定します。
currentActivityを取得し、Listenerをセットして完成です。
便利になること
いくつかプラグインを入れると、onActivityResult
で処理を入れないといけないことが多々あります。
そのたび、プラグイン追加して、呼び出すjarファイル更新して・・・と手間がかかります。
これならUnity上で、onActivityResult
を使用するプラグインも追加が容易になります。
この例ではActivityですが、引数がそのまま使用出来るので、ライブラリのコールバックとしても使いやすいです。
UnitySendMessageのように、文字列1つだけの引数で悩む必要もなくなります。
デメリット
javaコードから呼ばれるListenerは、java側でコールされたスレッドになるので、ほとんどの場合、UnityAPIが使用出来ません。
使用する場合、一時的にAction等持たせて、Updateで呼ぶ等が必要です。
その場合はロック処理もしておくといいでしょう。
onPause、onResumeは
void OnApplicationPause(bool isPause)
でもいい気はしますが、スレッドの違いでもしかしたら何かに使えるかもしれません。