UnityとAndroidネイティブの連携:UnityPlayerNativeActivityの拡張Activityに定義したstaticなメソッドを呼び出す

UnityとAndroidネイティブの連携 の投稿一覧

先日の投稿でUnityからAndroidプラグインとして、JavaClassの呼び出しを検証しました。
今回はUnityPlayerNativeActivityを拡張、呼び出す検証をします。

環境

  • OSX Yosemite v10.10.4
  • Unity v5.1.2f1
  • AndroidStudio v1.3.1
  • 検証端末 Nexus7(2012) v5.1.1

Androidプラグインを生成するまで

  1. 空のプロジェクトを作成
  2. build.gradleの編集
  3. gradle.propertiesの編集
  4. javaクラスの作成
  5. jar出力
空のプロジェクトを作成

AndroidStudioで、[Add No Activity]を選択し空のプロジェクトを作成します。
モジュール名はtestlib2に変更しておきます。

build.gradleの編集
JavaLibraryモジュールの作成と異なり、build.gradleは初期値が異なることに注意。

.jarを2つ追加
AndroidネイティブからUnityPlayerActivityを使えるようにするためにclasses.jarを、
Androidの機能を使えるようにするためandroid.jarを、
JavaLibraryのbuild.gradleを開いてdependenciesに追記します。

apply plugin: 'com.android.library'

android {
    compileSdkVersion 22
    buildToolsVersion "22.0.1"

    defaultConfig {
        minSdkVersion 22
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile files('/Applications/Unity/Unity.app/Contents/PlaybackEngines/AndroidPlayer/release/bin/classes.jar')  /*追記する行,classes.jarを追加する*/
    compile files('/Users/ユーザ名/Library/Android/sdk/platforms/android-22/android.jar')  /*追記する行,android.jarを追加する*/
}
この記事で書いた方法で、直接build.gradleファイルに追記しなくてもAndroidStudio上から直接パスを指定して追加できるかと思ったものの、できなかった。
この方法を取るには、プロジェクトに作成したlibsディレクトリに2つの.jarファイルを含めておけばできるようだ。

gradleタスクを追記
ファイルの一番下に追記する。

task clearJar(type: Delete) {
    delete 'build/libs/' + JAR_NAME
}
task makeJar(type: Copy) {
    from('build/intermediates/bundles/release/')
    into('release/')
    include('classes.jar')
    rename('classes.jar', JAR_NAME)
}
makeJar.dependsOn(clearJar, build)
Unityから動作させる上で、コーディング上は生成されるjarの名前を気にする必要は無いと思う。なので今回はjarファイル名やバージョンをビルド時に自動で変更挿入する行について省略している。
この点についてはjar生成時にjar名とバージョンコードをgradleから定義するの投稿を参照してください。

追記後、AndroidStudioのSync Project with Gradle Filesを実行しておく。
syncgradle

gradle.propertiesの編集
JAR_NAME=testlib2.jar

JAR=NAMEに入る文言は、そのまま生成されるjarファイルの名称になる。

build.gradleに記述するjar.baseNameとどちらが優先されるか未検証。
javaクラスの作成

Androidプラグインとなるjavaクラスを作成します。
前回同様に確認用として、toast表示機能のみを付けています。

package com.example;

import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;

import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerNativeActivity;

public class AndroidNativeActivityTest extends UnityPlayerNativeActivity {

    @Override
    protected void onCreate(Bundle bundle) {
        super.onCreate(bundle);
    }
    public static void showToast() {
        final Activity activity = UnityPlayer.currentActivity;
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(activity, "successful2!", Toast.LENGTH_LONG).show();
            }
        });
    }
}
jar出力

AndroidStudioのTerminalを開き、プロジェクトのrootに移動します。
次にjarを出力します。

./gradlew testlib2:clean testlib2:assembleDebug testlib2:makeJar

TerminalウィンドウにBUILD SUCCESSFULと表示されれば、jar出力は成功です。
testlib2/release直下にtestlib2.jarが出力されています。

AndroidStudioでの操作は終わり、ここからはUnityの操作に移ります。

Unityから生成したAndroidプラグインを呼び出すまで

ここからはJavaClassモジュールを用いた方法とあまり違いがありません。

  1. 空のプロジェクトを作成
  2. jarファイルの置き場となるディレクトリを作成する
  3. プラグインを呼び出すC#スクリプトを作成する
  4. 空のGameObjectを作成し、C#スクリプトをアタッチする
  5. ビルド、実機で実行できるか確認
空のプロジェクトを作成

Unityの新規プロジェクトを作成します。

jarファイルの置き場となるディレクトリを作成する

Assets/Plugins/Android/直下に、先ほど作成したtestlib2.jarファイルを配置します。
プロジェクトを新規作成した段階ではこのディレクトリは存在しないので、自分で作成します。
今回は折角なので、UnityとAndroidネイティブの連携:JavaClassの呼び出しで作成したtestlib.jarとともに、検証してみます。
testlib_testlib2

プラグインを呼び出すC#スクリプトを作成する
using UnityEngine;
using System.Collections;

public class Caller2 : MonoBehaviour {

	private static string JAVA_CLASS_NAME = "com.example.AndroidNativeActivityTest";
	private static string JAVA_METHOD_NAME = "showToast";

	private static string COROUTINES_NAME = "sleep";
	private static int WAIT_SECOND = 5;
	
	// Use this for initialization
	void Start () { 
		StartCoroutine(COROUTINES_NAME);
	}
	
	// Update is called once per frame
	void Update () {	
	}

	//「コルーチン」で呼び出すメソッド
	IEnumerator sleep(){
		yield return new WaitForSeconds(WAIT_SECOND);
		using ( AndroidJavaClass plugin = new AndroidJavaClass(JAVA_CLASS_NAME)){
			plugin.CallStatic(JAVA_METHOD_NAME);
		}
	}
}

コルーチンを使い、GameObjectとStartメソッドが呼ばれてから5秒後にtestlib2.jarで定義されているToast.makeText()が走ります。

空のGameObjectを作成し、C#スクリプトをアタッチする

普通にCreateEmptyして生成されたGameObjectに、先ほど作成したC#スクリプトをアタッチするだけ。

ビルド、実機で実行できるか確認

devicess1 devicess2
toast表示が正常に動いた。1枚目が表示され、数秒後に2枚目が表示される。

トーストの表示は前述のToast.LENGTH_SHORTだと、2秒経つと消えてしまう。Unityのスプラッシュロゴが表示されている間に消えてしまっていることもあるので、その場合は表示する秒数を増やそうと思ったけど、どうも無理っぽい。なのでtestlib2ではコルーチンを使用しています。
UnityEditor上では検証できない。
実行しようとしても、”Exception: JNI: Init’d AndroidJavaClass with null ptr!”のエラーとなる。

参考サイト
http://devdevdev.hatenablog.com/entry/2015/03/03/020735