這是我第一次寫博文鸠真,只是我做過項目的一些技術(shù)點悯仙,也就相當于自己的筆記,希望能對看到文章的你有用吠卷。
公司項目比較多使用AR锡垄,一般我們都是使用第三方SDK,使用的EasyAR祭隔。它有兩種方式來實現(xiàn)AR功能货岭,第一種是用JNI,使用NDK(自行百度google查找相關(guān)技術(shù)文章)疾渴,第二種是Android和Unity3D的交互千贯,Ar圖形,模型視頻等由Unity3D來完成搞坝,Android來處理 加載創(chuàng)建 掃描 脫卡等事件處理(著重講這部分)搔谴。
Unity導出的項目:
我記錄Android這部分的操作 不記錄Unity3D的
首先你要讓Unity的工程師導出一份Android項目給你,當然導出的AS項目(我沒用過Eclipse的方式)
lib文件下面是要使用的Jar包
src中包括了assets,jniLibs和java文件夾下的UnityPlayerActivity,UnityPlayerNativeActivity,UnityPlayerProxyActivity.建議使用UnityPlayerActivity.java桩撮,assets文件中是unity的一些資源文件敦第,包括了場景和渲染的一些文件峰弹,jniLibs當然是所用到的.so文件了
- 如果你已經(jīng)有Android的工程項目了,此時你只需要把assets的文件和lib中的文件芜果,和jniLibs的文件拷貝到你的項目中去鞠呈,然后把需要配置的類和權(quán)限在AndroidManifest.xml中配置一下(EasyAR需要用到攝像頭的權(quán)限,在6.0以上的版本也無需去申請權(quán)限右钾,SDK中有集成了蚁吝。如果你不放心 可以再去申請)
- 沒有項目,那么只需要把unity的導出項目直接導入到你的Android Studio中即可舀射。
下面就是我導入完成后的項目結(jié)構(gòu)圖
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>
先介紹一下 兩者之間的調(diào)用方法的方式:
Android調(diào)用Unity的方法
UnityPlayer.UnitySendMessage("ImageTargetManager", "LoadNativeAssetBundle", json);
- 第一個參數(shù)"ImageTargetManager"是Unity Object對象灭将,需要在Unity對象上綁定腳本】
- 第二個參數(shù)"LoadNativeAssetBundle"是Unity 中定義的方法名 (這兩個都是Unity工程師會提供給你的)
- 第三個參數(shù)是定義方法的參數(shù)(可空)。
Unity調(diào)用Android的方法
先在Android自定義一個方法
Android代碼
/**
* Unity調(diào)用此方法并把參數(shù)jsonString 調(diào)用給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);第一個參數(shù)是Android的方法名后控,第二個參數(shù)是傳遞給Android的參數(shù)
到這邊已經(jīng)把Android交互Unity的方法方式介紹完成了
發(fā)現(xiàn)的一個坑
當你使用玩AR時 點擊系統(tǒng)返回或者是自定義的ImageButton返回時, 如果你調(diào)用的是onDestroy方法空镜,你會發(fā)現(xiàn)應(yīng)用出現(xiàn)了Crash浩淘,如果你單單在點擊事件中 finish();該Activity,也會出現(xiàn)Crash吴攒。
UnityPlayerActivity中onDestory方法是這么寫的
@Override
protected void onDestroy()
{
mUnityPlayer.quit();
super.onDestroy();
}
這樣寫 會使后面的代碼不執(zhí)行了张抄,從而造成Crash
對mUnityPlayer.quit()方法的反編譯之后 發(fā)現(xiàn)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();
}
注意倒數(shù)第二行的this.kill()方法,不看實現(xiàn)可以猜出應(yīng)該是殺進程的洼怔。所以...
我google百度了不少時間發(fā)現(xiàn)了 可以在該Activity的AndroidManifest.xml中設(shè)置一個新的進程署惯。這樣,就不會影響你本身項目的進程
這樣設(shè)置之后镣隶,雖然解決了不會崩潰問題极谊,但是有時候退出Activity時會卡住一段時間。
我在搜索mUnityPlayer.quit()的時候還看到別人針對這個問題做了另外一種解決安岂,就是重寫UnityPlayer類的kill方法(就是上面提到的kill方法轻猖,然后再去調(diào)用自己重寫的方法即可
重寫的例子如下:
public class MyUnityPlayer extends UnityPlayer {
public MyUnityPlayer(ContextWrapper contextWrapper) {
super(contextWrapper);
}
//不執(zhí)行父類的方法
@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域那,并且響應(yīng)速度也比較快咙边。