在unity开发或者sdk开发经常遇到unity与移动端原生层之间进行通信,这里把它们之间通信做一个整理。
关于Unity与iOS之间通信,参考【Unity3d】Unity与iOS之间通信
Unity(c#)调用Android
(一)、编写Java代码
实际上,任何已经存在的Java代码都可以被c#调用,不像iOS中需要事先用extern "C"
修饰。
例如,Java中的MyJavaClass内容如下:
package com.devnn.demo;
public class MyJavaClass{
private static MyJavaClass instance=new MyJavaClass();
public static getInstance(){
return instance;
}
public String test(String param){
return "This message is from Android!"
}
}
getInstance
和test
是可以被c#调用的。
如果是kotlin写的代码,也是可以被c#调用的,要注意类路径,最好查看字节码或者反编译成Java查看路径。
另外,用了kotlin之后,需要额外添加kotlin运行时库,例如:
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.20"
为了方便导出jar或者aar,建议在library工程中编写。
(二)、将Java代码打包成aar或jar,拷贝到unity工程中
将打包好的aar或者jar拷贝到Unity工程的Assets
目录或子目录中。
实际上拷贝到unity工程的Assets
目录下的任意位置都可以,aar和jar会自动被unity作为lib依赖。(从导出gradle工程后可以看得出来)
(笔者使用的unity版本是2019.4,以前的版本不知道是否可以是任意位置。)
为了方便管理,以上aar/jar一般放在Assets/Plugins/Android
中。
(三)、在c#中调用Java代码
c#中提供了两个类可以调用Java代码:
AndroidJavaClass.cs
AndroidJavaObject.cs
它们都在UnityEngine
命名空间中。
AndroidJavaClass
是继承自AndroidJavaClass
。
这两个类的区别一般我们用不着,使用其中任意一个都可以。
使用方式很简单,在构造方法中传入Java类的完整路径,然后调用Call方式调用Java实例方法或者CallStatic调用Java的静态方法。方法泛型中写Java返回的类型。
示例代码:
//实例化AndroidJavaClass,传入Java类路径
AndroidJavaClass jc = new AndroidJavaClass("com.devnn.demo.MyJavaClass");
//如果找不到Java类,返回null
if(jc == null) return;
//调用Java类的getInstance方法获取实例
AndroidJavaObject jo = jc.CallStatic<AndroidJavaObject>("getInstance");
//如果找不到Java方法,返回null
if (jo == null) return;
string param = "Hello,Android!";
string result = jo.Call<string>("test", param); //调用test方法,返回值是字符串。
Android调用Unity(c#)
Android调用c#比较简单,使用以下方法即可。
UnityPlayer.UnitySendMessage("MyTestObject", "TestFunc","msg");
需要依赖unity的classes.jar,位置在unity安装目录:AndroidPlayer/Variations/mono/Release/Classes/classes.jar
。
Unity工程导出Android工程时,默认已经依赖了这个jar,自己新建的Android工程需要导入上述jar包。
这个unity的classes.jar目前不是开源的,反编译看到是混淆后的代码。
UnitySendMessage
方法的源码如下:
//com.unity3d.player.UnityPlayer.class
public static void UnitySendMessage(String var0, String var1, String var2) {
if (!n.c()) {
g.Log(5, "Native libraries not loaded - dropping message for " + var0 + "." + var1);
} else {
try {
nativeUnitySendMessage(var0, var1, var2.getBytes("UTF-8"));
} catch (UnsupportedEncodingException var3) {
}
}
}
private static native void nativeUnitySendMessage(String var0, String var1, byte[] var2);
可见,这是通过jni实现的。
第一个参数var0表示unity中物体GameObject的名字,注意不是c#脚本的名称也不是类名。
如下图:
第二个参数var1表示这个物体挂载的c#脚本中方法的名字。
第三个参数表示var2表示这个方法接收的数据。
例如,以上物体MyTestObject
挂载了MyScript.c#
脚本(如上图),MyScript.c#
中有一个TestFunc
方法:
using UnityEngine;
public class MyScript : MonoBehaviour
{
private void TestFunc(string content)
{
//这里是接收Android调用的实现
}
}
那么在Android中调用UnitySendMessage("MyTestObject", "TestFunc", "msg")
c#的TestFunc
方法就会执行。
如果有多个参数需要发送,推荐使用json格式。