unity3d和android前景,[unity3d]Unity3D与android交互----

Set域的值

Call分为两类,调用void方法和调用非void返回类型的方法,会使用一个泛型类型来表示这些非void返回类型的方法的返回类型;Get和Set也经常带一个泛型类型用以表示域的类型。

例子1:

[cpp] view plaincopy //注释表示是使用原始JNI方法必须做的工作

AndroidJavaObject jo = newAndroidJavaObject("java.lang.String","some_string");

// jni.FindClass("java.lang.String");

// jni.GetMethodID(classID, "", "(Ljava/lang/String;)V");

// jni.NewStringUTF("some_string");

// jni.NewObject(classID, methodID, javaString);

inthash = jo.Call("hashCode");

// jni.GetMethodID(classID, "hashCode", "()I");

// jni.CallIntMethod(objectID, methodID); 这个例子中,我们创建了一个 java.lang.String的实例,并用我们自定义的一个字符串初始化它,最后我们得到该字符串的哈希值。

AndroidJavaObject的构造方法至少需要一个参数----你想要实例化的类的名称。类名之后的参数会被对象的构造函数所使用,如上例种的字符串“some_string”,随后的对hashCode方法的Call会返回一个int型值,这也是为什么我们会传一个泛型参数给Call方法。

注意:不能使用点.来初始化一个嵌套类型,内部类必须使用$分隔符,在斜线/或点.分隔的类名中都可以使用。所以当类LayoutParams嵌套在ViewGroup类中时,像android.view.ViewGroup$LayoutParams或者android/view/ViewGroup$LayoutParams,这两种方式都是可行的。

例子2:

上面有个插件的例子是说获取当前程序的缓存目录的,下面这个例子直接用c#代码做同样的事情,而不需要任何插件:

[csharp] view plaincopy AndroidJavaClass jc =newAndroidJavaClass("com.unity3d.player.UnityPlayer");

// jni.FindClass("com.unity3d.player.UnityPlayer");

AndroidJavaObject jo = jc.GetStatic("currentActivity");

// jni.GetStaticFieldID(classID, "Ljava/lang/Object;");

// jni.GetStaticObjectField(classID, fieldID);

// jni.FindClass("java.lang.Object");

Debug.Log(jo.Call("getCacheDir").Call("getCanonicalPath"));

// jni.GetMethodID(classID, "getCacheDir", "()Ljava/io/File;"); // or any baseclass thereof!

// jni.CallObjectMethod(objectID, methodID);

// jni.FindClass("java.io.File");

// jni.GetMethodID(classID, "getCanonicalPath", "()Ljava/lang/String;");

// jni.CallObjectMethod(objectID, methodID);

// jni.GetStringUTFChars(javaString);

这个例子中,我们没有首先使用AndroidJavaObject,而是AndroidJavaClass ,因为我们想获取类com.unity3d.player.UnityPlayer的一个静态成员,而不是去创建一个新的对象(Android UnityPlayer会自动创建一个实例)。我们访问其静态域"currentActivity" ,这个时候我们用的是AndroidJavaObject作为泛型参数,这是因为实际类型(android.app.Activity)是类java.lang.Object的子类,任意非基本类型都必须作为AndroidJavaObject来访问。有一个例外就是字符串,字符串可以直接访问,尽管它在java中并不是基本类型。

之后就是调用的Activity的getCacheDir()得到缓存目录的文件对象,再调用getCanonicalPath()方法获取缓存目录路径的字符串表示。

当然,现在已经不需要通过这种方式来获取缓存目录了,因为unity3d提供了接口用以访问程序的缓存目录和数据目录,也就是Application.temporaryCachePath and Application.persistentDataPath。

例子3:

最后,是一个通过UnitySendMessage方法从java代码向脚本代码传递数据的小窍门。

[csharp] view plaincopy usingUnityEngine;

publicclassNewBehaviourScript : MonoBehaviour

{

  voidStart ()

  {

  JNIHelper.debug =true;

  using(JavaClass jc =newJavaClass("com.unity3d.player.UnityPlayer"))

      {

       jc.CallStatic("UnitySendMessage","Main Camera","JavaMessage","whoowhoo");

  }

}

voidJavaMessage(stringmessage)

  {

Debug.Log("message from java: "+ message);

}

}

类com.unity3d.player.UnityPlayer现在有一个静态方法UnitySendMessage,与iOS中native端的UnitySendMessage一样,可用来在java中向脚本传递数据。

这里我们直接从脚本中调用的,但它确实是在java端发送的消息,它会调回到unity3d的native代码,传递消息到名为"Main Camera"的游戏对象上去,该对象上绑定的某个脚本中包含有名为"JavaMessage"的方法。

在unity3d中使用java插件的最佳实践这一节主要针对那些没有足够jni,java和android经验的人。假设我们在unity3d中使用AndroidJavaObject/AndroidJavaClass来与java交互。

首先就是要注意对AndroidJavaObject/AndroidJavaClass的任何操作都是很费时的(是通过JNI来进行的)。因此为了代码性能和代码清晰性,我们强烈建议托管代码与native/java代码间的转换次数保持在最小数量。

你可以定义一个java方法完成所有的事情,然后我们通过AndroidJavaObject/AndroidJavaClass来与这个方法通信和获取结果,我们的JNI帮助类会尽可能多的缓存数据已提高性能。

[csharp] view plaincopy //第一次像这样调用java函数

AndroidJavaObject jo = newAndroidJavaObject("java.lang.String","some_string");// 有点费时

inthash = jo.Call("hashCode");//第一次 - 费时

inthash = jo.Call("hashCode");// 第二次 - 不那么费时, 因为我们已经知道了这个java方法,可以直接调用它。

在使用过后,Mono垃圾回收器会释放所有创建的AndroidJavaObject和AndroidJavaClass实例,但我们还是建议把它们放到using(){}块中,以保证它们能被尽快的清除掉。除此之外,你无法保证它们会被销毁掉。如果你设置了AndroidJNIHelper.debug为true,你会在log输出中看到垃圾回收器的活动记录。

[csharp] view plaincopy //获取系统语言的安全方法

voidStart ()

{

using(AndroidJavaClass cls =newAndroidJavaClass("java.util.Locale"))

  {

using(AndroidJavaObject locale = cls.CallStatic("getDefault"))

      {

Debug.Log("current lang = "+ locale.Call("getDisplayLanguage"));

}

}

}

也可以直接调用.Dispose()方法确保没有java对象残留,c#对象会存活长一点,最终还是会被mono的垃圾回收器回收。

继承UnityPlayerActivity java代码

在Unity Android上,我们可以继承标准的UnityPlayerActivity类(android上Unity Player的主要java类,类似于Unity iOS上的AppController.mm)。

应用程序可以覆写android系统与Unity Android之间的任意交互方法,只要新建一个Activity继承UnityPlayerActivity就可以实现。(在mac系统上,UnityPlayerActivity.java在/Applications/Unity/Unity.app/Contents/PlaybackEngines/AndroidPlayer/src/com/unity3d/player目录下;在windows系统中,它通常在C:\Program Files\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\src\com\unity3d\player目录下)

首先定位Unity Android的classes.jar文件,可以在Unity3d的安装目录(windows下通常是C:\Program Files\Unity\Editor\Data,mac下是/Applications/Unity)下的子文件夹PlaybackEngines/AndroidPlayer/bin中找到,将它添加到你编译activity的classpath中。最终编译出来的.class文件,需要打包成.jar文件,放到工程中的Assets->Plugins->Android目录下。因为android中manifest文件指明了启动哪个Activity,因此我们也需要重新写一个AndroidManifest.xml文件,也需要将它放到Assets->Plugins->Android目录下。

继承UnityPlayerActivity的一个例子,OverrideExample.java:

[java] view plaincopy packagecom.company.product;

importcom.unity3d.player.UnityPlayerActivity;

importandroid.os.Bundle;

importandroid.util.Log;

publicclassOverrideExampleextendsUnityPlayerActivity {

protectedvoidonCreate(Bundle savedInstanceState) {

// call UnityPlayerActivity.onCreate()

super.onCreate(savedInstanceState);

// print debug message to logcat

Log.d("OverrideActivity","onCreate called!");

}

publicvoidonBackPressed()

{

// instead of calling UnityPlayerActivity.onBackPressed() we just ignore the back button event

// super.onBackPressed();

}

}

相关的AndroidManifest.xml文件如下:

[html] view plaincopy <?xmlversion ="1.0"encoding="utf-8"?>

android:label="@string/app_name"

android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen">

UnityPlayerNativeActivity

同样我们可以创建UnityPlayerNativeActivity的子类,这与创建UnityPlayerActivity的子类具有相同的效果,但是会有较小的输入延迟。但是,需要明白的是,NativeActivity是在Gingerbread中引入的(即android 2.3),老的android版本没有这个特性,因为在NativeActivity中,触摸事件都是在native代码中处理的,java视图正常情况下是无法获取这些事件的,不过在unity3d中,有允许将事件传到DalvikVM的转发机制,要应用这个转发机制,必须修改manifest文件如下:

[html] view plaincopy <?xmlversion ="1.0"encoding="utf-8"?>

android:label="@string/app_name"

android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen">

要注意activity元素中的.OverrideExampleNative属性,还有两条meta-data元素,第一条meta-data元素指明使用unity3d库libunity.so,第二条meta-data元素使事件能传递到你创建的UnityPlayerNativeActivity子类中。

例子

native插件例子

这里有一个简单的使用native插件的例子。

这个例子演示了如果从unity3d android程序中来调用c代码,包中包含了一个通过native插件计算出来的两个数之和的场景,要注意,你必须用Android NDK来编译这个插件。

java插件例子

这里有一个简单的使用java代码的例子。

这个例子演示了怎么用java代码与android系统进行交互,以及如何用c++来将c#和java沟通起来,包中的场景显示了一个按钮,点击该按钮,会显示出程序在android系统中的缓存目录路径。需要JDK和Android NDK来编译这个插件。

这里有一个相似的例子,但是是基于预先编译好的JNI库,来封装native代码,供c#调用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值