申请API Key
- 打开这个连接 http://lbsyun.baidu.com/apiconsole/key,申请百度地图开发者平台服务,点击我同意,创建应用
-
这个发布版SHA1和开发板SHA1是什么意思呢?这个是打包程序时所用签名文件的SHA1指纹,通过ANdroid Studio可以查看到,打开任何一个项目点击右边工具栏的Gradle-->项目名-->:app-->Tasks-->android
-
双击这个signingReport文件
- 其中的F2:F8:68:53:5F:1C:D9:1E:68:6A:14:4B:24:91:DD:37:95:58:A1:9B就是需要的SHA1指纹了,要注意的是现在使用的是
debug.keystore
文件生成的指纹,这是Android自动生成用于测试的签名文件,当应用程序发布时还要创建一个正式的签名文件, - 在定义的项目中(com.example.lbstest)
记住这个密码,这就创建成功了
要得到它的指纹,就在cmd中输入以下命令
keytool -list -v -keystore <签名文件路径>
- 其中的F2:F8:68:53:5F:1C:D9:1E:68:6A:14:4B:24:91:DD:37:95:58:A1:9B就是需要的SHA1指纹了,要注意的是现在使用的是
-
现在得到的SHA1指纹实际上是一个开发版的SHA1指纹,不过现在没有发布版的SHA1,这两个值填写一样就可以了,最后还有一个包名,就是上一步中的包名
-
提交后,应用就创建成功了
- 其中的AK就是申请到的API Key,有了它就可以进行后续的LBS开发工作了
使用百度定位
项目就是lsbtest,包名是com.example.lbstest,就是上面定义的那个
- 准备LBS SDK
http://lbsyun.baidu.com/index.php?title=sdk/download&action#selected=location_all
-
将百度LBS开发平台上的SDK下载下来,点击开发包
-
-
下载后解压,其中有一个libs目录,这里面的内容就是我们需要的
- BaiduLBS_Android.jar这个文件是java层要使用的,其他子目录下的so文件是Native层要用的,
- so文件是C/C++语言写的,因为百度都封装好了,直接使用就可以了
- 首先看一下当前项目目录,
-
其中app模块下的libs目录就是用来存放Jar包的,把BaiduLBS_Android.jar复制到这里
-
接下来右击src/main目录,进行目录jniLibs目录,把压缩包里的所有目录直接复制到这里
-
- 这个时候在配置文件中build.gradle中,会默认有这一行代码
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
...
}
- 这将表示将所有以jar结尾的文件添加到当前的项目中,但是这个时候还没有引用成功,重启这个Android Studio
-
这个时候libs目录下的jar包就会多出一个向右的箭头,这就表示引用成功了
确定自己的位置的经纬度
- 修改activity_main.xml中的代码
- 这里只有一个TextView控件,用于显示当前位置的经纬度
- 修改AndroidManifest.xml文件中的代码
- 首先添加了好多权限,这在百度的开发文档中可以看到
- meta-data标签中value就是前面申请的API Key值
- 还有一个service标签,这个是百度带的
- 修改MainActivity中的代码
package com.example.lbstest;
public class MainActivity extends AppCompatActivity {
// 声明这个对象,该对象初始化需传入Context类型参数。推荐使用getApplicationConext()方法获取全进程有效的Context。
public LocationClient mLocationClient;
private MyLocationListener myListener = new MyLocationListener();
private TextView positionText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 进行初始化
mLocationClient = new LocationClient(getApplicationContext());
// 注册监听函数
mLocationClient.registerLocationListener(myListener);
setContentView(R.layout.activity_main);
// 获取到控件
positionText = (TextView)findViewById(R.id.position_text_view);
// 关于权限的操作
List permissionList = new ArrayList<>();
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION)!= PackageManager.PERMISSION_GRANTED){
permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_PHONE_STATE)!= PackageManager.PERMISSION_GRANTED){
permissionList.add(Manifest.permission.READ_PHONE_STATE);
}
if (ContextCompat.checkSelfPermission(MainActivity.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(MainActivity.this,permissions,1);
}else {
requestLocation();
}
}
//调用LocationClient的start()方法,便可发起定位请求
public void requestLocation(){
mLocationClient.start();
}
// 动态添加权限
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull 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{
//此处的BDLocation为定位结果信息类,通过它的各种get方法可获取定位相关的全部结果
@Override
public void onReceiveLocation(BDLocation bdLocation) {
StringBuilder currentPosition = new StringBuilder();
currentPosition.append("纬度:").append(bdLocation.getLatitude()).append("\n");
currentPosition.append("经度:").append(bdLocation.getLongitude()).append("\n");
currentPosition.append("定位方式:");
if (bdLocation.getLocType() == BDLocation.TypeGpsLocation){
currentPosition.append("GPS");
}else if (bdLocation.getLocType() == BDLocation.TypeNetWorkLocation){
currentPosition.append("网络");
}
// 获取完信息添加到控件中
positionText.setText(currentPosition);
}
}
}
- 在onCreate()方法中,首先创建了一个LocationClient的实例,在构建函数中接收一个Context参数,这里调用了getApplicationContext()方法获取全局的Context参数传入,然后调用LocationClient的registerLocationListener()方法来注册一个监听器,当获取位置的时候,就会回调这个定位监听器
- 关于运行时权限,这里使用了集合,只有当所有权限都被用户同意了,才会调用 requestLocation()方法开始地理位置定位
- 在 requestLocation()方法中,就只是的调用了LocationClient的start()方法就能开始定位了
- 在这个监听器中,获取到了详细的位置信息,然后设置到textView控件中
-
运行程序,运行权限就可以看到
- 不过,在默认的情况下,LocationClient的start()方法只会定位一次,但是如果我们此时移·动的话,怎么样才能更新位置呢?这个时候就得修改MainActivity中的代码了
...
//调用LocationClient的start()方法,便可发起定位请求
public void requestLocation(){
initLocation();
mLocationClient.start();
}
// 创建一个LocationClientOption对象,调用方法来设置跟新的间隔
private void initLocation(){
LocationClientOption option = new LocationClientOption();
option.setScanSpan(5000);
mLocationClient.setLocOption(option);
}
// 活动被销毁的时候要调用stop()方法来停止定位
@Override
protected void onDestroy() {
super.onDestroy();
mLocationClient.stop();
}
...
- 别的代码保持不变,增加了一个initLocation()方法,在这个方法中创建一个LocationClientOption对象,用这个对象的setScanSpan()方法来设置更新的间隔,这里这是5000,表示每个5秒就会更新当前的位置
- 注意:在这个活动销毁的时候,调用LocationClient的stop()方法来停止定位,不然程序会在后台不停的进行定位,从而消耗手机的电量
选择定位模式
上面是使用网络定位的方式,这次使用精准度高的GPS定位
-
首先GPS定位功能要由用户主动的启动才行,进入设置-->位置信息
- 开启GPS定位功能后,可以在initLocation()方法中对百度LBS SDK的定位模式指定,Hinght_Accuracy、Battery_Saving和Device_Sensors,
其中Hinght_Accuracy模式标识高精确度,在GPS信号正常的情况下优先使用,在无法使用GPS信号的时候就使用网络定位,
Battery_Saving表示节点模式,只会使用网络进行定位,Device_Sensors表示传感模式,只会使用GPS定位,其中的Hinght_Accuracy是默认的定位,不需要修改任何代码,把手机拿到室外就可以了,这个时候手机就会自动切换到GPS定位模式了 - 当然了也可以强制指定为GPS定位,修改MainActivity中的代码
private void initLocation(){
LocationClientOption option = new LocationClientOption();
option.setScanSpan(5000);
// 强制使用GPS定位的模式
option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);
mLocationClient.setLocOption(option);
}
- 这里调用了setLocationMode()方法将定位模式指定为传感器模式,就只能使用GPS来进行定位了,重新运行程序,到室外去,运行程序
看得懂的位置信息
当然了,获取经度和纬度对于小白来说也是看不懂的,这个时候就得获取直观的位置信息,
- 当然了,这些百度LBS SDK都支持,只需要进行一些简单的接口调用就可以了,修改MainActiviyt中的代码
package com.example.lbstest;
public class MainActivity extends AppCompatActivity {
...
private void initLocation(){
LocationClientOption option = new LocationClientOption();
option.setScanSpan(5000);
// 开启详细信息
option.setIsNeedAddress(true);
mLocationClient.setLocOption(option);
}
// 监听函数
public class MyLocationListener implements BDLocationListener{
//此处的BDLocation为定位结果信息类,通过它的各种get方法可获取定位相关的全部结果
@Override
public void onReceiveLocation(BDLocation bdLocation) {
StringBuilder currentPosition = new StringBuilder();
currentPosition.append("纬度:").append(bdLocation.getLatitude()).append("\n");
currentPosition.append("经度:").append(bdLocation.getLongitude()).append("\n");
currentPosition.append("国家:").append(bdLocation.getCountry()).append("\n");
currentPosition.append("省:").append(bdLocation.getProvince()).append("\n");
currentPosition.append("市:").append(bdLocation.getCity()).append("\n");
currentPosition.append("区:").append(bdLocation.getDistrict()).append("\n");
currentPosition.append("街道:").append(bdLocation.getStreet()).append("\n");
currentPosition.append("定位方式:");
if (bdLocation.getLocType() == BDLocation.TypeGpsLocation){
currentPosition.append("GPS");
}else if (bdLocation.getLocType() == BDLocation.TypeNetWorkLocation){
currentPosition.append("网络");
}
// 获取完信息添加到控件中
positionText.setText(currentPosition);
}
}
}
- 首先在initLocation()方法中调用了LocationClientOption的setIsNeedAddress(),设置了true,这就表示要获取当前位置的详细信息
-
在onReceiveLocation()方法中,通过get方法获取详细的位置,要注意的是:获取地址信息一定要需要用网络,即使设置了Device_Sensors这个模式,也会自动开启网络定位功能
- 这样就获取了当前位置的详细信息了
让地图显示出来
- 直接在上一个的基础上进行修改,在activity_main.xml中
- 首先在TextView控件中设置
visibility="gone"
,就是让它在界面上隐藏 - 放置了一个新的MapView控件,这个是百度自定义的,直接使用就可以了,设置为充满屏幕
- 接下来修改MainActivity中的代码
package com.example.lbstest;
public class MainActivity extends AppCompatActivity {
// 声明这个对象,该对象初始化需传入Context类型参数。推荐使用getApplicationConext()方法获取全进程有效的Context。
public LocationClient mLocationClient;
private MyLocationListener myListener = new MyLocationListener();
private TextView positionText;
//
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 进行初始化
mLocationClient = new LocationClient(getApplicationContext());
// 注册监听函数
mLocationClient.registerLocationListener(myListener);
// 调用这个方法来进行初始化
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_main);
// 获取到这个控件
mapView = (MapView)findViewById(R.id.bmapView);
...
}
...
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onResume();
}
@Override
protected void onDestroy() {
super.onDestroy();
mLocationClient.stop();
mapView.onDestroy();
}
...
}
- 首先调用 SDKInitializer.initialize()方法,里面传入getApplicationContext()获取全局的Context参数,来进行初始化,注意:初始化操作要在setContentView()方法之前调用
- 获取到这个控件的实例,以后会用到
- 重写这个onResume()、onPause()、onDestroy()方法,对MapView进行管理,以保证资源能够及时得到释放
- 运行程序就可以看到,百度地图就显示出来了
- 但是这个时候报错了,只有网格没有地图
百度查了一大堆,都是什么SHA1 错误,需要根据LogCat打印的去做更换,一脸懵逼了,不知道到哪去改这个东西,最后到百度的API控制中心
-
点击设置,在这里把SHA1换成打印日志里面的,结果就好了
这个坑算是填上了
移动到我的位置
显示是显示出来的,但是出来的是默认的北京市的,怎么才能定位到自己的呢?
- 百度LBS SDK的API中提供了一个BaiduMap类,它是地图的总控制器,调用MapView的getMap()方法就可以获取到BaiduMap的实例
BaiduMap baiduMap = mapView.getMap()
- 获取到这个以后,就可以对地图进行各种操作了,比如设置地图的缩放级别以及将地图以哦对那个到某个经纬度上
- 地图的缩放级别在3到19之间,越大就越精细,也可以是小数点,比如设置为12.5就可以写成
MapStatusUpdate update = MapStatusUpdateFactory.zoomTo(12.5f);
baiduMap.animateMapStatus(update);
- 其中 MapStatusUpdateFactory.zoomTo()方法就收的是一个float参数,设置级别,zoomTo()方法返回的是MapStatusUpdate对象,把这个传入到 BaiduMap.animateMapStatus()方法中就可以设置缩放级别了
- 怎么将地图移动到某一个经纬度上呢,这个时候就要借助LatLng类,这个类就是用于存放经纬度的,它的构造方法接收两个参数,第一个是纬度值,第二个是经度值,之后调用MapStatusUpdateFactory的newLatLng()方法将这个LatLng对象传入,这个newLatLng()方法也是返回一个MapStatusUpdate对象,把这个对象传入到BaiduMap的animateMapStatus()方法中,就可以将地图移动到指定的经纬度上了
LatLng ll = new LatLng(111,222);
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
baiduMa.animateMapStatus(update);
- 继续在这个项目上修改,
package com.example.lbstest;
public class MainActivity extends AppCompatActivity {
...
private BaiduMap baiduMap;
private boolean isFirstLocate = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 进行初始化
mLocationClient = new LocationClient(getApplicationContext());
// 注册监听函数
mLocationClient.registerLocationListener(myListener);
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_main);
mapView = (MapView)findViewById(R.id.bmapView);
// 获取到实例
baiduMap = mapView.getMap();
private void navigateTo(BDLocation location){
if (isFirstLocate){
// 设置位置
LatLng ll = new LatLng(location.getLatitude(),location.getLongitude());
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
baiduMap.animateMapStatus(update);
// 设置缩放级别
update = MapStatusUpdateFactory.zoomTo(10f);
baiduMap.animateMapStatus(update);
isFirstLocate = false;
}
}
// 监听函数
public class MyLocationListener implements BDLocationListener{
@Override
public void onReceiveLocation(BDLocation bdLocation) {
if (bdLocation.getLocType() == BDLocation.TypeNetWorkLocation ||bdLocation.getLocType() == BDLocation.TypeGpsLocation ){
navigateTo(bdLocation);
}
}
}
}
}
- 主要添加了navigateTo()方法,这个方法就是用来设置位置和缩放,和上面一摸一样,这里的参数就是我当前的位置
-
在onReceiveLocation()方法中,当设备定位到当前位置的时候,就直接调用navigateTo()方法就可以了,直接将BDLocation对象传入就可以了
让我显示在地图上
如果当前的设备正在移动,那么显示我的这个光标就会跟着一起移动
- 百度的LBS SDK当中提供了一个MyLocationData.Builder类,这个类就是用来封装设备当前所在的位置,只要将当前位置的经纬度传入进来就可以了
MyLocationData.Builder locationBuilder = new MyLocationData.Builder();
locationBuilder.latitude(50);
locationBuilder.longitude(100);
- MyLocationData.Builder类还提供了一个build()方法,当把封装的信息都设置完成后,只需要调用build()方法就可以生成一个MyLocationData的实例,然后把这个实例传入到BaiduMap的setMyLocationData()方法中,就可以了
MyLocationData locationData = locationBuilder.build();
baiduMap.setMyLocationData(locationData);
- 具体实现
package com.example.lbstest;
public class MainActivity extends AppCompatActivity {
...
private BaiduMap baiduMap;
private boolean isFirstLocate = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 进行初始化
mLocationClient = new LocationClient(getApplicationContext());
// 注册监听函数
mLocationClient.registerLocationListener(myListener);
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_main);
mapView = (MapView)findViewById(R.id.bmapView);
// 获取到实例
baiduMap = mapView.getMap();
// 开启这个功能
baiduMap.setMyLocationEnabled(true);
...
private void navigateTo(BDLocation location){
if (isFirstLocate){
// 设置位置
LatLng ll = new LatLng(location.getLatitude(),location.getLongitude());
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
baiduMap.animateMapStatus(update);
// 设置缩放级别
update = MapStatusUpdateFactory.zoomTo(10f);
baiduMap.animateMapStatus(update);
isFirstLocate = 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);
}
}
}
- 在navigateTo()方法中,新增了 MyLocationData的逻辑,和上面讲的一样,但是要把这个逻辑放到if语句外面,因为这个是随着我们的移动而移动
- 要注意: baiduMap.setMyLocationEnabled(true),将此功能开启
当然了,这只是简单的操作,具体的可以到官网查看