在前述文章中,已经使用了AndroidJavaProxy代理接口,本节我们将详细的介绍AndroidJavaProxy代理的用法。正如其名,AndroidJavaProxy是一个代理,它在Android端代码与Unity端代码交互中起一个桥接作用。其一般用法为在Java代码中定义接口(Interface),建立代码调用外观,然后在Unity端用C#实现Java代码定义的接口,在使用时,在C#代码中实例化实现接口的类并将该实例对象传递到Java端,Java端根据情况执行接口方法,回调C#中的实现逻辑。
下面通过一个实例进行演示。首先需要在Java端定义一个接口,ProxyExample.java文件代码如下:
java
//5-1
//Java端代码
package com.davidwang.android2unity;
public interface ProxyExample
{
void OnFired(String msg);
}
然后,在C#端,通过AndroidJavaProxy代理实现该接口,在使用时将实现接口的类的实例传递到Java端,代码如下:
csharp
//5-2
//C#端代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UnityProxyExample : MonoBehaviour
{
void Start()
{
using (AndroidJavaObject jo = new AndroidJavaObject("com.davidwang.android2unity.ProxyUseCase"))
{
var mCallbackListener = new SDKCallbackListener();
// 调用Jar中的方法,并把new的值传进去
jo.Call("Init", mCallbackListener);
}
}
class SDKCallbackListener : AndroidJavaProxy
{
// 引用Jar中接口
public SDKCallbackListener() : base("com.davidwang.android2unity.ProxyExample") { }
//实现接口中的方法
public void OnFired(string str)
{
Debug.Log("OnFired:" + str);
}
}
}
在代码5-2中,C#端实现了Java接口,接口中的方法必须为Public,方法签名与Java端完全一致。然后通过Java端的Init()方法将实现接口的实例对象传递到Java端,Java端使用方法代码如下:
java
//5-3
//Java端代码,ProxyUseCase.java
package com.davidwang.android2unity;
public class ProxyUseCase {
private ProxyExample proxyExample;
public void Init(ProxyExample proxyExample){
this.proxyExample = proxyExample;
try {
java.lang.Thread.sleep(5000);
EventCallback();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
public void EventCallback(){
proxyExample.OnFired("some event fired in Android ");
}
}
在代码5-3中,EventCallback()方法本应该由Java端的其他事件触发,为演示简单,这里采用了延时触发方法。Java端通过调用其接口方法,实现了对C#端实例对象方法的调用。他们之间的关系示意图如图1所示。
图1 AndroidJavaProxy原理示意图 在C#端,通过实现Java端的接口,可以生成本地端的实例对象,这个实例对象在Mono / IL2CPP虚拟机内,然后通过调用Java端的方法将本地端的实例对象引用传递到Java端,因为实例对象实现了Java端的接口,所以Java端可以通过接口调用到实例对象的方法,本质上是通过引用调用Mono / IL2CPP虚拟机端的本地实例对象。所以AndroidJavaProxy代理实质上是在C#端与Java端建立了一个对象引用指针,通过这个指针可以指向实例对象,虽然这个实例对象存在于另一个虚拟机中。
本节中,我们采用另一种打包方式,将代码打包成Jar包。Jar包只包含编译后的class文件与清单文件,不包含图片布局等资源文件;aar包则包含所有相关的资源,class文件、清单文件、res资源文件等。所以如果只有类库文件时建议生成Jar包;如果还包含布局文件、图片、字体等资源文件时建议使用aar包。
在Android Studio中,类库的建立方法与Unity与Android交互通信系列(3)所述一致,不再赘述。点击展开app目录下的android2unity目录,双击鼠标打开该目录下的build.gradle文件,如图2所示。
图2 打开类库目录下的build.gradle文件 如图2所示,在打开的build.gradle文件中dependencies指令前添加一个task[ Task任务要作为一级指令,即不包含在其他编译指令之中。],task任务指令代码如下:
java
//5-4
task makeJar(type: Copy) {
//如果之前有编译打包,则删除原存在的jar包
delete 'build/libs/andriod2unity.jar'
//Android Studio默认打包路径
from('build/intermediates/aar_main_jar/release/')
//将打包后的文件复制到该目录下
into('build/libs/')
//include参数来设置过滤,我们只关心classes.jar包
include('classes.jar')
//重命名生成的jar包
rename ('classes.jar', 'andriod2unity.jar')
}
makeJar.dependsOn(build)
编译Jar包时,鼠标点击task任务左侧的绿色三角形图标展开下拉菜单,单击鼠标选择"Run 'Android2Unity[makeJ...'"开始编译打包,如图3所示。
图3 编译生成Jar包
编译打包成功后,即可以在android2unity类库模块下的build/libs目录下找到生成的android2unity.jar包[ 根据Android Studio版本不同,有的版本不会生成libs目录,这时可以将Jar包生成到outputs目录中,即代码清单5-4中将Jar包生成的路径修改到build/outputs目录下。通过Task任务的方式还可同时生成aar包,该包区分debug、release版本,位于build/outputs/aar目录下]。与使用aar包一样,将该jar文件复制到Unity工程Assets/Plugins/Android目录或其子目录下,然后在Unity端将UnityProxyExample脚本挂载到场景中的任意对象上,连接手机,打包运行,即可看到正确的调用输出。