首先進(jìn)入百度地圖開發(fā)者中心,找到鷹眼軌跡。按照開發(fā)指南首先申請(qǐng)密鑰,即獲取百度要求的sha1值,在Android studio控制臺(tái)G:\android2016\LBSdemo>下輸入keytool -list -v -keystore D:\key\lbsdemo.jks提示'keytool' 不是內(nèi)部或外部命令,也不是可運(yùn)行的程序。可能是我打開方式不對(duì),于是我到命令行窗口在Java的安裝目錄下找到keytool命令,
那么按照提示輸入
其中命令-keystore后的目錄是Android Studio在打包時(shí)開發(fā)者設(shè)置的key的路徑,接著會(huì)讓你輸入當(dāng)時(shí)設(shè)置的密碼,密碼輸入時(shí)不顯示,回車即可。http://lbsyun.baidu.com/index.php?title=android-yingyan/guide/key此處有官方圖文引導(dǎo)。
下一步配置工程,下載庫文件解壓后將庫粘到libs文件夾下,并在app的build gradle 添加
sourceSets { main { jniLibs.srcDir 'libs' } }
接下來配置清單文件:(直接從官網(wǎng)上粘)
1、在Application標(biāo)簽中聲明SERVICE組件,每個(gè)APP擁有自己獨(dú)立的鷹眼追蹤service
<service android:name="com.baidu.trace.LBSTraceService" android:enabled="true" android:process=":remote"> </service>
2、聲明使用權(quán)限:
<!-- 這個(gè)權(quán)限用于進(jìn)行網(wǎng)絡(luò)定位--> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission> <!-- 這個(gè)權(quán)限用于訪問GPS定位--> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission> <!-- 用于訪問wifi網(wǎng)絡(luò)信息,wifi信息會(huì)用于進(jìn)行網(wǎng)絡(luò)定位--> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission> <!-- 獲取運(yùn)營商信息,用于支持提供運(yùn)營商信息相關(guān)的接口--> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission> <!-- 這個(gè)權(quán)限用于獲取wifi的獲取權(quán)限,wifi信息會(huì)用來進(jìn)行網(wǎng)絡(luò)定位--> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission> <!-- 用于讀取手機(jī)當(dāng)前的狀態(tài)--> <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission> <!-- 寫入擴(kuò)展存儲(chǔ),向擴(kuò)展卡寫入數(shù)據(jù),用于寫入對(duì)象存儲(chǔ)BOS數(shù)據(jù)--> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> <!-- 訪問網(wǎng)絡(luò),網(wǎng)絡(luò)定位需要上網(wǎng)--> <uses-permission android:name="android.permission.INTERNET" /> <!-- SD卡讀取權(quán)限,用于寫入對(duì)象存儲(chǔ)BOS數(shù)據(jù)--> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"></uses-permission> <!-- 用于加快GPS首次定位--> <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"></uses-permission> <!-- 用于Android M及以上系統(tǒng),申請(qǐng)加入忽略電池優(yōu)化白名單--> <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"></uses-permission>
在Mainfest.xml正確設(shè)置AccessKey(ak),如果設(shè)置錯(cuò)誤將會(huì)導(dǎo)致鷹眼服務(wù)無法正常使用。需在Application標(biāo)簽中加入以下代碼,并填入開發(fā)者自己的 Android 類型 ak。meta-data與activity同一級(jí)。
AK就是剛剛拿SHA1申請(qǐng)的那個(gè)字符串。
<meta-data android:name="com.baidu.lbsapi.API_KEY" android:value="AK" /> //key:開發(fā)者申請(qǐng)的Key
import相關(guān)類:
import com.baidu.trace.Trace; import com.baidu.trace.LBSTraceClient; import com.baidu.trace.model.OnCustomAttributeListener;import com.baidu.trace.model.OnTraceListener;import com.baidu.trace.api.track.OnTrackListener; import com.baidu.trace.api.fence.OnFenceListener; import com.baidu.trace.api.entity.OnEntityListener;import com.baidu.trace.api.analysis.OnAnalysisListener;import com.baidu.trace.api.bos.OnBosListener;
以上就是官網(wǎng)上配置工程一節(jié)的介紹。
結(jié)果,震驚的是,官方demo竟然調(diào)不起來,看Log
看了論壇的帖子,才意識(shí)到我上面獲取的是發(fā)布版本的SHA1,而調(diào)試的時(shí)候應(yīng)該用debug的SHA1,那我想的對(duì)不對(duì)試試就知道了
deblug的SHA1:B2:31:7E:C6:53:FE:4A:1B:E6:C8:B0:24:F5:0A:F5:E4:07:60:A6:BA
release的SHA1:02:D4:70:1E:FD:31:AA:C0:E9:8B:05:E7:DF:0C:DC:99:5D:84:4A:0A
那拿著這個(gè)字符串再去百度申請(qǐng)ak,結(jié)果,我沉默了,又走了彎路,還是沒調(diào)起來。
我真是醉了,我在命令行拿到的SHA1竟然和論壇下載的工具獲得的SHA1不一樣。日狗了。換了SHA1重新設(shè)置一下調(diào)起來了。接下來就是分析demo移植了。
第二天咱們來分析demo中是如何獲得 手機(jī)位置信息并繪制軌跡曲線的。
在TrackApplication中的OnCreate(),
1 @Override 2 public void onCreate() { 3 super.onCreate(); 4 mContext = getApplicationContext(); 5 entityName = CommonUtil.getImei(this); 6 // 若為創(chuàng)建獨(dú)立進(jìn)程,則不初始化成員變量 7 if ("com.baidu.track:remote".equals(CommonUtil.getCurProcessName(mContext))) { 8 return; 9 }10 SDKInitializer.initialize(mContext);11 initView();12 initNotification();13 mClient = new LBSTraceClient(mContext);14 mTrace = new Trace(serviceId, entityName);15 mTrace.setNotification(notification);16 trackConf = getSharedPreferences("track_conf", MODE_PRIVATE);17 locRequest = new LocRequest(serviceId);18 mClient.setOnCustomAttributeListener(new OnCustomAttributeListener() {19 @Override20 public Map<String, String> onTrackAttributeCallback() {21 Map<String, String> map = new HashMap<>();22 map.put("key1", "value1");23 map.put("key2", "value2");24 return map;25 }26 });27 clearTraceStatus();28 }
做了一部分初始化的工作:entityName是設(shè)備的IMEI號(hào),在通知欄添加了應(yīng)用通知Notification告知用戶服務(wù)正在運(yùn)行,實(shí)例化軌跡客戶端LBSTraceClient、軌跡服務(wù)Trace,Trace有多個(gè)構(gòu)造方法,并且給軌跡服務(wù)設(shè)置Notification。創(chuàng)建SharedPreference來存儲(chǔ)軌跡服務(wù)的配置信息。實(shí)例化定位請(qǐng)求LocRequest,mClient.setOnCustomAttributeListener()是為了自定義參數(shù),官方解釋是:
為實(shí)現(xiàn)自定義屬性數(shù)據(jù)上傳,開發(fā)者須重寫OnCustomAttributeListener監(jiān)聽器中的onTrackAttributeCallback()接口,調(diào)用 LBSTraceClient.setOnCustomAttributeListener()方法設(shè)置自定義屬性監(jiān)聽器,并按照設(shè)置的定位周期更新onTrackAttributeCallback()的返回值。SDK每采集一次軌跡,便會(huì)自動(dòng)回調(diào)onTrackAttributeCallback()接口,獲取屬性值并寫入當(dāng)前軌跡點(diǎn)的屬性字段中。自定義屬性監(jiān)聽器需通過LBSTraceClient.setOnCustomAttributeListener()進(jìn)行設(shè)置,LBSTraceService只回調(diào)最新設(shè)置的自定義監(jiān)聽器。onTrackAttributeCallback()的返回值是Map<String, String>類型,每個(gè)對(duì)象都是一個(gè)<key,value>對(duì),其中key為entity的自定義字段名稱,value為值。
clearTraceStatus():
/** * 清除Trace狀態(tài):初始化app時(shí),判斷上次是正常停止服務(wù)還是強(qiáng)制殺死進(jìn)程,根據(jù)trackConf中是否有is_trace_started字段進(jìn)行判斷。 * <p> * 停止服務(wù)成功后,會(huì)將該字段清除;若未清除,表明為非正常停止服務(wù)。 */ private void clearTraceStatus() { if (trackConf.contains("is_trace_started") || trackConf.contains("is_gather_started")) { SharedPreferences.Editor editor = trackConf.edit(); editor.remove("is_trace_started"); editor.remove("is_gather_started"); editor.apply(); } }
在TracingActivity如圖,這個(gè)布局就是com.baidu.mapapi.map.MapView和下方兩個(gè)按鈕。在OnCreate()的init()初始化三個(gè)監(jiān)聽器和地圖繪制的一些工具類,主要關(guān)注點(diǎn)擊兩個(gè)按鈕后事件的邏輯。
1 private void init() { 2 initListener(); 3 trackApp = (TrackApplication) getApplicationContext(); 4 viewUtil = new ViewUtil(); 5 mapUtil = MapUtil.getInstance(); 6 mapUtil.init((MapView) findViewById(R.id.tracing_mapView)); 7 mapUtil.setCenter(trackApp); 8 startRealTimeLoc(Constants.LOC_INTERVAL); 9 powerManager = (PowerManager) trackApp.getSystemService(Context.POWER_SERVICE);10 11 traceBtn = (Button) findViewById(R.id.btn_trace);12 gatherBtn = (Button) findViewById(R.id.btn_gather);13 traceBtn.setOnClickListener(this);14 gatherBtn.setOnClickListener(this);15 setTraceBtnStyle();16 setGatherBtnStyle();17 notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);18 }
第8行startRealTimeLoc()看方法名開啟實(shí)時(shí)定位,傳入實(shí)時(shí)定位間隔單位是秒,方法實(shí)例化了一個(gè)內(nèi)部類runnable,并把這個(gè)runnable對(duì)象發(fā)送到handler處理。這個(gè)runnable的子線程調(diào)用了TrackApplication的getCurrentLocation()獲取當(dāng)前位置。
public void startRealTimeLoc(int interval) { realTimeLocRunnable = new RealTimeLocRunnable(interval); realTimeHandler.post(realTimeLocRunnable); }
getCurrentLocation(OnEntityListener entityListener, OnTrackListener trackListener)需要傳入兩個(gè)監(jiān)聽器,在這個(gè)方法中,
1 /** 2 * 獲取當(dāng)前位置 3 */ 4 public void getCurrentLocation(OnEntityListener entityListener, OnTrackListener trackListener) { 5 // 網(wǎng)絡(luò)連接正常,開啟服務(wù)及采集,則查詢糾偏后實(shí)時(shí)位置;否則進(jìn)行實(shí)時(shí)定位 6 if (NetUtil.isNetworkAvailable(mContext) 7 && trackConf.contains("is_trace_started") 8 && trackConf.contains("is_gather_started") 9 && trackConf.getBoolean("is_trace_started", false)10 && trackConf.getBoolean("is_gather_started", false)) {11 LatestPointRequest request = new LatestPointRequest(getTag(), serviceId, entityName);12 ProcessOption processOption = new ProcessOption();13 processOption.setNeedDenoise(true);14 processOption.setRadiusThreshold(100);15 request.setProcessOption(processOption);16 mClient.queryLatestPoint(request, trackListener);17 } else {18 mClient.queryRealTimeLoc(locRequest, entityListener);19 }20 }
判斷是否開啟了軌跡服務(wù)和軌跡采集和網(wǎng)絡(luò)連接確定查詢糾偏后實(shí)時(shí)位置或者進(jìn)行實(shí)時(shí)定位。構(gòu)造請(qǐng)求參數(shù)和選項(xiàng)請(qǐng)求位置。
回到剛才的startRealTimeLoc(int interval),傳入的interval間隔也是handler發(fā)送消息的間隔。而這個(gè)handler在demo中只是簡(jiǎn)單的繼承Handler并沒有自定義handlerMessage()的邏輯。這就是個(gè)循環(huán)。輪詢?cè)O(shè)備的位置。
在初始化監(jiān)聽時(shí),OnTrackListener()重寫了onLatestPointCallback(LatestPointResponse response)方法,其中判斷response的返回碼以及返回的點(diǎn)不是原點(diǎn)后將點(diǎn)轉(zhuǎn)化為地圖上的點(diǎn)并調(diào)用mapUtil.updateStatus(currentLatLng,true)繪制點(diǎn)。OnEntityListener()重寫了onReceiveLocation(TraceLocation location),與上面類似。OnTraceListener()中重寫了開啟軌跡服務(wù)和采集服務(wù)成功失敗的回調(diào),
其中上圖的開啟采集是建立在開啟服務(wù)的基礎(chǔ)之上的。例如在開啟服務(wù)的回調(diào)中,成功的話將TrackApplication中的服務(wù)開啟標(biāo)志位置為true,并在SharedPreference中持久化,注冊(cè)廣播。停止服務(wù)的回調(diào)中,成功停掉的話把TrackApplication的兩個(gè)標(biāo)記位都置為false,并且移除SP的兩個(gè)key,解除廣播。
public void onStartTraceCallback(int errorNo, String message) { if (StatusCodes.SUCCESS == errorNo || StatusCodes.START_TRACE_NETWORK_CONNECT_FAILED <= errorNo) { trackApp.isTraceStarted = true; SharedPreferences.Editor editor = trackApp.trackConf.edit(); editor.putBoolean("is_trace_started", true); editor.apply(); setTraceBtnStyle(); registerReceiver(); } viewUtil.showToast(TracingActivity.this, String.format("onStartTraceCallback, errorNo:%d, message:%s ", errorNo, message)); }
if (StatusCodes.SUCCESS == errorNo || StatusCodes.CACHE_TRACK_NOT_UPLOAD == errorNo) { trackApp.isTraceStarted = false; http://www.cnblogs.com/henu529/p/7127774.html