Android側プラグインの構成整備
Unityプロジェクトからネイティブ機能へアクセスするには、専用のライブラリモジュールを作成する必要があります。Android Studioにおいて既存のApplicationモジュールとは別にLibraryタイプModuleを追加し、パッケージネームスペースを区別しておきます。
引き続き、Unityランタイムから直接呼び出し可能なJavaクラスを定義します。ここではAndroid側のウィンドウコンテキスト取得とユーザー向けUIフィードバック表示を一元化するマネージャーを実装します。
package com.game.plugin.androidbridge;
import android.app.Activity;
import android.os.Handler;
import android.os.Looper;
import android.widget.Toast;
public class AndroidBridgeManager {
private static volatile Activity unityActivityRef;
/**
* Unityプロセスが保持するアクティビティ参照を取得
*/
public Activity getUnityContext() {
if (unityActivityRef == null) {
try {
Class> targetClass = Class.forName("com.unity3d.player.UnityPlayer");
java.lang.reflect.Field activityField = targetClass.getDeclaredField("currentActivity");
unityActivityRef = (Activity) activityField.get(null);
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
throw new IllegalStateException("Unity Contextの初期化に失敗しました", e);
}
}
return unityActivityRef;
}
/**
* メインスレッドへディスパッチしてトースト表示を実施
* @param userMessage 表示対象の文字列
* @return 実行ステータス
*/
public boolean dispatchNativeAlert(String userMessage) {
Activity ctx = getUnityContext();
if (ctx != null && !ctx.isFinishing()) {
postToMainThread(() ->
Toast.makeText(ctx, userMessage, Toast.LENGTH_SHORT).show()
);
// Android→Unityへデータを返す場合はこの位置に
// UnityPlayer.UnitySendMessage("ManagerObject", "ReceiveCallback", userMessage);
return true;
}
return false;
}
private void postToMainThread(Runnable runnable) {
new Handler(Looper.getMainLooper()).post(runnable);
}
}
AARアーカイブのビルドと設置
ソースコードの修正が完了したら、Gradleビルドツール経由でパッケージファイルを生成します。モジュール名の設定画面から「Make Library」を実行し、出力ディレクトリ(通常は build/outputs/aar)内に拡張子.aarのファイルが作成されることを確認します。生成されたバイナリは、Unityプロジェクトの Assets/Plugins/Android フォルダ配下に配置してください。配置後はUnityのエンジンが自動的にマニフェストのマージとJNIロードを行います。
C#ランタイムからの呼び出し処理
Unity環境では AndroidJavaObject クラスを用いてメモリ内ネイティブアドレスとやり取りします。UIアクションを起点としてプラグイン関数をトリガーするコントローラーの実装例を以下に示します。
using UnityEngine;
using UnityEngine.UI;
public class BridgeConnector : MonoBehaviour
{
private const string NAMESPACE_PATH = "com.game.plugin.androidbridge";
private const string BRIDGE_CLASS = "AndroidBridgeManager";
private AndroidJavaObject nativeWrapper;
private void Awake()
{
// ネイティブクラスのインスタンスをヒープ上に確保
nativeWrapper = new AndroidJavaObject(NAMESPACE_PATH + "." + BRIDGE_CLASS);
// 簡易的なUIフック(Scene上にButtonが存在することを想定)
Button triggerBtn = FindObjectOfType<Button>();
if (triggerBtn != null)
{
triggerBtn.onClick.AddListener(SendCommandToNative);
}
}
private void SendCommandToNative()
{
Debug.Log("[CLR] ネイティブ層へコマンド送信開始");
bool executionResult = nativeWrapper.Call<bool>("dispatchNativeAlert", "Androidレイヤーより応答中");
if (executionResult)
{
Debug.Log("[CLR] ハンドシェイク完了");
}
else
{
Debug.LogWarning("[CLR] ネイティブ呼び出しが拒否されました");
}
}
/// <summary>
/// Java側から送信されたペイロードを受信する登録メソッド
/// </summary>
public void ReceiveNativePayload(string data)
{
Debug.LogFormat("[CLR] 着信データ解析: {0}", data);
}
}
ターゲットデバイスでの検証手順
Unity Editorのプレイモードまたは実際のAndroid端末へのビルド展開を行い、実機上での動作を検証します。画面の操作イベント発生時に指定したメッセージがデバイスのオーバーレイ通知としてレンダリングされ、ConsoleビューにC#側のデバッグログが順次出力されれば、クロスプラットフォーム通信経路は正常確立されています。パーミッションの動的取得や非同期データのシリアライズを伴うケースでは、各OSのライフサイクル規約に合わせて拡張を行ってください。