1. 程式人生 > >Unity學習筆記007.Unity接入原生Android百度AR地圖

Unity學習筆記007.Unity接入原生Android百度AR地圖

大概操作步驟按筆記006執行。

1.背景

環境:

OS:Windows10
Android Studio3.2
Unity 2018.1.2f1

思路

Unity端:主調方,UI
Android端:底層介面,打包aar方式

2.步驟

2.1 Android Studio基礎配置

2.1.1 新建工程、匯入Unity介面包。

對比百度demo,匯入百度lib,如圖:
在這裡插入圖片描述
模仿demo,新建Activity,如下:
在這裡插入圖片描述

2.1.2 配置app的build.gradle

//apply plugin: 'com.android.application'
apply plugin: 'com.android.library'
android { compileSdkVersion 28 // Add sourceSets { main { //Path to your source code main { jniLibs.srcDir('libs') jni.srcDirs = [] } java { srcDir 'src/main/java' } }
} defaultConfig { // applicationId "com.polin.baiduarmapsdk" minSdkVersion 15 targetSdkVersion 28 // versionCode 1 // versionName "1.0" // testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } // Add lintOptions { abortOnError false } } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' implementation files('libs/android-support-v4.jar') implementation files('libs/BaiduLBS_Android.jar') implementation files('libs/classes.jar') implementation files('libs/gson-2.2.4.jar') implementation files('libs/org.apache.http.legacy.jar') } // Add Backup //task to delete the old jar task deleteOldJar(type: Delete) { delete 'release/BaiduMapKit.jar' } //task to export contents as jar task exportJar(type: Copy) { from('build/intermediates/packaged-classes/release/') into('release/') include('classes.jar') ///Rename the jar rename('classes.jar', 'BaiduMapKit.jar') } exportJar.dependsOn(deleteOldJar, build)

2.1.3 配置AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.polin.baiduarmapsdk">

    <!--訪問相機許可權-->
    <uses-permission android:name="android.permission.CAMERA"/>
    <!--訪問閃光燈-->
    <uses-permission android:name="android.permission.FLASHLIGHT"/>
    <!-- 這個許可權用於進行網路定位-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
    <!-- 這個許可權用於訪問GPS定位-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
    <!-- 用於訪問wifi網路資訊,wifi資訊會用於進行網路定位-->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
    <!-- 獲取運營商資訊,用於支援提供運營商資訊相關的介面-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
    <!-- 這個許可權用於獲取wifi的獲取許可權,wifi資訊會用來進行網路定位-->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
    <!-- 用於讀取手機當前的狀態-->
    <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
    <!-- 寫入擴充套件儲存,向擴充套件卡寫入資料,用於寫入離線定位資料-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
    <!-- 訪問網路,網路定位需要上網-->
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:label="@string/app_name">

        <!-- 開發金鑰 -->
        <meta-data
            android:name="com.baidu.lbsapi.API_KEY"
            android:value="****">
        </meta-data>

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data
                android:name="unityplayer.UnityActivity"
                android:value="true" />
        </activity>
        <activity android:name=".ArActivity" >
            <meta-data
                android:name="unityplayer.UnityActivity"
                android:value="true" />
        </activity>
        <activity android:name=".BuildingArActivity" >
            <meta-data
                android:name="unityplayer.UnityActivity"
                android:value="true" />
        </activity>
        <activity android:name=".SceneryArActivity">
            <meta-data
                android:name="unityplayer.UnityActivity"
                android:value="true" />
        </activity>
        <!-- 接入百度地圖定位SDK -->
        <service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote"></service>
    </application>

</manifest>

2.1.4 嘗試打包成aar

在這裡插入圖片描述
在該目錄下找到aar包,連同AndroidManifest.xml一起,即是我們將放入Unity中的Android資源。
在這裡插入圖片描述
至此,Android Studio端的配置完成。

2.2 Unity端基礎配置

2.2.1 新建工程

2.2.2 填入Android工程包名

2.3 編寫與測試

2.3.1 嘗試在AndroidManifest.xml中新增百度Key,並獲取在其中註冊獲取手機許可權

將MainActivity作為入口,編寫工具類LocSdkClient、PermissionsChecker、UntiyClient。
LocSdkClient:

public class LocSdkClient {
    /**
     *
     * 百度定位sdk 座標獲取工具類
     */
    private static LocSdkClient mInstance = null;
    public LocationClient mLocationClient = null;

    private LocSdkClient(Context context) {

        mLocationClient = new LocationClient(context.getApplicationContext());
        // 宣告LocationClient類
        // mLocationClient.registerLocationListener(myListener);
        // 註冊監聽函式

        LocationClientOption option = new LocationClientOption();

        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
        // 可選,設定定位模式,預設高精度
        // LocationMode.Hight_Accuracy:高精度;
        // LocationMode. Battery_Saving:低功耗;
        // LocationMode. Device_Sensors:僅使用裝置;

        option.setCoorType("bd09");
        // 可選,設定返回經緯度座標型別,預設gcj02
        // gcj02:國測局座標;
        // bd09ll:百度經緯度座標;
        // bd09:百度墨卡託座標;
        // 海外地區定位,無需設定座標型別,統一返回wgs84型別座標

        option.setScanSpan(2000);
        // 可選,設定發起定位請求的間隔,int型別,單位ms
        // 如果設定為0,則代表單次定位,即僅定位一次,預設為0
        // 如果設定非0,需設定1000ms以上才有效

        option.setOpenGps(true);
        // 可選,設定是否使用gps,預設false
        // 使用高精度和僅用裝置兩種定位模式的,引數必須設定為true

        option.setLocationNotify(true);
        // 可選,設定是否當GPS有效時按照1S/1次頻率輸出GPS結果,預設false

        option.setIgnoreKillProcess(false);
        // 可選,定位SDK內部是一個service,並放到了獨立程序。
        // 設定是否在stop的時候殺死這個程序,預設(建議)不殺死,即setIgnoreKillProcess(true)

        option.SetIgnoreCacheException(false);
        // 可選,設定是否收集Crash資訊,預設收集,即引數為false

        option.setWifiCacheTimeOut(5 * 60 * 1000);
        // 可選,7.2版本新增能力
        // 如果設定了該介面,首次啟動定位時,會先判斷當前WiFi是否超出有效期,若超出有效期,會先重新掃描WiFi,然後定位

        option.setEnableSimulateGps(false);
        // 可選,設定是否需要過濾GPS模擬結果,預設需要,即引數為false

        mLocationClient.setLocOption(option);
        // mLocationClient為第二步初始化過的LocationClient物件
        // 需將配置好的LocationClientOption物件,通過setLocOption方法傳遞給LocationClient物件使用
        // 更多LocationClientOption的配置,請參照類參考中LocationClientOption類的詳細說明

        mLocationClient.start();
        // mLocationClient為第二步初始化過的LocationClient物件
        // 呼叫LocationClient的start()方法,便可發起定位請求e
    }

    public LocationClient getLocationStart() {
        return mLocationClient;
    }

    public static LocSdkClient getInstance(Context context) {
        if (mInstance == null) {
            Class var0 = LocSdkClient.class;
            synchronized (LocSdkClient.class) {
                if (mInstance == null) {
                    mInstance = new LocSdkClient(context);
                }
            }
        }
        return mInstance;
    }
}

PermissionsChecker:

/**
 * 許可權申請
 */

public class PermissionsChecker {

    private final Context mContext;

    public PermissionsChecker(Context context) {
        mContext = context.getApplicationContext();
    }
    // 判斷許可權集合
    public boolean lacksPermissions() {
        String[] permissions = new String[] {
//                Manifest.permission.FLASHLIGHT,
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.CAMERA,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.INTERNET,
                Manifest.permission.READ_PHONE_STATE,
                Manifest.permission.CHANGE_WIFI_STATE,
                Manifest.permission.ACCESS_NETWORK_STATE,
                Manifest.permission.ACCESS_WIFI_STATE
        };
        for (String permission : permissions) {
            if (lacksPermission(permission)) {
                return true;
            }
        }
        return false;
    }
    // 判斷是否缺少許可權
    private boolean lacksPermission(String permission) {
        return ContextCompat.checkSelfPermission(mContext, permission) == PackageManager.PERMISSION_DENIED;
    }
}

UntiyClient:

public class UntiyClient extends UnityPlayerActivity {
    /**
     * unity專案啟動時的的上下文
     */
    private static Activity _unityActivity;
    /**
     * 獲取unity專案的上下文
     * @return
     */
    public static Activity GetActivity(){
        if(null == _unityActivity) {
            try {
                Class<?> classtype = Class.forName("com.unity3d.player.UnityPlayer");
                Activity activity = (Activity) classtype.getDeclaredField("currentActivity").get(classtype);
                _unityActivity = activity;
            } catch (ClassNotFoundException e) {

            } catch (IllegalAccessException e) {

            } catch (NoSuchFieldException e) {

            }
        }
        return _unityActivity;
    }

    /**
     * 呼叫Unity的方法
     * @param gameObjectName    呼叫的GameObject的名稱
     * @param functionName      方法名
     * @param args              引數
     * @return                  呼叫是否成功
     */
    public static boolean CallUnity(String gameObjectName, String functionName, String args){
        try {
            Class<?> classtype = Class.forName("com.unity3d.player.UnityPlayer");
            Method method =classtype.getMethod("UnitySendMessage", String.class,String.class,String.class);
            method.invoke(classtype,gameObjectName,functionName,args);
            return true;
        } catch (ClassNotFoundException e) {

        } catch (NoSuchMethodException e) {

        } catch (IllegalAccessException e) {

        } catch (InvocationTargetException e) {

        }
        return false;
    }
}

MainActivity:

public class MainActivity extends UnityPlayerActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_main);
    }

        // MainActivity初始化函式
    public void init(){
        // 判斷許可權
        PermissionsChecker permissionsChecker = new PermissionsChecker(GetActivity());
        if (permissionsChecker.lacksPermissions()) {
            Toast.makeText(GetActivity(), "缺少許可權,請開啟許可權!", Toast.LENGTH_LONG).show();
            openSetting();
        }
        else{
            Toast.makeText(GetActivity(), "許可權已開啟!", Toast.LENGTH_LONG).show();
        }
    }

    /**
     * 開啟設定許可權介面
     *
     * @param
     */
    public void openSetting() {
        Intent intent = new Intent();
        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        Uri uri = Uri.fromParts("package", getPackageName(), null);
        intent.setData(uri);
        startActivity(intent);
    }
}

在Unity中建立MainActivity初始化測試按鈕:
在這裡插入圖片描述

匯出aar包與AndroidManifest.xml到Unity的Plugins/Android中,編寫Unity主調指令碼:

public class UIControl : MonoBehaviour {

	// Use this for initialization
	void Start () {
        transform.Find("MainActivityInit").GetComponent<Button>().onClick.AddListener(InitMainActivity);       
    }

    public void InitMainActivity()
    {
        AndroidJavaClass unity = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject currentActivity = unity.GetStatic<AndroidJavaObject>("currentActivity");
        currentActivity.Call("init");
    }
}

打包apk
報錯1.
在這裡插入圖片描述
解決方案1.
把Unity打包方式從Gradle改為Internal。
報錯2.
在這裡插入圖片描述
解決方案2.
報錯資訊顯示:aar包中的Unity介面包classes.jar重複了,那就刪掉。
用壓縮軟體開啟aar包,找到libs目錄下的classes.jar,刪除此包。
在這裡插入圖片描述
報錯3.
在這裡插入圖片描述
解決方案3.
這些資源找不到,再次開啟aar包,找到./res/values/values.xml並進行修改:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorAccent">#D81B60</color>
    <color name="colorPrimary">#008577</color>
    <color name="colorPrimaryDark">#00574B</color>
    <string name="app_name">BaiduArMapSDK</string>
    <style name="AppTheme" parent="android:Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="android:colorPrimary">@color/colorPrimary</item>
        <item name="android:colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="android:colorAccent">@color/colorAccent</item>
    </style>
</resources>

報錯4.
在這裡插入圖片描述
解決方案4.
依然找不到這個主題,我們就不用它了

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorAccent">#D81B60</color>
    <color name="colorPrimary">#008577</color>
    <color name="colorPrimaryDark">#00574B</color>
    <string name="app_name">BaiduArMapSDK</string>
    <style name="AppTheme" parent="android:Theme.Light">
        <!-- Customize your theme here. -->
        <item name="android:colorPrimary">@color/colorPrimary</item>
        <item name=