Skip to main content
ARShow
 首页 » 资源教程 » Unity3D教程

写给VR手游开发小白的教程:(五)Cardboard插件与Android之间的通信交互

2016年09月12日 12:51:0670020

上篇已经把BaseVRDevice这个类解析了一下,紧接着,摆在我们眼前的问题是既然已经完成了VR设备的基类,那后续的子类必然会对基类做一个相应的扩展,以实现Android和ios设备所独有的功能。事实上AndroidBaseVRDevice这个类就完成了这些事情,学过Android的人都知道一个app的运行最基本的就是Layout和Activity,一个控制前端一个控制后台,而我们本节所要介绍的这个类,就是在BaseVRDevice的基础上,增加了Android所特有的Java对象的创建和Activity的管理,这搭建了一个桥梁,允许我们将Unity和Android两个不同的平台进行通信和交互。


AndroidBaseVRDevice.cs的代码如下,大家可以参照着看看


  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
#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新的对象就不再详述了,无非就是用泛型实现对象内调用其他对象方法,相信大家都能看懂

评论列表暂无评论
发表评论