在unity中的回调事件如果需要暴露给AS工程监听的话,可以在自己的工程下创建一个Plugins文件夹,在子文件夹下再添加Android文件夹,这个Android文件夹下创建的java类或者jar、aar包在unity工程输出AS包的时候会一同打包出去。
举个例子,当unity工程中有个加载场景的方法,在加载时会不断返回加载的进度,在加载完成后回调加载完成事件。如果要把这个加载场景的方法暴露给AS工程进行调用,AS工程是不能直接在一个方法里把加载中、加载完成的监听放进加载方法中的。
因为AS调用Unity的方法,只能通过以下方式进行调用
/*
gameObj----unity挂载调用类的gameobject物体的name
function----unity中触发的类
param----unity中触发的类的参数
*/
UnityPlayer.UnitySendMessage("gameObj","function","param")
这种机制的话,如果方法中需要把监听事件传进去让回调监听是无法直接实现的,不过如果懂一点AS基础的话,就可以在AS工程中把对应的监听事件进一步封装,整合成一个方法的形式,下面说下具体的做法。
首先是在unity工程中,在Plugins/Android下创建的java类用于标记需要监听的回调方法。按照上面的例子,加载场景的话需要监听加载进度与加载完成事件。那么可以创建一个CallbackActivity.java,里面的代码如下所示:
package com.XXX.XXXX;
import android.os.Bundle;
import android.widget.FrameLayout;
import com.unity3d.player.UnityPlayerActivity;
public abstract class CallbackActivity extends UnityPlayerActivity
{
public static CallbackActivity instance = null;
abstract protected void loadSceneComplete();//加载完成的监听事件
abstract protected void loadSceneProcess(String percent);//加载中的监听事件
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
instance = this;
}
@Override
protected void onDestroy() {
super.onDestroy();
instance = null;
}
}
这两个监听的回调在Unity触发加载场景的方法时不断触发。下面是unity的代码
/// <summary>
/// 加载场景
/// </summary>
/// <param name="content"></param>
public void LoadScene(string content)
{
#if UNITY_ANDROID
AndroidJavaClass jc = new AndroidJavaClass("com.XXX.XX.CallbackActivity");
AndroidJavaObject activity = jc.GetStatic<AndroidJavaObject>("instance");
#endif
rbxManager.LoadScene(sceneID,Progress.Create<float>(percent =>
{
#if UNITY_ANDROID
activity.Call("loadSceneProcess", precent.ToString());
#endif
}), ()=> {
#if UNITY_ANDROID
activity.Call("loadSceneComplete","");
#endif
});
}
正常的逻辑是当AS工程中调用了UnityPlayer.UnitySendMessage("gameObj","LoadScene","content")方法来 加载场景时,需要在继承上面的CallbackActivity类中override掉loadSceneComplete和loadSceneProcess这两个方法才能监听。代码如下所示:
public class UnityCallbackActivity extends CallbackActivity {
@Override
protected void loadSceneComplete() {
//监听
}
@Override
protected void loadSceneProcess(String percent) {
//监听
}
}
到这一步为止就是默认的做法,通过UnityPlayer.UnitySendMessage来触发加载,然后在复写的方法里面监听事件。
如果导出的Unity工程是自己使用当然没问题,但如果把工程提供给不懂3D开发的AS开发工程师的话,理解起来就有点绕,个人认为需要上方法上进一步封装,把方法的调用与监听都放在同一个函数里面。
首先是委托的重写。java跟C#不太一样,没有Action这个种系统内置的委托类型,而是通过接口的方式来实现委托的。
拿上面加载场景的例子来说。对应loadSceneComplete与loadSceneProcess这两个回调的方法,需要重新定义两个对应接口的java类

package com.realibox.ar.callback;
public interface LoadSceneCallback{
public void loadSceneAction(float percent);
}
package com.xxx.xxxx.callback;
public interface LoadSceneComleteCallback{
public void loadSceneCompleteAction();
}
然后在上面的UnityCallbackActivity.java进一步修改,代码如下
public class UnityCallbackActivity extends CallbackActivity {
/*
*when scene loading complete, this function will callback
*/
private LoadSceneComleteCallback loadSceneComleteCallback;
@Override
protected void loadSceneComplete() {
if (loadSceneComleteCallback!=null)
loadSceneComleteCallback.loadSceneCompleteAction();
}
/*
* when scene is loading, this function will stay callback
*/
private LoadSceneCallback loadSceneCallback;
@Override
protected void loadSceneProcess(String percent) {
if (loadSceneCallback!=null) {
loadSceneCallback.loadSceneAction(p);
}
}
}
上面实现的逻辑就是当Unity回调这两个事件时,继承这两个接口的类的方法也会触发。
这样的话,在AS工程中,调用场景的方法就可以进一步封装,代码如下:
void Init(){
LoadProject(sceneId,
percent -> {
Log.e(TAG, "percent-"+percent);
},
() -> {
Log.e(TAG, "loadsenecomplete");
});
}
/*
*
* scene_id
* LoadSceneCallback:return percent of load scene
* LoadComleteCallback:callback when finish load scene
*/
protected void LoadProject(String sceneid, String doMain,LoadSceneCallback loadSceneCallback,LoadSceneComleteCallback loadSceneComleteCallback) {
UnityPlayer.UnitySendMessage("gameobj", "LoadScene", sceneid);
this.loadSceneCallback = loadSceneCallback;
this.loadSceneComleteCallback = loadSceneComleteCallback;
}
这样的话当调用加载场景的方法时,可以把加载中与加载完成的回调都当成参数传进方法里面。