重拾百度定位之踩坑篇(上)
前言
最近更新項目中用的百度定位SDK時遇見了一個奇葩的問題。當升級SDK后百度定位一直返回505,通過百度定位官網查看該碼表示AK非法或者不存在。很糾結,于是自己又寫了一個demo來研究一下百度定位以及大家使用百度定位經常出現的問題,特此記錄。這篇文章我先將百度定位的實現也介紹一下,最后再分析遇到的問題及解決方案。
定位分析
目前百度定位提供了WIFI,基站,GPS等多種定位方式,適用于室內、室外多種定位場景,具有出色的定位性能:定位精度高(其實我是想吐槽的)、覆蓋率廣、網絡定位請求流量小、定位速度快。
集成定位SDK
現在官網提供的最新的定位SDK版本是v7.0,官網SDK下載地址請戳 定位SDK,可根據自己的需要下載,在這里我進入全部下載,只下載了全量定位。在新版本V7.0中百度將定位對開發包實現了分離
(1)基礎定位:開發包體積最小,但只包含基礎定位能力(GPS/WiFi/基站)、基礎位置描述能力;
(2)離線定位:在基礎定位能力基礎之上,提供離線定位能力,可在網絡環境不佳時,進行精準定位;
(3)室內定位:在基礎定位能力基礎之上,提供室內高精度定位能力,精度可達1-3米;
(4)全量定位:包含離線定位、室內高精度定位能力,同時提供更人性化的位置描述服務;
對于這四種類型定位開發包是互斥的,一個應用中只需集成一種定位開發包即可。下載成功之后,將jar包和.so文件放到對應的文件下即可。
申請秘鑰
使用百度定位,我們需要在官網申請一個AK,項目定位時需要使用這個Ak,一個應用對于一個AK,AK申請時需要提供包名及SHA1值。具體方式
可去官網查看。在這里我簡單介紹下SHA1獲取方式。在申請Ak時,頁面填寫發布版SHA1和開發版SHA1。下面我提供兩種方式獲取SHA1值。
AndroidStudio Terminal獲取
- -rfc 以 RFC 樣式輸出
- -alias <alias> 要處理的條目的別名
- -keystore <keystore> 密鑰庫名稱
- -storepass <arg> 密鑰庫口令
- -storetype <storetype> 密鑰庫類型
- -providername <providername> 提供方名稱
- -providerclass <providerclass> 提供方類名
- -providerarg <arg> 提供方參數
- -providerpath <pathlist> 提供方類路徑
- -v 詳細輸出
- -protected 通過受保護的機制的口令
上面是獲取密鑰庫信息的一些命令,則在此獲取SHA1可以
- keytool -v -list -keystore 【密鑰庫文件路徑】 -storepass 【密鑰庫文件密碼】
在Terminal執行命令后就出現上面的詳細信息。SHA1后面的那一串字符就是我們需要的SHA1.
CMD方式
如果要在CMD中獲取,必須先要設置環境變量,具體設置方式可谷歌搜索。當然獲取的命令和在AndroidStudio中獲取是一樣的。在上面我獲取下開發版SHA1。對于debug版一般存用戶下的.android目錄下,我們打開CMD后執行 cd .android然后通過dir就可以看到目錄下會有一個debug.keystore文件,我們找的就是它。
在圖中你會看到沒有寫-storepass參數(當然也可和上面一樣)。在回車后會提示輸入密鑰庫口令,對于我們的debug版本口令默認是android,輸入后回車即可看到詳細信息了。
環境配置
要想實現定位,我們必須在清單文件中加入一些必要的權限以及key等信息,如下
- <!--百度定位權限相關-->
- <!-- 這個權限用于進行網絡定位-->
- <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" />
- <!-- SD卡讀取權限,用戶寫入離線定位數據-->
- <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"> </uses-permission>
- <application
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:supportsRtl="true"
- android:theme="@style/AppTheme">
- <service
- android:name="com.baidu.location.f"
- android:enabled="true"
- android:process=":remote" >
- </service>
- <meta-data
- android:name="com.baidu.lbsapi.API_KEY"
- android:value="w7NQOKL8SpxHrs6lixBNoe90" />
- </application>
定位實現
對于定位的實現我們可以分為三步,第一步:初始化LocationClient;第二步:通過LocationClientOption設置定位參數;第三步:實現BDLocationListener接口。看著是不是很簡單,你沒看錯,確實很簡單。
初始化LocationClient
- /**
- * 獲取LocationService實例
- *
- * @param context
- * @return
- */
- public static LocationService getInstance(Context context) {
- if (locationClient == null) {
- synchronized (LocationService.class) {
- locationService= new LocationService(context);
- }
- }
- return locationService;
- }
- private LocationService(Context context) {
- if (locationClient == null) {
- locationClient = new LocationClient(context);
- locationClient.setLocOption(getDefaultLocationClientOption());
- }
- }
設置定位參數
- /***
- * 配置參數
- *
- * @return DefaultLocationClientOption
- */
- public LocationClientOption getDefaultLocationClientOption() {
- if (locationClientOption == null) {
- locationClientOption = new LocationClientOption();
- locationClientOption.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);//可選,默認高精度,設置定位模式,高精度,低功耗,僅設備
- locationClientOption.setCoorType("bd09ll");//可選,默認gcj02,設置返回的定位結果坐標系,如果配合百度地圖使用,建議設置為bd09ll;
- locationClientOption.setScanSpan(3000);//可選,默認0,即僅定位一次,設置發起定位請求的間隔需要大于等于1000ms才是有效的
- locationClientOption.setIsNeedAddress(true);//可選,設置是否需要地址信息,默認不需要
- locationClientOption.setIsNeedLocationDescribe(true);//可選,設置是否需要地址描述
- locationClientOption.setNeedDeviceDirect(true);//可選,設置是否需要設備方向結果
- locationClientOption.setLocationNotify(true);//可選,默認false,設置是否當gps有效時按照1S1次頻率輸出GPS結果
- locationClientOption.setIgnoreKillProcess(true);//可選,默認true,定位SDK內部是一個SERVICE,并放到了獨立進程,設置是否在stop的時候殺死這個進程,默認不殺死
- locationClientOption.setIsNeedLocationDescribe(true);//可選,默認false,設置是否需要位置語義化結果,可以在BDLocation.getLocationDescribe里得到,結果類似于“在北京天安門附近”
- locationClientOption.setIsNeedLocationPoiList(true);//可選,默認false,設置是否需要POI結果,可以在BDLocation.getPoiList里得到
- locationClientOption.SetIgnoreCacheException(false);//可選,默認false,設置是否收集CRASH信息,默認收集
- locationClientOption.setIsNeedAltitude(false);//可選,默認false,設置定位時是否需要海拔信息,默認不需要,除基礎定位版本都可用
- }
- return locationClientOption;
- }
接下文