本文的目的是讲解一下为什么要这样写,以及如何变通。基本的交互参考上面提到的文章就可以了。
先简单说下上面提到的文章中的基本交互步骤:
这是unity导出的工程基本的目录结构:
会自动生成3个activity。assets和libs是用到的资源和库。Android端用的时候吧这些东西拷贝到自己的工程中就行了,Manifest中的代码合并一下。需要交互的方法全部写到UnityPlayerActivity中即可,按照上面链接的教程就可以实现交互。
然而,但是,我们第一次按照教程做的时候死活不行,交互不了,为什么呢?
我们当时的操作是:自己写了一个Activity,继承自UnityPlayerActivity,然后manifest中的unity的Activity换成自己的
然后Unity调用Android的方法交互各种无效果。为什么呢?
坑1
在说为什么之前,先说这里的一个坑:Unity的Activity一旦启动就不能finish,为什么?看代码:
@Override protected void onDestroy ()
{
mUnityPlayer.quit();
super.onDestroy();
}
上面的这段代码是UnityPlayerActivity中自动生成的,调用了mUnityPlayer.quit()
,看下quit是怎么实现的:
protected void kill() {
Process.killProcess(Process.myPid());
}
public void quit() {
this.k = true;
if(!this.e.e()) {
this.pause();
}
this.a.a();
try {
this.a.join(4000L);
} catch (InterruptedException var1) {
this.a.interrupt();
}
g.Log(4, "onDestroy");
if(this.g != null) {
this.h.unregisterReceiver(this.g);
}
this.g = null;
if(l.c()) {
this.removeAllViews();
}
if(i.b) {
i.g.a(this.h);
}
this.kill();
h();
}
重点看quit代码的倒数第二行,调用了kill,而kill直接把当前进程干掉了,纳尼???我是要关闭页面不是退出应用啊!
好吧,既然你这么霸道,我启动以后不关闭你总可以了吧,但是我退出应用总应该关闭你吧?然而这里又出现了一个坑:
坑2
unity的Activity直接finish绝大多数的手机会被认为应用是异常关闭,发生重启,我X坑啊
解决办法,在handler中post一下:
new Handler().post(new Runnable() {
@Override
public void run() {
// 调用UnityActivity的finish方法
}
});
为啥要这样写?我也不知道,试出来的…
好了,说完坑了,再说一下为什么我的交互会失败呢?
先说我们交互成功的写法:
1 Android调用Unity的方法,这个是没问题的:
// 第一个参数是unity中的交互脚本所挂在的物体的名字,第二个是方法名,第三个是参数
// 下面这行代码的意思是交互脚本挂在了LoadingManager上,交互方法叫message
UnityPlayer.UnitySendMessage("LoadingManager", "message", type);
2 Unity调用Android:
在我们自己的UnityActivity中,有方法method()
供unity调用:
// 继承自自动生成的UnityPlayerActivity进行我们自定义的代码编写
public class UnityActivity extends UnityPlayerActivity{
// 自身的引用
public static Activity mActivity;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mActivity = this;
}
// 暴露给unity的方法
public void method(){
}
}
unity中调用方式为:
private AndroidJavaObject m_activity;
void Awake()
{
// 获取自己定义的Activity的实例
AndroidJavaClass jc = new AndroidJavaClass("自定义的Activity所在的包名.UnityActivity");
// 拿到mActivity变量
m_activity = jc.GetStatic<AndroidJavaObject>("mActivity");
}
public void callAndroidMethod() {
// 调用Android中暴露的方法
m_activity.Call("method");
}
每个参数的意思都写明白了,小伙伴可以按照这个格式去实现自己的交互。
最后说一下为什么我们按照文章开始提到的教程写的交互方式没有成功。那篇教程中的交互方式在unity中是这样写的:
注释1
using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
using( AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity"))
{
//调用Android插件中UnityTestActivity中StartActivity0方法,stringToEdit表示它的参数
jo.Call("StartActivity0",stringToEdit);
}
}
自动生成的UnityPlayerActivity
代码片段:
protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code
// Setup activity layout
@Override protected void onCreate (Bundle savedInstanceState)
{
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
getWindow().setFormat(PixelFormat.RGBX_8888); // <--- This makes xperia play happy
mUnityPlayer = new UnityPlayer(this);
setContentView(mUnityPlayer);
mUnityPlayer.requestFocus();
}
在Activity中实例化了一个UnityPlayer 对象,且Activity自身作为参数,再看UnityPlayer 的代码片段:
public static Activity currentActivity = null;
public UnityPlayer(ContextWrapper var1) {
super(var1);
if(var1 instanceof Activity) {
currentActivity = (Activity)var1;
}
...
}
将UnityPlayerActivity的引用赋值给了一个静态变量currentActivity
,看到这里大家就应该明白了,前面我标注释1位置的代码中是获得了UnityPlayer
的currentActivity
变量,而currentActivity
是UnityPlayerActivity
的引用。我做交互的时候自己写了一个类UnityActivity
继承UnityPlayerActivity
,unity中调用的方法都写在了UnityActivity
中。currentActivity 是父类引用,调用不到子类UnityActivity
中的方法,因此交互是无法做到的,如果按照这篇博客中的方法,所有的交互都必须写在UnityPlayerActivity
中。虽然这样没有什么错误,但是毕竟UnityPlayerActivity
是自动生成的,在里面直接写我们的代码不太好。写一个子类实现我们的交互以及额外的业务逻辑是比较符合实际开发流程的。