网站空间的参数,定制企业网站费用,津seo快速排名,视频网站建设公司在上一篇文章中#xff0c;我们介绍了Unity和Android交互通信的原理及在Unity中直接调用Java代码的方式#xff0c;但没有给出代码示例#xff0c;下面通过实际例子演示上篇文章中AndroidJavaClass、AndroidJavaObject两个类的基本用法#xff0c;由于交互通信涉及到两端我们介绍了Unity和Android交互通信的原理及在Unity中直接调用Java代码的方式但没有给出代码示例下面通过实际例子演示上篇文章中AndroidJavaClass、AndroidJavaObject两个类的基本用法由于交互通信涉及到两端我们先使用Android Studio创建Unity2Java类Java代码如下
//代码片断1
package com.example.davidwang;public class Unity2Java {public static void StaticPrint(String str){System.out.println(str);}public static int StaticAdd(int a,int b){return ab;}public void DynamicPrint(String str){System.out.println(str);}public int DynamicAdd(int a,int b){return ab;}
}找到该类所在的.java文件并将该文件复制到Unity工程Assets/Plugins/Android目录或其子目录下然后在Unity工程窗口Project窗口中选中该java文件在属性窗口Inspector窗口中查看其导入设置确保Android平台被选择如图1所示。
图1 在Java文件导入设置中勾选Android多选框 为在Unity端调用Java代码通过Unity创建Android2Unity.cs脚本文件代码如下
//代码片断2
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Android2Unity : MonoBehaviour
{void Start(){using (AndroidJavaClass Unity2JavaClass new AndroidJavaClass(com.example.davidwang.Unity2Java)){Unity2JavaClass.CallStatic(StaticPrint, Hello World from Android static method );int result1 Unity2JavaClass.CallStaticint(StaticAdd, 1, 1);Debug.Log(结果1 result1);Unity2JavaClass.Call(DynamicPrint, Hello World from Android dynamic method );int result2 Unity2JavaClass.Callint(DynamicAdd, 1, 2);Debug.Log(结果2 result2);}using (AndroidJavaObject Unity2JavaObject new AndroidJavaObject(com.example.davidwang.Unity2Java)){Unity2JavaObject.CallStatic(StaticPrint, Hello World from Android static method );int result3 Unity2JavaObject.CallStaticint(StaticAdd, 1, 3);Debug.Log(结果3 result3);Unity2JavaObject.Call(DynamicPrint, Hello World from Android dynamic method );int result4 Unity2JavaObject.Callint(DynamicAdd, 1, 4);Debug.Log(结果4 result4);}}
}在Unity中将Android2Unity脚本挂载到场景中的任意对象上连接手机打包运行[ Java代码编译后运行于dalvik / art虚拟机其控制台输出不能输出到Unity Debug窗口所以只能通过真机运行Logcat查看输出。]输出结果如下
行号 类型 输出信息
1 System.out Hello World from Android static method
2 Unity 结果12
3 Unity
4 Unity 结果20
5 System.out Hello World from Android static method
6 Unity 结果34
7 System.out Hello World from Android dynamic method
8 Unity 结果45上述代码首先演示了Java端无返回值、有返回值方法的调用通过泛型方法定义返回值类型获取Java端方法执行结果由于数据类型的不同Java端与C#端交互支持的类型有string、int、float、bool、AndroidJavaObject共5类也可以返回这些数据类型的数组其次演示了静态方法和实例方法的调用类静态方法使用带static后辍的方法访问而对象实例方法则使用不带Static后辍的方法调用再次演示了AndroidJavaClass和AndroidJavaObject类使用上的区别通过输出结果可以看到AndroidJavaClass调用对象实例方法既不报错也不执行AndroidJavaObject类调用类静态方法可以正常执行[ Java语言支持实例对象调用类静态方法或者获取类静态属性这与C#语言不同。]虽然我们使用时都使用了new关键字但AndroidJavaClass类不会生成实例对象而AndroidJavaObject类会实例化对象。 类与实例的属性获取/设置与上述方法使用基本一致通过这种方式就可以直接在C#代码中调用Java端的原生类代码如下[ 为了简化排版后续Java代码与C#代码将放置于同一个代码片断中并使用注释进行说明。]
//代码片断3
//Java端代码
package com.example.davidwang;
import android.app.Activity;
import android.widget.Toast;public class Unity2Java {public boolean ShowToast(Activity activity, String str){Toast.makeText(activity,str,Toast.LENGTH_SHORT).show();return true;}
}//C#端代码
//获取设备UUID
private string GetAndroidID()
{string androidID NONE;
#if UNITY_ANDROID !UNITY_EDITORusing (AndroidJavaObject contentResolver new AndroidJavaClass(com.unity3d.player.UnityPlayer).GetStaticAndroidJavaObject(currentActivity).CallAndroidJavaObject(getContentResolver)){using (AndroidJavaClass secure new AndroidJavaClass(android.provider.Settings$Secure)){androidID secure.CallStaticstring(getString, contentResolver, android_id);}}
#endifreturn androidID;
}//调用Andriod端Toast
private void ShowToast()
{if (Application.platform RuntimePlatform.Android)using (AndroidJavaObject Unity2JavaObject new AndroidJavaObject(com.example.davidwang.Unity2Java)){using (AndroidJavaObject activity new AndroidJavaClass(com.unity3d.player.UnityPlayer).GetStaticAndroidJavaObject(currentActivity)){bool isSuccess Unity2JavaObject.Callbool(ShowToast, activity, From Unity);Debug.Log(ShowToast Status : isSuccess);}}
}在上述代码片断3中我们演示了两种直接调用Android端原生类的方式第一种方法是通过直接获取Android端的原生类调用其静态方法第二种是通过调用自定义的Java类间接调用Android原生类方法。同时由于C#代码运行平台不确定为确保代码兼容多平台我们也使用了两种判断代码执行平台的方法第一种使用预编译指令区分平台另一种通过Application类直接判断当前运行平台这也是在多平台开发中经常使用的技巧。 除此之外代码还演示了获取当前活动Activity的方法即通过com.unity3d.player.UnityPlayer类获取当前ActivityAndroid很多类都需要传递活动的Activity或者Context上下文对象通过这种方式获取当前Activity是一种常用方法。 使用AndroidJavaClass和AndroidJavaObject类直接调用Java代码或Android原生类非常方便但只能是单向由C#调用Java代码Java没办法反向调用C#代码实现反向调用则必须使用AndroidJavaProxy类正如其名这是个代理类负责在Java和C#代码之间桥接后文我们还会详细介绍该类。 如前文所述Java端与C#端交互支持的类型有string、int、float、bool、AndroidJavaObject共5类AndroidJavaObject可以表示所有对象类型因此除string、int、float、bool 4种基本类型其余对象都可由AndroidJavaObject表达。C#端调用Java端方法千差万别但Java端调用C#端就以上5类包括数组则共10类因此我们可以编写一个通用的框架因为结构稍微有点复杂涉及到C#端AndroidCallbackManager.cs、AndoridCallbackInterface.cs两个脚本文件Java端CallUnityInterface.java、Java2Unity.java两个代码文件。 其中AndroidCallbackManager.cs文件代码如下
//代码片断4
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AndroidCallbackManager : MonoBehaviour
{void Start(){using (AndroidJavaObject activity new AndroidJavaClass(com.unity3d.player.UnityPlayer).GetStaticAndroidJavaObject(currentActivity)){using (AndroidJavaObject appController new AndroidJavaObject(com.example.davidwang.Java2Unity)){AndoridCallbackInterface callback new AndoridCallbackInterface(com.example.davidwang.CallUnityInterface);callback.stringCallBack StringProcess;callback.intCallBack IntProcess;callback.floatArrayCallBack FloatArrayProcess;appController.Call(Init, activity, callback);Debug.Log(In Start);}}}public void StringProcess(string str){Debug.Log(string callback :str);}public void IntProcess(int value){Debug.Log(int callback : value);}public void FloatArrayProcess(float[] arr){foreach (var value in arr)Debug.Log(float in arr: value);}
}在代码片断4中AndroidCallbackManager类是Unity端的使用类是调用入口其首先获取到当前Activity实例化Java端的Java2Unity类并且同时实例化了一个C#端的AndoridCallbackInterface类。然后设置AndoridCallbackInterface类的回调方法之后调用了Java端的初始化方法。 AndoridCallbackInterface.cs文件代码如下
//代码片断5
using System;
using UnityEngine;
public class AndoridCallbackInterface : AndroidJavaProxy
{public ActionAndroidJavaObject javaObjectCallBack;public Actionbool boolCallBack;public Actionstring stringCallBack; public Actionint intCallBack;public Actionfloat floatCallBack;public Actionfloat[] floatArrayCallBack; //构造方法public AndoridCallbackInterface(string interfaceName) : base(interfaceName){}public void JavaObjectCallBack(AndroidJavaObject _data){if (javaObjectCallBack ! null)javaObjectCallBack(_data);}public void BoolCallBack(bool _data){if (boolCallBack ! null)boolCallBack(_data);}public void StringCallBack(string _data){if (stringCallBack ! null)stringCallBack(_data);}public void IntCallBack(int _data){if (intCallBack ! null)intCallBack(_data);}public void FloatCallBack(float _data){if (floatCallBack ! null)floatCallBack(_data);}public void FloatArrayCallBack(float[] _data){if (floatArrayCallBack ! null)floatArrayCallBack(_data);}
}在代码片断5中AndoridCallbackInterface类继承自AndroidJavaProxy类定义了回调方法如前文所述Java端与C#端交互支持的类型共有5种这里为了通用将这5种回调方法都进行了演示还包括一个Float数组的演示方法。该类构造方法很重要这里需要通过AndroidJavaProxy类将C#端实例与Java端的CallUnityInterface接口对应起来[ 可以理解为建立了一个从Java端到C#端AndoridCallbackInterface类实例的指针这样Java端就可以通过这个指针访问到C#端的实例。]这样Java端就可以调用C#端实例的方法。 CallUnityInterface.java文件代码如下
//代码片断6
package com.example.davidwang;public interface CallUnityInterface {public void JavaObjectCallBack(Object _data);public void BoolCallBack(boolean _data);public void StringCallBack(String _data);public void IntCallBack(int _data);public void FloatCallBack(float _data);public void FloatArrayCallBack(float[] _data);
}在代码片断6中CallUnityInterface接口方法签名与AndoridCallbackInterface类中对应方法签名需要完全一致这样才能确保正确相互调用。 CallUnityInterface.java文件代码如下
//代码片断7
package com.example.davidwang;import android.content.Context;
public class Java2Unity {private Context context null; //上下文对象private CallUnityInterface callback null; //缓存回调public void Init(Context context , CallUnityInterface callback){this.context context;this.callback callback;try {java.lang.Thread.sleep(5000);Run();}catch (InterruptedException e){e.printStackTrace();}}private void Run(){int i 100;String str From Java;float[] floatArr {1.01f,1.02f,1.03f};this.callback.IntCallBack(i);this.callback.StringCallBack(str);this.callback.FloatArrayCallBack(floatArr);}
}在代码片断7中Java2Unity类首先通过Init()方法获取到当前上下文对象[ 在本示意中上下文对象并没有使用但很多时间都需要上下文对象或者当前Activity。]和回调实例通过回调接口即可以调用C#端的方法这里通过延时5秒触发回调方法。 在这个通用框架中这4个类的相互关系如图2所示。
图2 Java端与C#端相互调用关系示意图 在Unity中将AndroidCallbackManager脚本挂载到场景中的任意对象上连接手机打包运行[
Java代码编译后运行于dalvik / art虚拟机其控制台输出不能输出到Unity Debug窗口所以只能通过真机运行Logcat查看输出。]输出结果如下
行号 类型 输出信息
1 Unity int callback :100
2 Unity string callback :From Java
3 Unity float in arr:1.01
4 Unity float in arr:1.02
5 Unity float in arr:1.03
6 Unity In Start通过结果看到Java端正确的向C#端回调了相应方法并且参数传递无误。而且也可以看到这种调用是同步的会阻塞当前线程。 提示 在开发中通常我们都是在Android Studio中进行Java代码编写然后将代码复制到Assets/Plugins/Android目录中供Unity使用如果改动了Android Studio中的Java代码则需要再次复盖Unity中的对应文件而且同时存在两份一样的文件文件内容同步维护会是非常大的问题这时我们可以通过创建文件/文件夹链接确保只有一份文件。文件夹链接类似于Windows操作系统中的快捷方式但可供第三方软件使用。 Windows下创建方式mklink /D LINK_PATH SOURCE_PATH Linux下创建方式ln -s SOURCE_PATH LINK_PATH 其中参数LINK_PATH为链接的路径,这个路径无真实文件夹或者文件SOURCE_PATH为源文件/文件夹路径即真实的文件路径。通过创建文件/文件夹链接就可以只在Assets/Plugins/Android目录下保留一份代码文件Android Studio通过链接连接到相应的文件或文件夹从而可以保持文件同步无需进行复制代码文件的操作。