Android Unity3D 相互交互,及退出继承UnityPlayerActivity的Crash问题

这是我第一次写博文,只是我做过项目的一些技术点,也就相当于自己的笔记,希望能对看到文章的你有用。
公司项目比较多使用AR,一般我们都是使用第三方SDK,使用的EasyAR。它有两种方式来实现AR功能,第一种是用JNI,使用NDK(自行百度google查找相关技术文章),第二种是Android和Unity3D的交互,Ar图形,模型视频等由Unity3D来完成,Android来处理 加载创建 扫描 脱卡等事件处理(着重讲这部分)。

Unity导出的项目:

我记录Android这部分的操作 不记录Unity3D的
首先你要让Unity的工程师导出一份Android项目给你,当然导出的AS项目(我没用过Eclipse的方式)

Android Unity3D 相互交互,及退出继承UnityPlayerActivity的Crash问题_第1张图片
Unity导出项目结构.png

lib文件下面是要使用的Jar包
src中包括了assets,jniLibs和java文件夹下的UnityPlayerActivity,UnityPlayerNativeActivity,UnityPlayerProxyActivity.建议使用UnityPlayerActivity.java,assets文件中是unity的一些资源文件,包括了场景和渲染的一些文件,jniLibs当然是所用到的.so文件了

  • 如果你已经有Android的工程项目了,此时你只需要把assets的文件和lib中的文件,和jniLibs的文件拷贝到你的项目中去,然后把需要配置的类和权限在AndroidManifest.xml中配置一下(EasyAR需要用到摄像头的权限,在6.0以上的版本也无需去申请权限,SDK中有集成了。如果你不放心 可以再去申请)
  • 没有项目,那么只需要把unity的导出项目直接导入到你的Android Studio中即可。
    下面就是我导入完成后的项目结构图
Android Unity3D 相互交互,及退出继承UnityPlayerActivity的Crash问题_第2张图片
项目结构.png

ArMapActivity的布局


    
    
    
    
 
先介绍一下 两者之间的调用方法的方式:
Android调用Unity的方法

UnityPlayer.UnitySendMessage("ImageTargetManager", "LoadNativeAssetBundle", json);

  • 第一个参数"ImageTargetManager"是Unity Object对象,需要在Unity对象上绑定脚本】
  • 第二个参数"LoadNativeAssetBundle"是Unity 中定义的方法名 (这两个都是Unity工程师会提供给你的)
  • 第三个参数是定义方法的参数(可空)。
Unity调用Android的方法

先在Android自定义一个方法

Android代码
 /**
   * Unity调用此方法并把参数jsonString 调用给Android
   * @param jsonString
   */
 public void Unity3DSendMessage(String jsonString) {
        Log.i("TAG", "[Unity3DSendMessage] " + jsonString);
        final JsonRetrun entity = new Gson().fromJson(jsonString, JsonRetrun.class);
        switch (entity.getActionName()) {
            case "sceneLoaded":
                break;
            case "loadModelAssetCompleted":
                break;
            case "imageTargetBound":
                break;
            case "imageTargetBoundFail":
                break;
            case "TargetFound":
                break;
            case "TargetLost":
                break;
            default:
                break;
        }
    }
Unity代码
AndroidJavaClass jc = new AndroidJavaClass ("com.unity3d.player.UnityPlayer");
AndroidJavaObject jo = jc.GetStatic ("ArMapActivity");
jo.Call ("Unity3DSendMessage","");

jo.call(String str1,String str2);第一个参数是Android的方法名,第二个参数是传递给Android的参数

到这边已经把Android交互Unity的方法方式介绍完成了

发现的一个坑

当你使用玩AR时 点击系统返回或者是自定义的ImageButton返回时, 如果你调用的是onDestroy方法,你会发现应用出现了Crash,如果你单单在点击事件中 finish();该Activity,也会出现Crash。
UnityPlayerActivity中onDestory方法是这么写的

@Override  
protected void onDestroy()  
{  
       mUnityPlayer.quit();  
       super.onDestroy();          
}  

这样写 会使后面的代码不执行了,从而造成Crash
对mUnityPlayer.quit()方法的反编译之后 发现quit方法是这样的

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();
    }

    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();
}

注意倒数第二行的this.kill()方法,不看实现可以猜出应该是杀进程的。所以...

我google百度了不少时间发现了 可以在该Activity的AndroidManifest.xml中设置一个新的进程。这样,就不会影响你本身项目的进程

AndroidManifest设置.png

这样设置之后,虽然解决了不会崩溃问题,但是有时候退出Activity时会卡住一段时间。
我在搜索mUnityPlayer.quit()的时候还看到别人针对这个问题做了另外一种解决,就是重写UnityPlayer类的kill方法(就是上面提到的kill方法,然后再去调用自己重写的方法即可
重写的例子如下:

public class MyUnityPlayer extends UnityPlayer {

    public MyUnityPlayer(ContextWrapper contextWrapper) {
        super(contextWrapper);
    }

    //不执行父类的方法
    @Override
    protected void kill() {

    }
}

然后在有Unity的ArMapActivity中

@Override  
protected void onCreate(Bundle savedInstanceState)  
    {  
      super.onCreate(savedInstanceState);  
      mUnityPlayer = new MyUnityPlayer(this); 
      layoutUnity.addView(mUnityPlayer);
      mUnityPlayer.requestFocus();
    }  

这样子,就能解决退出Activity不Crash,并且响应速度也比较快。

你可能感兴趣的:(Android Unity3D 相互交互,及退出继承UnityPlayerActivity的Crash问题)