进入高德开发者平台
参考:http://lbs.amap.com/api/Android-location-sdk/locationsummary/
配置
下载
从网站下载并解压得到定位包“AMap_Location_V2.x.x.jar“。
Eclipse配置工程
开发工程中新建“libs”文件夹,将定位包拷贝到 libs 的根目录下。拷贝完成后的工程目录(以 V1.0.4 为例)如图所示:
注意:若您在 Eclipse 上使用 adt22 以下的版本插件,则需要在 Eclipse 上进行如下配置:
选中 Eclipse 的工程,右键选择 “Properties > Java Build Path > Order and Export”,勾选 “Android Private Libraries”。
Android Studio配置工程
1.打开Android Studio编译器,切换到project查看方式,如图所示:
2.将下载的定位SDK的jar包复制到libs目录下,如果有老版本定位jar包在其中,请删除。如图所示:
定位
进行定位之前,需要在 AndroidManifest.xml 文件中进行权限设置,确保定位功能可以正常使用。
配置AndroidManifest.xml
首先,请在application标签中声明service组件,每个app拥有自己单独的定位service。
1
|
<service android:name=
"com.amap.api.location.APSService"
></service>
|
接下来声明使用权限
Android 6.0及以上系统可以参考Android 6.0权限说明章节。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<!--用于进行网络定位-->
<uses-permission android:name=
"android.permission.ACCESS_COARSE_LOCATION"
></uses-permission>
<!--用于访问GPS定位-->
<uses-permission android:name=
"android.permission.ACCESS_FINE_LOCATION"
></uses-permission>
<!--获取运营商信息,用于支持提供运营商信息相关的接口-->
<uses-permission android:name=
"android.permission.ACCESS_NETWORK_STATE"
></uses-permission>
<!--用于访问wifi网络信息,wifi信息会用于进行网络定位-->
<uses-permission android:name=
"android.permission.ACCESS_WIFI_STATE"
></uses-permission>
<!--这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
<uses-permission android:name=
"android.permission.CHANGE_WIFI_STATE"
></uses-permission>
<!--用于访问网络,网络定位需要上网-->
<uses-permission android:name=
"android.permission.INTERNET"
></uses-permission>
<!--用于读取手机当前的状态-->
<uses-permission android:name=
"android.permission.READ_PHONE_STATE"
></uses-permission>
<!--写入扩展存储,向扩展卡写入数据,用于写入缓存定位数据-->
<uses-permission android:name=
"android.permission.WRITE_EXTERNAL_STORAGE"
></uses-permission>
|
最后设置Key,在application标签中加入
1
2
3
|
<meta-data android:name=
"com.amap.api.v2.apikey"
android:value=
"key"
>
//开发者申请的key
</meta-data>
|
定位模式介绍
高德定位服务包含GPS和网络定位(Wi-Fi和基站定位)两种能力。定位SDK将GPS、网络定位能力进行了封装,以三种定位模式对外开放
高精度定位模式:会同时使用网络定位和GPS定位,优先返回最高精度的定位结果;
低功耗定位模式:不会使用GPS,只会使用网络定位(Wi-Fi和基站定位);
仅用设备定位模式:不需要连接网络,只使用GPS进行定位,这种模式下不支持室内环境的定位。
初始化定位客户端
注:请在主线程中声明AMapLocationClient类对象,需要传Context类型的参数。推荐用getApplicationConext()方法获取全进程有效的context。
1
2
3
4
5
6
7
8
|
//声明AMapLocationClient类对象
public
AMapLocationClient mLocationClient =
null
;
//声明定位回调监听器
public
AMapLocationListener mLocationListener =
new
AMapLocationListener();
//初始化定位
mLocationClient =
new
AMapLocationClient(getApplicationContext());
//设置定位回调监听
mLocationClient.setLocationListener(mLocationListener);
|
配置定位参数
设置定位参数包括:定位模式(高精度定位模式,低功耗定位模式和仅设备定位模式),是否返回地址信息等。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
//声明mLocationOption对象
public
AMapLocationClientOption mLocationOption =
null
;
//初始化定位参数
mLocationOption =
new
AMapLocationClientOption();
//设置定位模式为高精度模式,Battery_Saving为低功耗模式,Device_Sensors是仅设备模式
mLocationOption.setLocationMode(AMapLocationMode.Hight_Accuracy);
//设置是否返回地址信息(默认返回地址信息)
mLocationOption.setNeedAddress(
true
);
//设置是否只定位一次,默认为false
mLocationOption.setOnceLocation(
false
);
if
(mLocationOption.isOnceLocationLatest()){
mLocationOption.setOnceLocationLatest(
true
);
//设置setOnceLocationLatest(boolean b)接口为true,启动定位时SDK会返回最近3s内精度最高的一次定位结果。
//如果设置其为true,setOnceLocation(boolean b)接口也会被设置为true,反之不会。
}
//设置是否强制刷新WIFI,默认为强制刷新
mLocationOption.setWifiActiveScan(
true
);
//设置是否允许模拟位置,默认为false,不允许模拟位置
mLocationOption.setMockEnable(
false
);
//设置定位间隔,单位毫秒,默认为2000ms
mLocationOption.setInterval(
2000
);
//给定位客户端对象设置定位参数
mLocationClient.setLocationOption(mLocationOption);
//启动定位
mLocationClient.startLocation();
|
AMapLocationClientOption核心方法解析
下表是设置定位参数的核心方法,是上一章节代码段中方法的详细展开,可在参考手册AMapLocationClientOption类中查阅其他未展示方法。
方法名 | 参数说明 | 返回值说明 | 方法效果 | 默认值 |
setLocationMode(AMapLocationMode locationMode) | locationMode是定位类型AMapLocationMode的对象,提供三个枚举常量分别代表三种定位模式。 Hight_Accuracy:高精度定位模式; Device_Sensors:仅设备定位模式; Battery_Saving:低功耗定位模式; | 返回AMapLocationClientOption类对象 | 用于设置SDK定位模式 | Hight_Accuracy,默认高精度模式 |
setLocationCacheEnable(boolean isLocationCacheEnable) | isLocationCacheEnable是布尔型参数,true表示使用定位缓存策略;false表示不使用。 | void | 启用缓存策略,SDK将在设备位置未改变时返回之前相同位置的缓存结果。 | true,默认启用缓存策略 |
setInterval(long interval) | interval是长整型参数,用于设定连续定位间隔,毫秒级参数。 | 返回AMapLocationClientOption类对象 | 例如向方法传1000,连续定位启动后会以1s为间隔时间返回定位结果。 | 2000 |
setOnceLocation(boolean isOnceLocation) | isOnceLocation是布尔型参数,true表示启动单次定位,false表示使用默认的连续定位策略。 | 返回AMapLocationClientOption类对象 | 传入true,启动定位,AmapLocationClient将会返回一次定位结果。 | false |
setOnceLocationLatest(boolean isOnceLocationLatest) | isOnceLocationLatest是布尔型参数,true表示获取最近3s内精度最高的一次定位结果;false表示使用默认的连续定位策略。 | 返回AMapLocationClientOption类对象 | 出入true,启动定位, AmapLocationClient将会最近3s内精度最高的一次定位结果。 | false |
setNeedAddress(boolean isNeedAddress) | isNeedAddress是布尔型参数,true表示定位返回经纬度同时返回地址描述(定位类型是网络定位的会返回);false表示不返回地址描述。 | 返回AMapLocationClientOption类对象 | 传入true,启动定位,AmapLocationClient返回经纬度的同时会返回地址描述。注意:模式为仅设备模式(Device_Sensors)时无效。 | true |
setMockEnable(boolean isMockEnable) | isMockEnable是布尔型参数,true表示允许外界在定位SDK通过GPS定位时模拟位置,false表示不允许模拟GPS位置。 | void | 传入true,启动定位,可以通过外界第三方软件对GPS位置进行模拟。注意:模式为低功耗模式(Battery_Saving)时无效。 | false |
setWifiActiveScan(boolean isWifiActiveScan) | isWifiActiveScan是布尔型参数,true表示会主动刷新设备wifi模块,获取到最新鲜的wifi列表(wifi新鲜程度决定定位精度);false表示不主动刷新。 | void | 传入true,启动定位,AmapLocationClient会驱动设备扫描周边wifi,获取最新的wifi列表(相比设备被动刷新会多消耗一些电量),从而获取更精准的定位结果。注意:模式为仅设备模式(Device_Sensors)时无效 | false |
setHttpTimeOut(long httpTimeOut) | httpTimeOut是长整型参数,用于设定通过网络定位获取结果的超时时间,毫秒级。 | void | 传入20000,代表网络定位超时时间为20秒。 | 30000 |
获取定位结果
AMapLocationListener接口只有onLocationChanged方法可以实现,用于接收异步返回的定位结果,回调参数是AMapLocation。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
//可以通过类implement方式实现AMapLocationListener接口,也可以通过创造接口类对象的方法实现
//以下为后者的举例:
AMapLocationListener mAMapLocationListener =
new
AMapLocationListener(){
@Override
public
void
onLocationChanged(AMapLocation amapLocation) {
if
(amapLocation !=
null
) {
if
(amapLocation.getErrorCode() ==
0
) {
//定位成功回调信息,设置相关消息
amapLocation.getLocationType();
//获取当前定位结果来源,如网络定位结果,详见定位类型表
amapLocation.getLatitude();
//获取纬度
amapLocation.getLongitude();
//获取经度
amapLocation.getAccuracy();
//获取精度信息
SimpleDateFormat df =
new
SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss"
);
Date date =
new
Date(amapLocation.getTime());
df.format(date);
//定位时间
amapLocation.getAddress();
//地址,如果option中设置isNeedAddress为false,则没有此结果,网络定位结果中会有地址信息,GPS定位不返回地址信息。
amapLocation.getCountry();
//国家信息
amapLocation.getProvince();
//省信息
amapLocation.getCity();
//城市信息
amapLocation.getDistrict();
//城区信息
amapLocation.getStreet();
//街道信息
amapLocation.getStreetNum();
//街道门牌号信息
amapLocation.getCityCode();
//城市编码
amapLocation.getAdCode();
//地区编码
amapLocation.getAoiName();
//获取当前定位点的AOI信息
}
else
{
//显示错误信息ErrCode是错误码,errInfo是错误信息,详见错误码表。
Log.e(
"AmapError"
,
"location Error, ErrCode:"
+ amapLocation.getErrorCode() +
", errInfo:"
+ amapLocation.getErrorInfo());
}
}
}
}
|
AMapLocation核心方法解析
下表是AMapLocation类的核心方法,是上一章节代码段中方法的详细展开,可在参考手册AMapLocation类中查阅其他未展示方法。
方法 | 返回值 | 返回值说明 | 方法效果 | 备注 |
getLatitude() | double | 纬度 | 获取纬度 | |
getLongitude() | double | 经度 | 获取经度 | |
getAccuracy() | float | 精度 | 获取定位精度 单位:米 | |
getAltitude() | double | 海拔 | 获取海拔高度信息 | 模式为仅设备模式(Device_Sensors)时有效 |
getBearing() | float | 方向角 | 获取方向角信息 | 模式为仅设备模式(Device_Sensors)时有效 |
getAddress() | String | 地址描述 | 获取地址描述 | 模式为仅设备模式(Device_Sensors)时无此信息 |
getCountry() | String | 国家 | 获取国家名称 | 模式为仅设备模式(Device_Sensors)时无此信息 |
getProvince() | String | 省 | 获取省名称 | 模式为仅设备模式(Device_Sensors)时无此信息 |
getCity() | String | 城市 | 获取城市名称 | 模式为仅设备模式(Device_Sensors)时无此信息 |
getDistrict() | String | 城区 | 获取城区名称 | 模式为仅设备模式(Device_Sensors)时无此信息 |
getStreet() | String | 街道 | 获取街道名称 | 模式为仅设备模式(Device_Sensors)时无此信息 |
getStreetNum() | String | 街道门牌号 | 获取街道门牌号信息 | 模式为仅设备模式(Device_Sensors)时无此信息 |
getCityCode() | String | 城市编码 | 获取城市编码信息 | 模式为仅设备模式(Device_Sensors)时无此信息 |
getAdCode() | String | 区域编码 | 获取区域编码信息 | 模式为仅设备模式(Device_Sensors)时无此信息 |
getPoiName() | String | 当前位置POI名称 | 获取当前位置的POI名称 | 模式为仅设备模式(Device_Sensors)时无此信息 |
getAoiName() | String | 当前位置所处AOI名称 | 获取当前位置所处AOI名称 | 模式为仅设备模式(Device_Sensors)时无此信息 |
getLocationType() | int | 定位来源 | 获取定位结果来源 | 可参考定位类型编码表 |
getLocationDetail() | String | 定位信息描述 | 定位信息描述 | 用于问题排查 |
getErrorInfo() | String | 定位错误信息描述 | 定位出现异常的描述 | 可参考定位错误码表 |
getErrorCode() | String | 定位错误码 | 定位出现异常时的编码 | 可参考定位错误码表 |
停止定位
停止定位:
1
|
mLocationClient.stopLocation();
//停止定位
|
销毁定位客户端:
销毁定位客户端之后,若要重新开启定位请重新New一个AMapLocationClient对象。
1
|
mLocationClient.onDestroy();
//销毁定位客户端。
|
注意事项
● 目前手机设备在长时间黑屏或锁屏时CPU会休眠,这导致定位SDK不能正常进行位置更新。若您有锁屏状态下获取位置的需求,您可以应用alarmManager实现1个可叫醒CPU的Timer,定时请求定位。
● 使用定位SDK务必要注册GPS和网络的使用权限。
● 在使用定位SDK时,请尽量保证网络畅通,如获取网络定位,地址信息等都需要设备可以正常接入网络。
● 定位SDK在国内返回高德类型坐标,海外定位将返回GPS坐标。
● 仅设备定位(通过GPS定位)是设备本地定位行为,是不返回地址信息的,地址信息在网络定位时会返回。
● V1.x版本定位SDK参考手册和错误码参考表可以点我获取。
辅助功能
地理围栏
地理围栏功能,是以一个圆形的地理边界作为虚拟围栏,当手机进入、离开该区域时,手机可以接收自动通知。
AMapLocationClient类的 addGeoFenceAlert(int fenceId,double latitude,double longitude, float radius, long expiration, PendingIntent intent) 方法可用于添加地理围栏,该方法的参数:
fenceId-围栏id
latitude-警戒区域中心点的纬度。
longitude-警戒区域中心点的经度。
radius-警戒区域的半径,单位为米,围栏半径在100米-1000米之间。
expiration-警戒时间,单位为毫秒,设置为-1时表示没有时间限制。
intent-当检测到进入或离开警戒区域时将被激活的PendingIntent。该 intent 的 Bundle 的 status 字段值为0表示从区域中离开,1表示进入该区域。
说明:只在进入或离开警戒区域时给出一次警告信息,在警戒区域内活动或者在区域外活动无警告。
示例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
//实例化定位客户端
AMapLocationClient mlocationClient =
null
;
mlocationClient =
new
AMapLocationClient(getApplicationContext());
//注册Receiver,设置过滤器
IntentFilter fliter =
new
IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
fliter.addAction(GEOFENCE_BROADCAST_ACTION);
//mGeoFenceReceiver为自定义的广播接收器
registerReceiver(mGeoFenceReceiver, fliter);
//声明对应的intent对象
Intent intent =
new
Intent(GEOFENCE_BROADCAST_ACTION);
//创建PendingIntent对象
PendingIntent mPendingIntent =
null
;
mPendingIntent = PendingIntent.getBroadcast(getApplicationContext(),
0
,intent,
0
);
//添加地理围栏
mlocationClient.addGeoFenceAlert(fenceId, latLng.latitude,latLng.longitude,
1000
,
1000
*
60
*
30
, mPendingIntent);
//自定义广播接收器
private
BroadcastReceiver mGeoFenceReceiver =
new
BroadcastReceiver() {
@Override
public
void
onReceive(Context context, Intent intent) {
// 接收广播内容,处理进出的具体操作。
}
};
//启动定位
mlocationClient.startLocation();
|
坐标转换
支持GPS/Mapbar/Baidu等多种类型坐标在高德地图上使用。参见类CoordinateConverter。
1
2
3
4
5
6
7
|
CoordinateConverter converter =
new
CoordinateConverter();
// CoordType.GPS 待转换坐标类型
converter.from(CoordType.GPS);
// sourceLatLng待转换坐标点 DPoint类型
converter.coord(sourceLatLng);
// 执行转换操作
DPoint desLatLng = converter.convert();
|
判断位置所在区域
CoordinateConverter类提供的isAMapDataAvailable(double latitude,double longitude)接口可以用来判断指定位置是否在大陆以及港、澳地区。
自2.2版本isAMapDataAvailable(double latitude,double longitude)方法参数进行了调整,第一个参数传纬度,第二个参数传经度;
1
2
3
4
|
CoordinateConverter converter =
new
CoordinateConverter();
//返回true代表当前位置在大陆、港澳地区,反之不在。
boolean
isAMapDataAvailable = converter.isAMapDataAvailable(latitude,longitude);
//第一个参数为纬度,第二个为经度,纬度和经度均为高德坐标系。
|
Android 6.0系统在原有的AndroidManifest.xml声明权限的基础上新增了运行时权限动态检测,定位等权限也包含在其中。
声明目标SDK版本
Android 6.0系统默认为targetSdkVersion小于23的应用默认授予了所申请的所有权限,所以如果您APP设置的targetSdkVersion低于23,在运行时也不会崩溃。
Android Studio:
在build.gradle中声明targetSdkVersion为23。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
android {
compileSdkVersion
23
buildToolsVersion
'23.0.1'
defaultConfig {
applicationId
"com.amap.location.demo"
minSdkVersion
14
targetSdkVersion
23
versionCode
1
versionName
"2.5.0"
}
buildTypes {
release {
minifyEnabled
false
proguardFiles getDefaultProguardFile(
'proguard-android.txt'
),
'proguard-rules.pro'
}
}
}
|
Eclipse:
在AndroidManifest.xml中声明targetSdkVersion为23。
1
2
|
<uses-sdk android:minsdkversion=
"14"
android:targetsdkversion=
"23"
>
</uses-sdk>
|
检查并申请定位权限
在运行定位之前需要对定位权限进行检查和申请,示例代码如下,也可参考示例Demo的CheckPermissionsActivity.Java文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//SDK在Android 6.0下需要进行运行检测的权限如下:
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_STATE
//这里以ACCESS_COARSE_LOCATION为例
if
(ContextCompat.checkSelfPermission(
this
, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
//申请WRITE_EXTERNAL_STORAGE权限
ActivityCompat.requestPermissions(
this
,
new
String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
WRITE_COARSE_LOCATION_REQUEST_CODE);
//自定义的code
}
|
用户授权
在请求权限后,系统会弹出相应的Dialog提示用户授予权限,如下图所示:
接收回调
用户选择允许或拒绝后,会回调onRequestPermissionsResult方法, 该方法类似于onActivityResult方法。
1
2
3
4
5
|
@Override
public
void
onRequestPermissionsResult(
int
requestCode, String[] permissions,
int
[] grantResults) {
super
.onRequestPermissionsResult(requestCode, permissions, grantResults);
//可在此继续其他操作。
}
|
v2.x版定位SDK错误码对照表
需要下载V1.x版定位SDK错误码对照表请移步论坛,该页下方提供在线查看。
当使用V2.x版本定位或地理围栏发生异常时,回调接口将返回错误码。错误码列表如下:
响应码 | 问题说明 | 问题排查策略 |
---|---|---|
0 | 定位成功。 | 可以在定位回调里判断定位返回成功后再进行业务逻辑运算。 |
1 | 一些重要参数为空,如context; | 请对定位传递的参数进行非空判断。 |
2 | 定位失败,由于仅扫描到单个wifi,且没有基站信息。 | 请重新尝试。 |
3 | 获取到的请求参数为空,可能获取过程中出现异常。 | 请对所连接网络进行全面检查,请求可能被篡改。 |
4 | 请求服务器过程中的异常,多为网络情况差,链路不通导致 | 请检查设备网络是否通畅。 |
5 | 请求被恶意劫持,定位结果解析失败。 | 您可以稍后再试,或检查网络链路是否存在异常。 |
6 | 定位服务返回定位失败。 | 请将errorDetail(通过getLocationDetail()方法获取)信息通过工单系统反馈给我们。 |
7 | KEY鉴权失败。 | 请仔细检查key绑定的sha1值与apk签名sha1值是否对应,或通过高频问题查找相关解决办法。 |
8 | Android exception常规错误 | 请将errordetail(通过getLocationDetail()方法获取)信息通过工单系统反馈给我们。 |
9 | 定位初始化时出现异常。 | 请重新启动定位。 |
10 | 定位客户端启动失败。 | 请检查AndroidManifest.xml文件是否配置了APSService定位服务 |
11 | 定位时的基站信息错误。 | 请检查是否安装SIM卡,设备很有可能连入了伪基站网络。 |
12 | 缺少定位权限。 | 请在设备的设置中开启app的定位权限。 |
v1.x版定位SDK错误码对照表
定位SDK v1.x版本(版本号请查询jar包名称或通过SDK提供的getVersion()方法获取)错误码对照表。由于v1.x版本定位SDK稳定性较差,建议您尽快进行更新。
响应码 | 说明 |
0 | 正常,有返回结果 |
21 | IO 操作异常 |
22 | 连接异常 |
23 | 连接超时 |
24 | 无效的参数 |
25 | 空指针异常 |
26 | URL异常 |
27 | 未知主机 |
28 | 连接服务器失败 |
29 | 通信协议解析错误 |
30 | http 连接失败 |
31 | 未知的错误 |
32 | Key鉴权验证失败,请检查key绑定的sha1值、包名与apk信息是否对应,或通过高频问题查找相关解决办法。 |
33 | 没有获取到设备的定位权限 |
34 | 无法获取城市信息 |
35 | 当前ip请求次数超过配额 |