寫給VR手遊開發小白的教程:(五)Cardboard外掛與Android之間的通訊互動

weixin_34007020發表於2017-08-30

原文地址:http://blog.csdn.net/mao_xiao_feng/article/details/52416439
上篇已經把BaseVRDevice這個類解析了一下,緊接著,擺在我們眼前的問題是既然已經完成了VR裝置的基類,那後續的子類必然會對基類做一個相應的擴充套件,以實現AndroidiOS裝置所獨有的功能。事實上AndroidBaseVRDevice這個類就完成了這些事情,學過android的人都知道一個app的執行最基本的就是Layout和Activity,一個控制前端一個控制後臺,而我們本節所要介紹的這個類,就是在BaseVRDevice的基礎上,增加了Android所特有的Java物件的建立和Activity的管理,這搭建了一個橋樑,允許我們將Unity和Android兩個不同的平臺進行通訊和互動。

AndroidBaseVRDevice.cs的程式碼如下,大家可以參照著看看

#if UNITY_ANDROID

using UnityEngine;
using System.Collections.Generic;

public abstract class AndroidBaseVRDevice : BaseVRDevice {
protected AndroidJavaObject cardboardActivity;

public override bool SupportsNativeDistortionCorrection(List<string> diagnostics) {
bool support = base.SupportsNativeDistortionCorrection(diagnostics);
if (cardboardActivity == null) {
diagnostics.Add("Cannot access Activity");
}
return support;
}

public override void Destroy() {
if (cardboardActivity != null) {
cardboardActivity.Dispose();
cardboardActivity = null;
}
base.Destroy();
}

protected virtual void ConnectToActivity() {
try {
using (AndroidJavaClass player = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) {
cardboardActivity = player.GetStatic<AndroidJavaObject>("currentActivity");
}
} catch (AndroidJavaException e) {
cardboardActivity = null;
Debug.LogError("Exception while connecting to the Activity: " + e);
}
}

protected virtual bool CallActivityMethod(string name, params object[] args) {
return CallObjectMethod(cardboardActivity, name, args);
}

protected virtual bool CallActivityMethod<T>(ref T result, string name, params object[] args) {
return CallObjectMethod(ref result, cardboardActivity, name, args);
}

protected AndroidJavaObject Create(string className, params object[] args) {
try {
return new AndroidJavaObject(className, args);
} catch (AndroidJavaException e) {
Debug.LogError("Exception creating object " + className + ": " + e);
return null;
}
}

protected static bool CallObjectMethod(AndroidJavaObject jo, string name, params object[] args) {
if (jo == null) {
Debug.LogError("Object is null when calling method " + name);
return false;
}
try {
jo.Call(name, args);
return true;
} catch (AndroidJavaException e) {
Debug.LogError("Exception calling method " + name + ": " + e);
return false;
}
}

protected static bool CallObjectMethod<T>(ref T result, AndroidJavaObject jo, string name,
params object[] args) {
if (jo == null) {
Debug.LogError("Object is null when calling method " + name);
return false;
}
try {
result = jo.Call<T>(name, args);
return true;
} catch (AndroidJavaException e) {
Debug.LogError("Exception calling method " + name + ": " + e);
return false;
}
}
}

#endif

來自CODE的程式碼片AndroidBaseVRDevice.cs

/**************************************************************************************************************************************/

程式碼的第一句就給我們擺了難題,AndroidJavaObject這個類看著像是Android的,但事實上它是Unity庫裡的一個類,見聖典:
http://www.ceeger.com/Script/AndroidJavaObject/AndroidJavaObject.html
發現這個類下,有一系列函式和一個構造方法static function AndroidJavaObject (className : string, params args : object[])
這個構造方法很有趣,它有兩個引數分別是1、指定的Java類名2、傳遞的引數
為什麼說他有趣?
大家可以看一個例子
//建立一個java.lang.String物件,持有該字串"some string"function Start() {var jo = new AndroidJavaObject("java.lang.String", "some string");}

這是摘自聖典的一個例子,我們通過建構函式將AndroidJavaObject例項化了以後,生成的居然不是AndroidJavaObject的例項而是其字串引數java.lang.String物件的一個例項。這很神奇,因為我們通常所能認識到的是建構函式構造的一定是類本身,那為什麼這裡不是?

事實上,我們構造出來的仍然是本身,只不過“看起來”不一樣而已。什麼是“看起來”不一樣呢?
從這裡需要引申到Java中所有物件的祖先類,Object類,這裡的AndroidJavaObject就是Object類的一個泛型,關於Object類的概念,給一個連結這裡不再詳述
http://www.cnblogs.com/mengdd/archive/2013/01/03/2842809.html
好了,現在Object作為泛型類,把AndroidJavaObject這個類作為引數來確定具體例項化哪個物件,而例項化哪個物件的問題,就由例項化的AndroidJavaObject類來解答了,所以說,不管是最終例項化的java.lang.String類,還是我們覺得應該例項化的AndroidJavaObject類,都是產自於Object類,它們事實上來源是相同的,而我們只是通過泛型這種手段來將Object物件做了個“變形”。
理解了這一步,我們就知道AndroidJavaObject類在Unity中存在的意義了,它就像一座橋樑,將Java物件與遠方的Unity中的物件聯絡起來。

/**************************************************************************************************************************************/
AndroidJavaClass player = new AndroidJavaClass("com.Unity3D.player.UnityPlayer"
//同理AndroidJavaClass也是如此,只不過它聯絡了Java中的類和Unity中的類。需要說明的一點是,Class類沒有公共構造方法,我們都知道類是物件的抽象,而Class是對Java中所有類的一個抽象,它儲存的是一個Java類的元資訊,負責類的型別標識問題而從不負責類的例項化問題。於是,我們知道AndroidJavaClass的例項得到的是指定的型別,而不是例項化的物件。附上聖典的介紹:
http://www.ceeger.com/Script/AndroidJavaClass/AndroidJavaClass.html

/**************************************************************************************************************************************/

解決了這個問題,讓我們接著往下
using (AndroidJavaClass player = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
//這一步相當於在Java中引用了名為com.unity3d.player.UnityPlayer的庫,而C#與Java互通上面已經說了,一句話就是C#中建立的Java物件需要用到新增到Java語言中的com.unity3d.player.UnityPlayer庫中的操作,聽起來有些拗口。

cardboardActivity = player.GetStatic<AndroidJavaObject>("currentActivity");
//然後我們接著呼叫AndroidJavaClass 類下的GetStatic.<FieldType>方法去獲取當前的Activity,這句話如果在上一句之前是無法執行的,因為GetStatic.<FieldType>語句是Unity庫裡的語句,我們正是通過新增了com.unity3d.player.UnityPlayer庫才使得該語句可用。說到這裡又有人會問了,我們開頭的using UnityEngine不是已經將Unity庫匯入進來了嗎?其實using UnityEngine只是將Unity和C#聯絡起來,但是我們現在做的,是C#環境中,實現Android和Unity的通訊,兩者顯然不一樣。
哈哈,這就是程式設計的魅力:無限的擴充套件性+嚴密的邏輯性!

/**************************************************************************************************************************************/

接下去呼叫物件方法的一些函式和Creat新的物件就不再詳述了,無非就是用泛型實現物件內呼叫其他物件方法,相信大家都能看懂

相關文章