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

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中即可。
下面就是我导入完成后的项目结构图

ArMapActivity的布局
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- unity3d layout -->
<LinearLayout
android:id="@+id/layout_unity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</LinearLayout>
<!-- 这边可以加入覆盖到unity的layout -->
</FrameLayout>
先介绍一下 两者之间的调用方法的方式:
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<AndroidJavaObject> ("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中设置一个新的进程。这样,就不会影响你本身项目的进程

这样设置之后,虽然解决了不会崩溃问题,但是有时候退出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,并且响应速度也比较快。
网友评论