由於某些原因Google的網絡服務在中國不可訪問,從而導致網絡定位方式的API失效,而GPS定位雖然不用網絡,但是必須在室外才能進行有效的定位。基於以上原因可以使用第三方公司的SDK,國內在這領域做得比較好的是百度、高德
一、申請API Key
要想使用百度的LBS功能,首先必須申請一個API Key。需要百度賬號才能申請,沒有的話可以去註冊一個。登錄你的百度賬號,打開http://developer.baidu.com/user/reg鏈接,在裏面填寫一些註冊信息即可(只需填寫帶 * 的部分內容就足夠了),然後點擊提交,進行郵箱驗證,點擊郵件發來的鏈接就可完成註冊。
到此一切順利!這樣說明成爲了一名百度開發者。接着訪問http://lbsyun.baidu.com/apiconsole/key。目前新註冊的用戶列表是空的,點擊創建應用就可以去申請APIKey了。應用名稱可以隨便填(最好和Android項目名稱相同),應用類型選擇Android SDK ,啓用服務默認的就可以。
那麼發佈版和開發版SHA1是什麼東西呢? 打開你的Android Stuidio 項目,點擊Android stuidio右側工具欄的Gradle →項目名稱→:app→Tasks→android,這裏展示了項目中所有內置的Gradle Tasks,其中signingReport這個Task可以用來查看簽名文件信息。雙擊文件,結果如圖所示.查看下方的SHA1即可。注意:我們使用的是debug.keystore文件生成的指紋。這是Android自動生成的一個用於測試的簽名文件。而當應用程序發佈時還需要創建一個正式的簽名文件,如果需要得到它:可以在cmd中輸入keytool -list -v -keystore <簽名文件路徑> 然後輸入密碼...
我們得到了SHA1指紋就是開發版的SHA1,但是我們暫時還沒有發佈版的,兩個值都填一樣就可以了。最後還有一個包名,寫我們的應用程序的包名,比如com.example.hu.tourismsystem 。然後點擊提交就創建成功了。然後有了 訪問應用(AK)就可以完成後續LBS 開發工作了。
二、使用百度定位,引入包
沒有Android項目的可以現在創建,不過項目包名要和API key的包名一致。準備LBS SDK : 下載地址是http://lbsyun.baidu.com/sdk/download,我們這次會用到基礎地圖和基礎定位這兩個SDK,將他們勾上,然後點擊“開發包”下載。下載完後解壓,文件內容如圖
將BaiduLBS_Android.jar 複製到 項目app模塊下的libs 。右鍵src/main目錄創建 Directory 取名爲jniLibs的目錄,把壓縮包裏的所有文件夾複製到這裏,並且複製到app/libs下各一份。系統會在app/build.gradle默認有如下聲明:
dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') ...}並且在buildTypes塊下添加如下代碼
sourceSets { main() { jniLibs.srcDirs = ['libs'] } }
找到AndroidStuidio頂部工具欄Sync按鈕(sync Project with Gradle files 一般在從右數第四個),點擊他。然後薄酒引用成功了,如圖。這樣我們就把LBS的SDK準備好了。
注意:ksoap2-android... 這個與本項目無關
三、確定自己的經緯度:
首先在Manifest添加權限
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <uses-permission android:name="android.permission.WAKE_LOCK"/>在application標籤下添加:
<meta-data android:name="com.baidu.lbsapi.API_KEY" android:value="KLqE1SiyhO90Osu7ruCO67cbJdidDrgn"/>
<service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote" >其中values 爲申請到的Api Key,根據自己情況修改。
佈局文件很簡單:一個id爲positon_textview的TextView。
主程序:
public class ActivityMicroTourism extends AppCompatActivity {
public LocationClient mlocationClient;
private TextView positionText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_micro_tourism);
mlocationClient = new LocationClient(getApplicationContext());
mlocationClient.registerLocationListener(new MyLocationListener());
positionText = (TextView) findViewById(R.id.position_text_view);
List<String> permissionList = new ArrayList<>();
if (ContextCompat.checkSelfPermission(ActivityMicroTourism.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if (ContextCompat.checkSelfPermission(ActivityMicroTourism.this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.READ_PHONE_STATE);
}
if(ContextCompat.checkSelfPermission(ActivityMicroTourism.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if (!permissionList.isEmpty()){
String [] permissions =permissionList.toArray(new String[permissionList.size()]);
ActivityCompat.requestPermissions(ActivityMicroTourism.this,permissions,1);
}
else{requestLocation();}
}
private void requestLocation(){
mlocationClient.start();
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode){
case 1:
if(grantResults.length>0){
for(int result :grantResults){
if(result!=PackageManager.PERMISSION_GRANTED){
Toast.makeText(this,"必須同意所有權限才能使用本程序",Toast.LENGTH_SHORT).show();
finish();
return;
}
}
requestLocation();
}else {
Toast.makeText(this,"發生未知錯誤",Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
}
}
public class MyLocationListener implements BDLocationListener{
@Override
public void onReceiveLocation(BDLocation bdLocation) {
StringBuilder currentPositon =new StringBuilder();
currentPositon.append("緯度: ").append(bdLocation.getLatitude()).append(" ");
currentPositon.append("經線: ").append(bdLocation.getLongitude()).append(" ");
/*currentPositon.append("國家: ").append(bdLocation.getCountry()).append(" ");
currentPositon.append("省: ").append(bdLocation.getProvince()).append(" ");
currentPositon.append("市: ").append(bdLocation.getCity()).append(" ");
currentPositon.append("區: ").append(bdLocation.getDistrict()).append(" ");
currentPositon.append("街道: ").append(bdLocation.getStreet()).append(" ");*/
currentPositon.append("定位方式: ");
if(bdLocation.getLocType()==BDLocation.TypeGpsLocation){
currentPositon.append("GPS");
}else if(bdLocation.getLocType()==BDLocation.TypeNetWorkLocation){
currentPositon.append("Wifi");
}
positionText.setText(currentPositon);
}
}
在手機上運行該程序查看效果,同意所有權限,如果出現數據則表示成功。(如果只出現了經線和緯線,並且值非常離譜,也許只是你的網絡太差)可以自己在搞個刷新按鈕添加單擊事件。有三個權限是需要在運行時用戶同意的,爲啥要添加那麼多權限?因爲不給添不給用。本段代碼總的來說就是權限添加和權限驗證和獲取位置信息。
如果在用戶在快速移動中,怎樣實時更新位置?添加或修改如下代碼:
private void initLocation(){ LocationClientOption option =new LocationClientOption(); option.setScanSpan(5000); option.setIsNeedAddress(true); mlocationClient.setLocOption(option); }
private void requestLocation(){ initLocation(); mlocationClient.start(); }
@Override protected void onDestroy() { super.onDestroy(); mlocationClient.stop(); }每隔5秒鐘會更新一下當前位置。更新太快容易消耗手機電量讓手機發熱.setIsNeedAddress 能讓獲取豐富的位置信息,現在可以把onReceiveLocation裏的註釋取消了。
4、使用百度地圖
佈局文件:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_2"
android:orientation="vertical" >
<com.baidu.mapapi.map.MapView
android:id="@+id/bmapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"></com.baidu.mapapi.map.MapView>
<TextView
android:id="@+id/position_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:text="!"
/>
</LinearLayout>
主程序:修改
public class ActivityMicroTourism extends AppCompatActivity {
...
private MapView mapView; // --
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SDKInitializer.initialize(getApplication());//--
setContentView(R.layout.activity_micro_tourism);
mapView=(MapView)findViewById(R.id.bmapView);//--
mlocationClient = new LocationClient(getApplicationContext());
mlocationClient.registerLocationListener(new MyLocationListener());
...
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onDestroy() {
super.onDestroy();
mlocationClient.stop();
mapView.onDestroy(); //--
}
}
用手機運行程序,看看百度地圖是否能成功顯示出來,模擬器是不支持百度地圖SDK的。這裏注意一點SDKInitializer.initialize()要放在加載頁面之前。
如果能成功在手機上顯示地圖,那麼接下來的任務就是將地圖移動到我的位置,並且能讓我的位置顯示在地圖上.
public class ActivityMicroTourism extends AppCompatActivity {
...
private BaiduMap baiduMap; //--
private boolean isFristLocate=true; //--
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SDKInitializer.initialize(getApplication());
setContentView(R.layout.activity_micro_tourism);
mapView=(MapView)findViewById(R.id.bmapView);
baiduMap=mapView.getMap(); //--
baiduMap.setMyLocationEnabled(true);//--
mlocationClient = new LocationClient(getApplicationContext());
mlocationClient.registerLocationListener(new MyLocationListener());
...
}
private void navigateTo(BDLocation location){
if(isFristLocate ){
LatLng ll=new LatLng(location.getLatitude(),location.getLongitude());
MapStatusUpdate update= MapStatusUpdateFactory.newLatLng(ll);
baiduMap.animateMapStatus(update);
update=MapStatusUpdateFactory.zoomTo(16f);
baiduMap.animateMapStatus(update);
isFristLocate=false;
}
MyLocationData.Builder locationBuilder=new MyLocationData.Builder();
locationBuilder.latitude(location.getLatitude());
locationBuilder.longitude(location.getLongitude());
MyLocationData locationData=locationBuilder.build();
baiduMap.setMyLocationData(locationData);
}
@Override
protected void onDestroy() {
super.onDestroy();
mlocationClient.stop();
mapView.onDestroy();
baiduMap.setMyLocationEnabled(false); //--
}
public class MyLocationListener implements BDLocationListener{
@Override //--
public void onReceiveLocation(BDLocation bdLocation) {
if (bdLocation.getLocType()==BDLocation.TypeGpsLocation || bdLocation.getLocType()==BDLocation.TypeNetWorkLocation){
navigateTo(bdLocation);
}
...
}
@Override
public void onConnectHotSpotMessage(String s, int i) {}
}
}
其中,navaigateTo()是用來用來更新位置的,第一次打開程序的時候會更新位置
手機運行程序,查看效果。需要注意的幾點:
1、在佈局文件百度地圖控件會報錯,可以無視,模擬器上運行不了可以在手機上運行
2、由於可能某些人的手機比較舊,剛開始打開程序更新位置會失敗,可以嘗試添加一個刷新按鈕,執行navaigateTo()函數
3、更新位置是一個耗時比較大的操作,放在主線程中容易造成線程阻塞,最好在子線程中運行
4、百度地圖定位座標會發生點偏移,座標校正可以參考http://blog.sina.com.cn/s/blog_80a9926b0101ktoa.html
5、更多的開發指南可以參考 http://lbsyun.baidu.com