Android与Unity交互以及各种踩的坑

建议先看一下这篇文章热身一下:http://www.xuanyusong.com/archives/676

本文会对这种实现方法的问题进行分析并详细讲解优化后的交互实现和每个参数的意思

本文的目的是讲解一下为什么要这样写,以及如何变通。基本的交互参考上面提到的文章就可以了。

先简单说下上面提到的文章中的基本交互步骤:
这是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位置的代码中是获得了UnityPlayercurrentActivity变量,而currentActivityUnityPlayerActivity的引用。我做交互的时候自己写了一个类UnityActivity继承UnityPlayerActivity,unity中调用的方法都写在了UnityActivity中。currentActivity 是父类引用,调用不到子类UnityActivity中的方法,因此交互是无法做到的,如果按照这篇博客中的方法,所有的交互都必须写在UnityPlayerActivity中。虽然这样没有什么错误,但是毕竟UnityPlayerActivity是自动生成的,在里面直接写我们的代码不太好。写一个子类实现我们的交互以及额外的业务逻辑是比较符合实际开发流程的。

以上。吐槽:为了更好地开发Android和unity,硬是把unity入门了。。。

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值