はじめに

UnityでMLKitを使う記事を書いていたら、Androidプラグインの準備の段階だけで1つ記事になりそうなくらいだったので分割しました。
UnityでMLKitを使う記事は次回にしたいと思います。

本記事は「普段はUnityで開発しているけれど、一部Androidプラグインでの実装が必要になった」くらいの人向けです。
プラグインに絡まない技術的な説明は省いています。

できるだけシンプルなプラグインを例に進めたいので、今回は、四則演算を行うプラグインを作っていきます。
Java側で「前回の計算結果(初期値 = 0)」と「メソッドの引数」を使って四則演算をし、その結果をUnityで表示するアプリを作ります。

開発環境

  • Unity 2019.3.5f1
  • Android Studio 3.6.1
  • macOS Catalina 10.15.2
  • Android 10

プラグインの準備

実装に取り掛かる前にプラグインを作るためのプロジェクトを準備します。

プロジェクトを作成する

Android Studioでプロジェクトを作成します。

今回はJavaで制作します。

モジュールを作成する

プロジェクトができたので、次にライブラリ用のモジュールを作成します。

これでcalculationというモジュールができました。
ここから先はcalculationモジュールに機能を実装していきます。calculationモジュールは動作確認もUnityプロジェクトで試すので、元から作られているappというモジュールは消します。

Unityクラスライブラリを追加する

Unityクラスライブラリを追加して、Unity関連のAPIを使える様にします。

Unityクラスライブラリは、Unityアプリケーション(MacならUnity.app、WindowsならUnity.exe)が格納されているフォルダから見て
/PlaybackEngines/AndroidPlayer/Variations/mono/Release/Classes/classes.jar
にあります。

このclasses.jarをモジュール内のlibsフォルダにコピー&ペーストします。

これでUnity関連のAPIをJavaで使うことができる様になりましたが、classes.jarをプラグインに含めたままにしてしまうと、Unity側のビルドでエラーになってしまうので、classes.jarをJavaコードのコンパイルでのみ使用する様にします。

モジュールレベルのbuild.gradleを以下の様に変更します。

apply plugin: 'com.android.library'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.3"

    defaultConfig {
        minSdkVersion 29
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        consumerProguardFiles 'consumer-rules.pro'
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

}

dependencies {
    // implementation fileTree(dir: 'libs', include: ['*.jar'])
    //   ↓ 変更したのはここだけ
    compileOnly fileTree(dir: 'libs', include: ['*.jar'])

    implementation 'androidx.appcompat:appcompat:1.1.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}

ここまでできたら右上のSync Nowをクリックして、Gradleの変更を適用します。

プラグイン側に四則演算を実装

これでプラグインを作る準備ができました。
ここから四則演算を実装していきます。

Javaクラスを作成する

四則演算を書くJavaクラスを作成します。

コンストラクタ

コンストラクタで初期化処理を行います。

/**
 * 前回の計算結果
 */
private float _lastResult = 0;

/**
 * コンストラクタ
 */
public NativeCalculator()
{
    _lastResult = 0;
}

足し算、引き算

まずは足し算と引き算を実装していきます。

足し算、引き算はすぐに終わる処理の実装を想定して、計算結果を戻り値でC#に返します。

/**
 * 足す
 * @param num 足す値
 * @return 計算結果
 */
public float Add(int num)
{
    _lastResult += num;
    return _lastResult;
}

/**
 * 引く
 * @param num 引く値
 * @return 計算結果
 */
public float Subtract(int num)
{
    _lastResult -= num;
    return _lastResult;
}

掛け算、割り算

次に、掛け算と割り算を実装していきます。

掛け算、割り算は時間がかかる処理の実装を想定して、計算が終わったらUnitySendMessageを使って計算結果をC#に通知します。

UnitySendMessageで JavaからC#のメソッドを呼び出すには、呼び出し先のGameObject名メソッド名が必要になります。
今回は、GameObject名はコンストラクタで受け取り、メソッド名はメソッドの引数として受け取ることにします。

また、割り算は引数(割る値)が0だった時は計算ができないので、すぐにエラーを返すようにします。

/**
 * Unity側のGameObject名
 */
private String _gameObjectName;

/**
 * コンストラクタ
 * @param gameObjectName Unity側のGameObject名
 */
public Calculator(String gameObjectName)
{
    _lastResult = 0;
    _gameObjectName = gameObjectName;
}

/**
 * 掛ける
 * @param num 掛ける値
 * @param onComplete 計算結果を返すメソッド名
 */
public void Multiply(int num, String onComplete)
{
    _lastResult *= num;
    UnityPlayer.UnitySendMessage(_gameObjectName, onComplete, String.valueOf(_lastResult));
}

/**
 * 割る
 * @param num 割る値
 * @param onComplete 計算結果を返すメソッド名
 * @throws Exception 0除算の例外
 */
public void Divide(int num, String onComplete) throws Exception
{
    if(num == 0)
    {
        throw new Exception("0では割れません。");
    }
    _lastResult /= num;
    UnityPlayer.UnitySendMessage(_gameObjectName, onComplete, String.valueOf(_lastResult));
}

プラグインをビルドする

完成したプラグインをAARファイルとしてビルドします。

ビルドが完了すると、
/{プロジェクトフォルダ}/ {モジュールフォルダ}/build/outputs/aar/{AARファイル}
にAARファイルが生成されます。

Unity側に呼び出し処理と表示処理を実装する

プラグイン側の実装が完了しました。
次は、Unity側の実装に入っていきます。

Unityのプロジェクト作成とスクリプト作成の説明は省略します。

プラグインをUnityにインポートする

ビルドしたAARファイルをUnityにインポートします。

UnityエディタでAssets/Plugins/Androidとなるようにフォルダを作成し、Androidフォルダの中にAARファイルをドラッグ&ドロップします。

プラグイン側のクラスのインスタンスを生成する

プラグイン側に実装した四則演算クラスをC#から利用するために、AndroidJavaObjectのインスタンスを生成します。

AndroidJavaObjectのコンストラクタは、第1引数に{パッケージ名}.{クラス名}、第2引数以降にコンストラクタの引数となっています。

また、OnDestroyで解放処理も行っています。

/// <summary>
/// プラグイン側の計算クラスのインスタンス
/// </summary>
private AndroidJavaObject _calculator;

/// <summary>
/// プラグインのパッケージ名
/// </summary>
private const string PLUGIN_PACKAGE_NAME = "com.gaprot.calculation";  // 要変更

/// <summary>
/// Javaの計算クラス名
/// </summary>
private const string JAVA_CLASS_NAME = "NativeCalculator";  // 要変更

/// <summary>
/// Start
/// </summary>
private void Start()
{
    // インスタンス生成
    _calculator = new AndroidJavaObject($"{PLUGIN_PACKAGE_NAME}.{JAVA_CLASS_NAME}", ORIGINAL_VALUE, gameObject.name);
}

/// <summary>
/// OnDestroy
/// </summary>
private void OnDestroy()
{
    // 解放
    _calculator?.Dispose();
    _calculator = null;
}

足し算、引き算

Javaクラスのインスタンスができたので、そのJavaクラスが持つメソッドをC#から呼び出すことができるようになりました。

まずは、足し算と引き算のメソッドを呼び出してみます。
AndroidJavaObjectのメンバーメソッドは、Call<戻り値>(メソッド名, 引数1, 引数2, … …)で呼び出すことができます。

/// <summary>
/// プラグイン側の足し算メソッド名
/// </summary>
private const string ADD_METHOD = "Add";

/// <summary>
/// プラグイン側の引き算メソッド名
/// </summary>
private const string SUBTRACT_METHOD = "Subtract";

/// <summary>
/// 足す
/// </summary>
/// <param name="num">足す値</param>
private void add(int num)
{
    var result = _calculator.Call<float>(ADD_METHOD, num);  // 計算結果
}

/// <summary>
/// 引く
/// </summary>
/// <param name="num">引く値</param>
private void subtract(int num)
{
    var result = _calculator.Call<float>(SUBTRACT_METHOD, num);  // 計算結果
}

ここで一旦プラグインを使ってみる

「足す」、「引く」ボタンを押すとドロップダウンで選択している値を引数として、プラグイン側のメソッドを呼び出すようにしました。

掛け算、割り算

次は、掛け算と割り算のメソッド呼び出しを実装します。
足し算、割り算と違い戻り値のないメソッドなので、呼び出し方はCall(メソッド名, 引数1, 引数2, … …)となります。

また、計算結果を受け取るメソッドも必要になります。
UnitySendMessageでは文字列しか送れないので、数値として使いたい場合はC#側でパースが必要です。

割り算は0除算のエラーが返ってくるので呼び出し部分をtry/catchします。

/// <summary>
/// プラグイン側の掛け算メソッド名
/// </summary>
private const string MULTIPLY_METHOD = "Multiply";

/// <summary>
/// プラグイン側の割り算メソッド名
/// </summary>
private const string DIVIDE_METHOD = "Divide";

/// <summary>
/// 掛ける
/// </summary>
/// <param name="num">掛ける値</param>
private void multiply(int num)
{
    _calculator.Call(MULTIPLY_METHOD, num, "onCompleteCalc");
}

/// <summary>
/// 割る
/// </summary>
/// <param name="num">割る値</param>
private void divide(int num)
{
    try
    {
        _calculator.Call(DIVIDE_METHOD, num, "onCompleteCalc");
    }
    catch (Exception e)
    {
        _resultText.text += "\n" + e.Message;
    }
}

/// <summary>
/// 計算結果を受け取る
/// </summary>
/// <param name="result">計算結果</param>
private void onCompleteCalc(string result)
{
    var num = float.Parse(result);  // 計算結果
}

完成

完成品がこちらです。0除算のエラーもしっかり拾うことができています。

おわりに

こうやってまとめてみると、手間はかかるけど難しいことはほとんど無いなー、という感じです。

Unityで開発していると、C#では使うことが出来ないライブラリを使いたくなる場面に出会す事があります。その時にAndroidプラグインを作るという選択肢が取れると出来る事が一気に広がるので、ぜひ挑戦してみてください。
特にJavaはC#とかなり近い言語なので入りやすいと思います。

次回『Androidプラグインの応用編(MLKitによる顔検出)』もよろしくお願いします。



ギャップロを運営しているアップフロンティア株式会社では、一緒に働いてくれる仲間を随時、募集しています。 興味がある!一緒に働いてみたい!という方は下記よりご応募お待ちしております。
採用情報をみる