https://www.jianshu.com/p/b5e3cfcdf081
そのような電気へのアクセス、無線LANステータスとしてAndroidオペレーティングシステムの機能へのアクセスを必要とユニティ・プロジェクトは、我々は団結Androidの起動する必要がBroadcastReceiver
リスニング状態を、ユニティ・インターフェースにステータス更新通知後。これは、Android Unityとお互いに呼ばれるメカニズムを必要とし、直感的にC#とJavaメソッドが相互に呼び出すことがわかります。
そこユニティとAndroidは、接続する2つの方法がありますが、それは二つのプロジェクトを接続する方法になる、二つのプロジェクトを作成し、開発環境を必要とする2つのプロジェクトで同時にお互いを呼び出す必要があります:
- ユニティプロジェクト、ユニティ生成APKを構築するための最終用途機構にコピーされたAndroidのプロジェクトジェネレータAAR / jarファイル、。
- ユニティプロジェクトは、すべてのコンテンツとコードのAndroidのGradleへのプロジェクト、そしてオープンのAndroid Studioプロジェクトの開発、最終用途のAndroid StudioのパッケージAPKをエクスポートされます。
両方の長所と短所を比較します。
瓶/ AARライブラリを使用してユニティ | 輸出Gradleのユニティプロジェクト | |
---|---|---|
Unityと依存性のAndroid | Unityは唯一のAndroidライブラリを依存している、Segcieanedは、ファイルのみライブラリファイルを同期する必要があります | Androidはユニティ輸出シーンデータを依存している、あまりにも多くのファイルを同期する必要があります |
開発とデバッグスピード | Androidのライブラリファイルが比較的小さい、速い試運転 | ユニティプロジェクト大、スローシンクロ、デバッグサイクルが長いです |
メカニズムを構築 | 日食コンパイラのAndroidプロジェクトに似た組み込みのメカニズムのAndroidビルドユニティ、 | AndroidのメーカーのGradle |
柔軟性を構築 | カスタマイズの悪い、ではない深さは、ライブラリを明示的に完全に依存して依存しているユニティプロジェクトにコピーする必要があります | 非常に自由、あなたは最新のAndroidビルド・メカニズムを使用することができます |
APKをパッケージ化する方法 | 直接包装用ユニティビルドのメカニズム | Androidのスタジオパッケージ |
プロジェクトはユニティで、特に大規模なプロジェクト、あまりにも多くのエクスポートのユニティ事業費であるため、このプロジェクトでは、使用される最初のメソッドです。しかし、また、ライブラリファイルの依存関係の問題が発生しますが、原因の依存関係には多くないが、手動で解決することができます。以下は、ソリューションです。
- タスクのGradleを実行して
dependencies
、ウィンドウを「Gradleの、プロジェクト」プロジェクトのターゲットディレクトリにヘルプを見つけることができ、このタスクは依存関係ツリー構造を出力します。 - すべての依存関係は、別途ユニティプロジェクトに、ローカルにダウンロード。
レベルにあまり依存している場合、この2つのステップから分かるように、数が比較的小さく、許容可能であるが、存在する場合、深い依存の多数は特に問題となります。
ユニティコールアンドロイド
ユニティ公式ドキュメントプラグインの方法を経由してJavaコードを呼び出す必要がありますが、実際には任意のプラグインを導入する必要はJavaコードを呼び出すことはできません。ちょうどその時、彼は瓶やAARユニティプロジェクトを配置するとC#を経由して、その内容にアクセスする必要がある、通常の状況下で包装されているライブラリを呼び出す必要があります。
AARファイルの瓶またはユニティの下の任意のディレクトリに配置することができますが、管理の都合上、中に配置されているAssets/Plugins/Android
ディレクトリ。
C#のコールJavaメソッド、Javaフィールドへのアクセス
C#Javaは、基本原理は、JNI呼び出しを使用することで、Unityは非常に便利なインタフェースを提供している呼び出します。
- オブジェクトを作成します。使用してC#の
AndroidJavaObject
クラスは、Javaオブジェクトをカプセル化し、新しいAndroidJavaObject
コンストラクタ対応するJavaを呼び出すに対応する対象物を。C#の可変引数リストは任意の数のパラメータは、Javaオブジェクトのコンストラクタに渡すことができ、意味します。
// 第一个参数是 Java 类的完整包名,剩下的其他参数会传递给构造方法。
AndroidJavaObject jo = new AndroidJavaObject("java.lang.String", "some_string");
- オブジェクトのメソッドを呼び出します。使用し
AndroidJavaObject
たクラスで呼び出し方法を、一般的な非ジェネリックの2つのバージョンがあります。
// 泛型版本,目的是指定返回值的类型
int hash = jo.Call<int>("hashCode");
// 非泛型版本,处理返回值是void的情况。 jo.Call("aMethodReturnVoid"); // String中没有返回void的简单方法。。。
- クラスを取得し、主に静的フィールドを取得またはUnityPlayerを取得するために使用される静的メソッドを呼び出すために使用されます。
// 传入类的完整包名
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
- フィールドのないvoid型は存在しませんので、静的フィールド、唯一のジェネリック版を入手するには。。。
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
フィールドを設定すると、オブジェクトのフィールドを取得し、コードが静的なメソッドが少し似て呼び出します。
型マッピング
あなたはJavaメソッドに渡されたC#の変数/定数への直接Javaメソッドを呼び出すと、自動的にJavaの型への変換のC#を入力し処理します。C#のジェネリクスを通じ、JavaはタイプのC#のJava型を変換することです戻り値の型を指定することができます。次のようにC#やJava型である自動変換ルールのタイプです。
Java型 | C#型 |
---|---|
などの基本的なタイプ、int 、boolean |
タイプを対応する値int 、bool |
String |
string |
配列型 | 配列型(多次元配列にすることはできません) |
他から継承Object の種類 |
AndroidJavaObject |
Androidのは、ユニティを呼び出します
端からAndroidと直接ユニティスクリプトを呼び出すことはできませんが、インターフェイスコールバックかの方法でメッセージを送信します。
ウェイメッセージング
メッセージは、メッセージング・インターフェース上に構築された非常に単純な呼び出しメカニズム、次のとおりです。
// objectName: Unity 对象的名称
// methodName: Unity 对象绑定的脚本方法名
// message: 自定义消息
UnityPlayer.UnitySendMessage(String objectName, String methodName, String message);
簡単なパッケージを作成します。
import com.unity3d.player.UnityPlayer;
public class UnityPlayerCallback { public final String objectName; public final String methodName; public UnityPlayerCallback(String objectName, String methodName) { this.objectName = objectName; this.methodName = methodName; } public void invoke(String message) { UnityPlayer.UnitySendMessage(objectName, methodName, message); } }
メッセージはオブジェクトとメソッド名ユニティの名前を知っている必要があり、この情報はアンドロイドの最後に知られていない、それはJavaコードにハードコードされたべきではありません送信します。上側のAndroidのクライアントコードに関してユニティスクリプトコードなので、ライブラリファイルが提供するAndroidのライブラリ関数は、そのクライアントコードのいずれかの具体的な情報を知ることになっていないと呼ばれます。
正しいアプローチは、Javaオブジェクトを保存するには、これらの2つの文字列を呼び出すためにC#のJava側のコードを使用して、最も簡単に、ライブラリにこの情報を注入するためにいくつかの方法です。
メッセージタイプ= /データ:次の例は、単純なメッセージフォーマットを提供します。
// Java 代码
public class Downloader { private UnityPlayerCallback mUnityCallback; public void setDownloadCallback(String objectName, String methodName) { mUnityCallback = new UnityPlayerCallback(objectName, methodName); } ... void onDownloaded(File file, String url) { if (mUnityCallback != null) { mUnityCallback.invoke("downloaded/" + file.getName()); } } }
// C# 脚本:
void OnStart() { AndroidJavaObject downloader = new AndroidJavaObject("my.package.Downloader"); downloader.Call("setDownloadCallback", gameObject.name, "OnJavaMessage"); } void OnJavaMessage(string message) { // 这里解析 message,例:"download/filename.txt" if (message.StartsWith("downloaded/") { // 处理下载完成的逻辑... } }
このメソッドはラフで、コールバックメソッド、データ移動錯体が複数存在する場合の処理方法についてのメッセージは、開いていないので、あなたは、複雑なメッセージングフォーマットを定義する必要があります。
インタフェースの呼び出し
この方法は、C#のスクリプトで継承によって、スタイル、優れたJavaのJavaコールバックインタフェースの面で定義された、より自然を使用してAndroidJavaProxy
、このJavaクラスのインタフェースを実装します。コールバックメソッドを設定して、Java側のオブジェクトインターフェイスは、Java、C#のコールバックを設定するプロセスを完了するために、JavaコードにC#が提供される実装提供します。
この方法は、以下に例示されています。
Javaコードは、発信者に通知するために、ダウンロードの進捗状況とステータスのインタフェースを使用して、クラスのダウンロードツールを定義します。
// 回调接口
public interface DownloadListener { void onProgress(String name, int progress); void onDownloaded(String name); void onError(String name, String message); } // 下载工具类 public class DownloadHelper { public void download(String url, String name) {...} public void setDownloadListener(DownloadListener listener) {...} }
同じ名前のC#のコードも定義するDownloadHelper
Javaオブジェクトのクラスは、呼び出しをカプセル化:
public class DownloadHelper {
// 定义 C# 端的接口,对外隐藏 Java 相关代码
public interface IDownloadListener {
void OnProgress(string name, int progress);
void OnDownloaded(string name); void OnError(string name, string message); } // 定义个 Adapter 来适配 AndroidJavaProxy 对象和 IDownloadListener private class ListenerAdapter : AndroidJavaProxy { private readonly IDownloadListener listener; public ListenerAdapter(IDownloadListener listener) : base("my.package.DownloadListener") { this.listener = listener; } // 继承自 AndroidJavaProxy 的对象可以直接按照 Java 中的方法签名 // 写出对应的 C# 方法,参数类型遵循上文提到的数据类型转换规则。 // 当 Java 调用接口方法时,对应的 C# 方法会自动调用,非常方便。 void onProgress(string name, int progress) { listener.OnProgress(name, progress); } void onDownloaded(string name) { listener.OnDownloaded(name); } void onError(string name, string message) { listener.OnError(name, message); } } private readonly AndroidJavaObject javaObject; private ListenerAdapter listenerAdapter; public DownloadHelper() { javaObject = new AndroidJavaObject("my.package.DownloadHelper", DefaultDirectory); } public void SetDownloadListener(IDownloadListener listener) { if (listener != null) { listenerAdapter = new ListenerAdapter(listener); javaObject.Call("setDownloadListener", listenerAdapter); } else { listenerAdapter = null; javaObject.Call("setDownloadListener", null); } } public void Download(string url, string name) { javaObject.Call("download", url, name); } // 初始化下载目录 private static string DefaultDirectory; static DownloadHelper() { AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity"); string path = jo.Call<AndroidJavaObject>("getExternalFilesDir", "videos").Call<string>("getCanonicalPath"); DefaultDirectory = path; } }
使用時で、C#のを直接使用DownloadHelper
して授業DownloadHelper.IDownloadListener
することができます。
追伸:
同僚を達成するための第二の方法は、ユニティのスクリプトを書いた後に問題が見つかりました:原因コールバック・ダウンロード・モジュールには、ユニティのメインスレッドではありませんAndroidのUIスレッドで実行され、環境へのユニティコールバックは、それぞれを実行することはできませんオブジェクトの動作モード。Unityは、したがって、メインスレッドと実行コールバックを通知する必要があります。
C#コードを使用して、以下のように変更されたLoom
Androidのと少し似たクラスを、Handler
あなたは記事を参照することができユニティ織機プラグイン
private class ListenerAdapter : AndroidJavaProxy {
...
void onProgress(string name, int progress) { Loom.QueueOnMainThread((param) => { listener.OnProgress(name, progress); }, null); } void onDownloaded(string name) { Loom.QueueOnMainThread((param) => { listener.OnDownloaded(name); }, null); } void onError(string name, string message) { Loom.QueueOnMainThread((param) => { listener.OnError(name, message); }, null); } }
直接放送アンドリュースを取得する方法
アンドリュース層を使用することができるがBroadcastReceiver
、放送を受信するために、および層C#カスタムメソッドに送信されます。あなたがC#の側に直接、さらに便利に受け取ることができる場合でも、その後、彼は汎用性の高い放送受容層を書きました。
放送受容層を使用する方法で、この初見の主な目的は、この層の設計は2つあり:まず、C#コードアンドリュース放送に直接登録するには、他には十分に単純にするために使用するコードです。
最初のコードは使用します:
public class BTHolder : MonoBehaviour, UnityBroadcastHelper.IBroadcastListener {
UnityBroadcastHelper helper;
void Start() { if (helper == null) { helper = UnityBroadcastHelper.Register( new string[] { "some_action_string" }, this); } } void OnReceive(string action, Dictionary<string, string> dictionary) { // handle the broadcast } }
私たちは、放送の使用は、4つのステップが必要で見ることができます。
- 実装
UnityBroadcastHelper.IBroadcastListener
のインターフェイスを。 - 定義
UnityBroadcastHelper
オブジェクトとは、初期化します。 - 方法では
void OnReceive(string action, Dictionary<string, string> dictionary)
、カスタムコードの放送処理。 - ラジオを聞いて停止する)(適切なタイミングで呼び出しHelper.Stop。
これは、カスタムJavaコードを見ることができBroadcastReceiver
、ほとんどの原則の分析以下同じ手順です。
- 最初のJavaオブジェクトを使用して
UnityBroadcastHelper
保持するようにBroadcastReceiver
して、コンテキストのJavaコードに登録。 - 上記で言及し再利用するインターフェースモードがされる
UnityBroadcastHelper.BroadcastListener
C#でマッピングされましたUnityBroadcastHelper.IBroadcastListener
。Javaのターミナルで、このような呼び出しC#のインターフェイスは、放送を受信するには、C#の放送が受信された通知することができます。 - 最後に、C#辞書にマッピングされたエクストラバンドルに格納されるデータ放送を利用したデータ収集インターフェースは、に渡され
OnReceive
、使用C#のを容易にする方法。ここではすべてのタイプのデータに簡単にするために、文字列型にマッピングされ、このマッピングは詳細の一部を記述する必要があり、面倒です。
Javaコード:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle; import com.unity3d.player.UnityPlayer; import java.util.LinkedList; import java.util.Queue; public class UnityBroadcastHelper { private static final String TAG = "UnityBroadcastHelper"; public interface BroadcastListener { void onReceive(String action); } private final BroadcastListener listener; private Queue<String[]> keysQueue = new LinkedList<>(); private Queue<String[]> valuesQueue = new LinkedList<>(); public UnityBroadcastHelper(String[] actions, BroadcastListener listener) { MyLog.d(TAG, "UnityBroadcastHelper: actions: " + actions); MyLog.d(TAG, "UnityBroadcastHelper: listener: " + listener); this.listener = listener; IntentFilter intentFilter = new IntentFilter(); for (String action : actions) { intentFilter.addAction(action); } Context context = UnityPlayer.currentActivity; if (context == null) { return; } context.registerReceiver(broadcastReceiver, intentFilter); } public boolean hasKeyValue() { return !keysQueue.isEmpty(); } public String[] getKeys() { return keysQueue.peek(); } public String[] getValues() { return valuesQueue.peek(); } public void pop() { keysQueue.poll(); valuesQueue.poll(); } public void stop() { Context context = UnityPlayer.currentActivity; if (context == null) { return; } context.unregisterReceiver(broadcastReceiver); } private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); MyLog.d(TAG, "UnityBroadcastHelper: action: " + action); Bundle bundle = intent.getExtras(); if (bundle == null) { bundle = new Bundle(); } int n = bundle.size(); String[] keys = new String[n]; String[] values = new String[n]; int i = 0; for (String key : bundle.keySet()) { keys[i] = key; Object value = bundle.get(key); values[i] = value != null ? value.toString() : null; MyLog.d(TAG, "UnityBroadcastHelper: key[" + i + "]: " + key); MyLog.d(TAG, "UnityBroadcastHelper: value[" + i + "]: " + value); i++; } keysQueue.offer(keys); valuesQueue.offer(values); listener.onReceive(action); } }; }
C#コード:
using System.Collections.Generic;
using UnityEngine;
public class UnityBroadcastHelper {
public interface IBroadcastListener {
void OnReceive(string action, Dictionary<string, string> dictionary);
}
private class ListenerAdapter : AndroidJavaProxy {
readonly IBroadcastListener listener;
readonly UnityBroadcastHelper helper; public ListenerAdapter(IBroadcastListener listener, UnityBroadcastHelper helper) : base("UnityBroadcastHelper$BroadcastListener") { this.listener = listener; this.helper = helper; } void onReceive(string action) { AndroidJavaObject javaObject = helper.javaObject; if (!javaObject.Call<bool>("hasKeyValue")) { return; } string[] keys = javaObject.Call<string[]>("getKeys"); string[] values = javaObject.Call<string[]>("getValues"); javaObject.Call("pop"); Dictionary<string, string> dictionary = new Dictionary<string, string>(); Debug.Log("onReceive: dictionary: " + dictionary); int n = keys.Length; for (int i = 0; i < n; i++) { dictionary[keys[i]] = values[i]; } listener.OnReceive(action, dictionary); } } private readonly AndroidJavaObject javaObject; private UnityBroadcastHelper(string[] actions, IBroadcastListener listener) { ListenerAdapter adapter = new ListenerAdapter(listener, this); javaObject = new AndroidJavaObject("UnityBroadcastHelper", actions, adapter); } public static UnityBroadcastHelper Register(string[] actions, IBroadcastListener listener) { return new UnityBroadcastHelper(actions, listener); } public void Stop() { javaObject.Call("stop"); } }