最近共享单车很火,这也确实物联网发展的一大产物,科技在进步,我们也只有不断学习,不断探索,才能跟上时代进步的潮流。
共享单车一大特点肯定是需要定位啦,不管是通过GPS模块定位还是手机定位,我们都要慢慢分析,所以今天我们来使用一下百度地图SDK。
1.开始
准备工作,我们打开Android Studio新建一个项目
然后访问baidu地图 开发者中心,http://lbsyun.baidu.com/,注册开发者,登陆之后界面是这样的。
可以看到,百度地图和共享单车合作很广泛。
我们首先下载百度地图的SDK,
这里我们选中了一些常用的功能,然后开始下载
下载文件.PNG
下载后解压出现了这么多东西。
大概看一下,我们需要的东西就是在libs里,这是我们所依赖的库,assets存放了一些图片,在我电脑上暂时无法查看,先不管它,readme肯定是一个介绍,打开看看是一个版本说明。
暂时先不管,那么我在在使用这些的时候要先申请APIkey
进入控制台http://lbsyun.baidu.com/apiconsole/key,新建一个应用 新建.PNG
这里我们看几个加星号的属于必填项目,第一个是发布版SHA1
那么我想大家都知道APP发布需要一个签名,这个签名是打包这个APP的凭证,丢了这个签名可能就会出现不能打包的问题,所以这个东西一般需要保管的很好。
那么我们可以通过这个签名来获取到我们的SHA1的值,
打开cmd或者终端,定位到签名存放的目录,输入下面的命令
//其中,MyPrivateKey.jks就是我的签名
keytool -list -v -keystore MyPrivateKey.jks
然后回车输入密码,最后得到SHA1的值。
其次是开发版的SHA1我们也要填好,虽然不是必填项,可是不填的话可能会遇到不少bug,这个也很简单一样的逻辑,不过这个开发版keystore是Android Studio生成的,目录是在你的
C:\Users\苏凌\.android
下,苏凌是我的计算机名,这个.android下面有一个debug.keystore,我们使用同样的命令,输入密码(其实没有密码,直接回车就好),然后得到SHA1,填写到输入框。
然后填入包名,也就是新建工程的包名。点击提交算是创建完这个应用了。那么我们进行下一步的操作。
2.导入库
首先我们在Android Studio里切换,Project 选项卡
AS.PNG我们会发现lib这个文件夹,我们把我们下载的百度地图的lib下的jar文件放进去(注意只放jar,我下载的时候,这个jar有两个,可能版本不一样,数量不一样),这个时候,我们已经导入,可是现在,他只是在我们的文件夹里,不属于项目的一部分,我们只有右击他们俩,选择Add As Library选项,才能把他们真正的导入,导入之后我们应该能查看他们的内容。(注意,在jar文件上右击选择Add As Library,然后直接ok,等待完成就可以,一般导入一个另一个也会跟着导入,如果没有可以手动)
AS.PNG
接下来我们在src目录下的main目录下新建jniLibs目录,然后把so文件连同他的父文件夹一同导入
捕获2.PNG到此为止我们的文件都已经导入成功了,我们可以开始coding了。
3.Coding
我们参考百度给的开发文档
http://lbsyun.baidu.com/index.php?title=android-locsdk/guide/v5-0进行开发,
首先作为一个地图应用,需要的各种权限肯定是需要考虑的。
大厂……申请了这么多权限,但是不得不申请啊,缺少了某一项权限可能就出现了各种各样的问题。这里先不考虑Android6.0的权限弹窗问题
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
然后我们在<Application>标签里加上我们的key,添加这个的原因是记录访问次数,虽然百度地图是免费的,但是这个次数肯定是有用的。
<meta-data
<!--这一行不能改变-->
android:name="com.baidu.lbsapi.API_KEY"
<!--这一行填入刚申请的AK,在控制台可以找到-->
android:value="开发者 key" />
这里我们再在Application标签里增加一个服务,那么这个服务的作用是保持定位的服务,也就是我们即将在下面讲的一直定位
<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote"
></service>
好了我们现在可以开始正式的coding了。
简单坐标
首先我们获取我们的简单坐标,也就是实现了一个基础定位
布局,很简单,放了一个textview
【activity_main.xml】
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.surine.onemap.MainActivity"
tools:showIn="@layout/app_bar_main">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:id="@+id/first"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintHorizontal_bias="0.051"
app:layout_constraintVertical_bias="0.032"/>
</android.support.constraint.ConstraintLayout>
然后我们写java代码。
//这里我们只拿来一个方法一个自定义类
//这个方法在onCreate()方法中便可调用
private void initLocation() {
//findview
mTextView = (TextView) findViewById(R.id.first);
//客户端配置对象
LocationClientOption lco = new LocationClientOption();
//定位时间间隔,就是我们上面说的f服务要实现的功能
//f服务的运行才能保证一直定位
// span参数不能小于1000ms
lco.setScanSpan(4000);
//初始化定位客户端
mlc = new LocationClient(getApplicationContext());
//给定位客户端注册自定义监听器
mlc.registerLocationListener(new LocationListener());
//设置一些配置选项
//当然这个lco配置还有很多,具体在下面我会列举,
mlc.setLocOption(lco);
//启动定位客户端
mlc.start();
}
public class LocationListener implements BDLocationListener{
//接受位置信息
@Override
public void onReceiveLocation(BDLocation bdLocation) {
//通过一个StringBuilder来存放信息并展示
postion = new StringBuilder();
postion.append("经度:").append(bdLocation.getLongitude())
.append("\n纬度:").append(bdLocation.getLatitude())
.append("\n定位方式:");
if(bdLocation.getLocType() == BDLocation.TypeGpsLocation){
postion.append("GPS");
}else if(bdLocation.getLocType() == BDLocation.TypeNetWorkLocation){
postion.append("网络");
}
//在UI线程更新
runOnUiThread(new Runnable() {
@Override
public void run() {
mTextView.setText(postion);
}
});
}
//链接热点信息
@Override
public void onConnectHotSpotMessage(String s, int i) {
}
}
//停止运行,防止后台耗电
@Override
protected void onDestroy() {
super.onDestroy();
mlc.stop();
}
然后我们运行一下看看结果。(注意Android6.0以上提前授予APP相关权限)
结果
What,这个,一看就应是个错误数据吧。
没错这确实是一个错误数据,而且我们在开发中还是会很常见的。那么我们查阅资料,查看log,找找解决方案,下面是我的解决过程(我也是变研究边学习,所以遇到的问题和解决办法和大家一起分享)
首先我们在百度查相关的问题,发现不少网友也遇到了这个问题
大部分说是导入lib问题,权限问题,那么我们从这两个方面入手。
首先我们检查所需要的权限(清单文件),发现并没有Location相关的权限,可是权限都是原封不动的从百度官网复制下来的啊,去官网看看发现也没有,结果不是这个功能的,但确实是挺坑的,然后加入定位相关权限(也就是上面我提供的新版本权限),并且运行在手机上授权,发现还是这个样子。
那么我们在看看我们的AS log ,看这个log的样子应该是try catch下来的,那么我们可以在捕获的异常中发现这么一句话,就是没找到这个so文件,那么我以前也遇到过这个问题,当时是花费了挺多时间,包括请教学长,查阅资料等等,最后解决了,这次遇到就好办了,这个错误产生的主要原因是系统找不到这个文件的路径,所以我们要把这个路径告诉系统,在我们build.gradle(项目的)里添加
error.PNG
以下代码
sourceSets{
main{
jni.srcDirs=[]
jniLibs.srcDirs=['src/main/jniLibs']
}
}
然后同步一下,run。
build.PNG
得到如图所示的结果
正确结果
这说明我们的结果已经正常了。
这里我们补充一些官网上给的options
/*
可选,默认0,即仅定位一次,
设置发起定位请求的间隔需要
大于等于1000ms才是有效的
这个属性我们在上面用过的
*/
option.setScanSpan(span);
/*
可选,设置是否需要地址信息,默认不需要,这个属性的意思是如果我们传true,
那么我们可以通过location.getCity()等相关方法获取中文的地理位置,
而不是仅仅有经纬度如果不打开这个选项就去使用了相关方法就会得到null
*/
option.setIsNeedAddress(true);
/*
可选,默认false,设置是否使用gps
*/
option.setOpenGps(true);
/*
可选,默认false,设置是否当gps有效时按照1S1次频率输出GPS结果
*/
option.setLocationNotify(true);
/*
//可选,默认false,设置是否需要位置语义化结果,
可以在BDLocation.getLocationDescribe里得到,
结果类似于“在北京天安门附近”
*/
option.setIsNeedLocationDescribe(true);
/*
可选,默认false,设置是否需要POI(Point of Interest)结果,可以在
BDLocation.getPoiList里得到
*/
option.setIsNeedLocationPoiList(true);
/*
可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,
设置是否在stop的时候杀死这个进程,默认不杀死
*/
option.setIgnoreKillProcess(false);
/*
可选,默认false,设置是否收集CRASH信息,默认收集
*/
option.SetIgnoreCacheException(false);
/*
可选,默认false,设置是否需要过滤gps仿真结果,默认需要
*/
option.setEnableSimulateGps(false);
通过设置上面这些options可以达到相应的效果
下面给出一段代码,这段代码是来自一位简书用户,这也是一个相对丰富的位置监听器,大家可以根据需要选择功能
【作者:zhh_happig
链接:http://www.jianshu.com/p/29ccac3e1e42
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
感谢zhh_happig
】
//定位sdk获取位置后回调,这里添加一些判断,保证是获取到位置后的调用
if (null != location && location.getLocType() != BDLocation.TypeServerError) {
/**
* location.getTime() 是指服务端出本次结果的时间,如果位置不发生变化,则时间不变
*/
location.getTime();
/**
* 定位类型
BDLocation.TypeGpsLocation----gps定位
BDLocation.TypeNetWorkLocation----网络定位(wifi基站定位)
以及其他定位失败信息
*/
location.getLocType();
/**
* 对应的定位类型说明
* 比如"NetWork location successful"之类的信息
*/
location.getLocTypeDescription();
/**
* 纬度
*/
location.getLatitude();
/**
* 经度
*/
location.getLongitude();
/**
* 误差半径,代表你的真实位置在这个圆的覆盖范围内,
* 半径越小代表定位精度越高,位置越真实
* 在同一个地点,可能每次返回的经纬度都有微小的变化,
* 是因为返回的位置点并不是你真实的位置,有误差造成的。
*/
location.getRadius();
location.getCountryCode();//国家码,null代表没有信息
location.getCountry();//国家名称
location.getCityCode();//城市编码
location.getCity();//城市
location.getDistrict();//区
location.getStreet();//街道
location.getAddrStr();//地址信息
location.getLocationDescribe();//位置描述信息(xxxx附近)
/**
* 判断用户是在室内,还是在室外
* 1:室内,0:室外,这个判断不一定是100%准确的
*/
location.getUserIndoorState();
/**
* 获取方向
*/
location.getDirection();
//获取poi信息,但是要开启poi选项
if (location.getPoiList() != null && !location.getPoiList().isEmpty()) {
for (int i = 0; i < location.getPoiList().size(); i++) {
Poi poi = (Poi) location.getPoiList().get(i);
poi.getName();//获取位置附近的一些商场、饭店、银行等信息
}
}
if (location.getLocType() == BDLocation.TypeGpsLocation) {// GPS类型定位结果
location.getSpeed();//速度 单位:km/h,注意:网络定位结果是没有速度的
location.getSatelliteNumber();//卫星数目,gps定位成功最少需要4颗卫星
location.getAltitude();//海拔高度 单位:米
location.getGpsAccuracyStatus();//gps质量判断
} else if (location.getLocType() == BDLocation.TypeNetWorkLocation) {//网络类型定位结果
if (location.hasAltitude()) {//如果有海拔高度
location.getAltitude();//单位:米
}
location.getOperators();//运营商信息
} else if (location.getLocType() == BDLocation.TypeOffLineLocation) {// 离线定位结果
//离线定位成功,离线定位结果也是有效的;
} else if (location.getLocType() == BDLocation.TypeServerError) {
//服务端网络定位失败,可以反馈IMEI号和大体定位时间到loc-bugs@baidu.com;
} else if (location.getLocType() == BDLocation.TypeNetWorkException) {
//网络不同导致定位失败,请检查网络是否通畅;
} else if (location.getLocType() == BDLocation.TypeCriteriaException) {
//无法获取有效定位依据导致定位失败,一般是由于手机的原因,处于飞行模式下一般会造成这种结果,可以试着重启手机;
}
}
}
常见错误
1.errorcode 200(App不存在)
这个是鉴权的时候可能会产生的错误,说白了就是key写错了,你发现这个问题,检查了报名SHA1各种东西,但是就是不行,你变得很苦恼,这时候检查一下你的manifest.xml 里的key是不是多写了一个空格……(别说智障,真的好多次都是因为这个原因)
总结
本篇文章主要介绍简单使用了百度地图的定位功能,实现了一个简单的定位小程序,当然这个连这个小程序都还不完整,包括权限问题,这些我都打算单独一篇文章讲,我们先把地图的故事说完。
参考
百度地图开发文档
第一行代码第二版
简书:zhh_happig
网友评论