1. 程式人生 > >從零構建AR APP新手教程【Android篇】(4)-APP互動邏輯及嵌入呼叫Unity

從零構建AR APP新手教程【Android篇】(4)-APP互動邏輯及嵌入呼叫Unity

學習AR應用開發有一段時間了,自己開發了一款簡單的APP來練手,在這裡分享給大家。

前面介紹了Unity3D部分的實現,現在就來介紹Android原生部分的編碼實現。

1.APP基礎UI框架及互動邏輯


首頁就是簡單的ViewPager+Fragment,其中資料用RecyclerView展示。點選某項Item進入詳情頁,並傳入引數target name,target name就是vuforia建立的識別圖的名稱。
詳情頁載入SVG圖片,這裡使用VectorDrawable做了一個簡單的顏色變換效果,點選下方的按鈕就會呼叫Unity做的AR功能。

2.原生呼叫Unity

1)新建Activity繼承UnityPlayerActivity
public class 
UnityMainActivity extends UnityPlayerActivity {}
2)新建佈局檔案activity_unity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width=
"match_parent" android:layout_height="match_parent" android:background="#000" tools:context="com.cdh.paperup.ui.UnityMainActivity"> <FrameLayout android:id="@+id/flUnityContainer" android:layout_width="match_parent" android:layout_height="match_parent"/> <Button android:id="@+id/btnClose"
android:layout_width="28dp" android:layout_height="28dp" android:layout_margin="10dp" android:background="@mipmap/btn_close"/> </RelativeLayout>
FrameLayout用於載入UnityPlayer顯示Unity場景,Button用於關閉按鈕。 3)接著在AndroidManifest中定義
<activity
android:name=".ui.UnityMainActivity"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density"
android:launchMode="singleTask"
android:screenOrientation="landscape">
    <meta-data
android:name="unityplayer.UnityActivity"
android:value="true" />
</activity>
4)在Activity中新增UnityPlayer並呼叫
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
setContentView(R.layout.activity_unity_main);
ButterKnife.bind(this);
key = getIntent().getStringExtra("key"); //key即targetName
flUnityContainer.addView(mUnityPlayer);  //新增UnityPlayer到佈局中
mUnityPlayer.requestFocus();
mUnityPlayer.UnitySendMessage("TargetManager", "ConfigTrackable", key); //呼叫Unity方法
}
mUnityPlayer.UnitySendMessage(String, String, String)這個就是Android原生呼叫Unity的方法: 第一個引數是Unity指令碼所在GameObject的名稱; 第二個引數是指令碼中定義函式名稱; 第三個引數是傳遞給函式的引數(可空)。

5)新增關閉方法
@OnClick(R.id.btnClose)
public void onViewClicked() {
    finish();
}
到這裡可以執行檢視效果了,但是細心的人會發現一個問題,就是當點選關閉按鈕即呼叫finish()方法退出會造成整個APP所在程序退出,平時我們呼叫finish()只是當前Activity退出,要找到原因就要檢視原始碼了。 因為我們的Activity繼承的是UnityPlayerActivity,在這個類中定義了finish方法,所以在子Activity中呼叫退出實際是呼叫了父類的finish方法:
@Override
public void finish() {
    mUnityPlayer.quit();  //問題關鍵在這裡
    super.finish();  //這裡是呼叫Activity的finish方法,即平時正常的呼叫的方法
}
進入mUnityPlayer.quit()方法:
public void quit() {
    if(GoogleVrApi.b() != null) {
        GoogleVrApi.a();
}

    this.q = 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.n.unregisterReceiver(this.g);
}

    this.g = null;
    if(l.c()) {
        this.removeAllViews();
}

    this.kill();  //呼叫了kill方法
g();
}
可以看到一個kill方法,顧名思義就是這裡真正執行銷燬的方法,進入檢視:
protected void kill() {
    Process.killProcess(Process.myPid());  //銷燬當前程序
}
看到原來是這裡銷燬了當前所在程序,找到原因就好解決問題了。 新建class繼承UnityPlayer,UnityPlayer中的kill方法是protected修飾,所以可以在子類重新kill方法:
public class AndUnityPlayer extends UnityPlayer {

    public AndUnityPlayer(Context context) {
        super(context);
}

    @Override
protected void kill() {
    }
}
修改UnityPlayerActivity中的onCreate方法:
// Setup activity layout
@Override protected void onCreate(Bundle savedInstanceState)
{
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    super.onCreate(savedInstanceState);
mUnityPlayer = new AndUnityPlayer(this); //將UnityPlayer替換成AndUnityPlayer
}
大功告成,解決了finish問題。 執行起來的效果就是這樣:
到這裡就介紹完畢了,這幾篇教程只是籠統的講解編寫AR APP的簡單流程,因為我自己學習AR開發也沒有多長時間,所以很多地方講解的不夠細緻。