无法后台持续定位:
高德地图持续定位,在后台持续定位一段时间后就会报错;
错误码:12,错误信息:缺少定位权限 请到http://lbs.amap.com/api/android-location-sdk/guide/utilities/errorcode/查看错误码说明,错误详细信息:后台定位服务没有开启,请在设置中打开后台定位服务开关#1207
手机权限上就没有后台定位权限,Android8.0以后才会提示打开后台定位权限,(如果设置了target > 28,需要增加这个权限 ACCESS_BACKGROUND_LOCATION,否则不会弹出"始终允许"这个选择框);
下面看一下踩坑之旅:
集成高德地图定位SDK:
按照官方文档集成就行了:
2、获取定位数据 ;
下面就是在后台持续定位的代码,前台服务;也可以参考这个官方Demo android-o-backgroundlocation:
public class BackLocationService extends Service {
public BackLocationService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startForeground(1,buildNotification());
initLocation();
// 设置定位参数
locationClient.setLocationOption(locationOption);
// 启动定位
locationClient.startLocation();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
locationClient.onDestroy();
super.onDestroy();
}
private AMapLocationClient locationClient = null;
private AMapLocationClientOption locationOption = null;
private void initLocation() {
//初始化client
locationClient = new AMapLocationClient(this.getApplicationContext());
locationOption = getDefaultOption();
//设置定位参数
locationClient.setLocationOption(locationOption);
// 设置定位监听
locationClient.setLocationListener(locationListener);
}
/**
* 默认的定位参数
*/
private AMapLocationClientOption getDefaultOption() {
AMapLocationClientOption mOption = new AMapLocationClientOption();
mOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);//可选,设置定位模式,可选的模式有高精度、仅设备、仅网络。默认为高精度模式
mOption.setGpsFirst(false);//可选,设置是否gps优先,只在高精度模式下有效。默认关闭
mOption.setHttpTimeOut(30000);//可选,设置网络请求超时时间。默认为30秒。在仅设备模式下无效
mOption.setInterval(2000);//可选,设置定位间隔。默认为2秒
mOption.setNeedAddress(true);//可选,设置是否返回逆地理地址信息。默认是true
mOption.setOnceLocation(false);//可选,设置是否单次定位。默认是false
mOption.setOnceLocationLatest(false);//可选,设置是否等待wifi刷新,默认为false.如果设置为true,会自动变为单次定位,持续定位时不要使用
AMapLocationClientOption.setLocationProtocol(AMapLocationClientOption.AMapLocationProtocol.HTTP);//可选, 设置网络请求的协议。可选HTTP或者HTTPS。默认为HTTP
mOption.setSensorEnable(true);//可选,设置是否使用传感器。默认是false
mOption.setWifiScan(true); //可选,设置是否开启wifi扫描。默认为true,如果设置为false会同时停止主动刷新,停止以后完全依赖于系统刷新,定位位置可能存在误差
mOption.setLocationCacheEnable(true); //可选,设置是否使用缓存定位,默认为true
return mOption;
}
/**
* 定位监听
*/
AMapLocationListener locationListener = new AMapLocationListener() {
@Override
public void onLocationChanged(AMapLocation location) {
if (null != location) {
StringBuffer sb = new StringBuffer();
//errCode等于0代表定位成功,其他的为定位失败,具体的可以参照官网定位错误码说明
if (location.getErrorCode() == 0) {
sb.append("Service定位成功" + ",");
sb.append("经 度 : " + location.getLongitude() + ",");
sb.append("纬 度 : " + location.getLatitude() + ",");
sb.append("定位时间: " + Utils.formatUTC(location.getTime(), "yyyy-MM-dd HH:mm:ss") + ",");
} else {
//定位失败
sb.append("Service定位失败" + ",");
sb.append("经 度 : " + location.getLongitude() + ",");
sb.append("纬 度 : " + location.getLatitude() + ",");
sb.append("定位时间: " + Utils.formatUTC(location.getTime(), "yyyy-MM-dd HH:mm:ss") + ",");
sb.append("错误码:" + location.getErrorCode() + ",");
sb.append("错误信息:" + location.getErrorInfo() + ",");
sb.append("错误描述:" + location.getLocationDetail() + ",");
// stopForeground(true);
}
//定位之后的回调时间
sb.append("回调时间: " + Utils.formatUTC(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss") + "\n");
//解析定位结果,
String result = sb.toString();
Log.i("Location", result);
} else {
}
}
};
private static final String NOTIFICATION_CHANNEL_NAME = "BackgroundLocation";
private NotificationManager notificationManager = null;
boolean isCreateChannel = false;
@SuppressLint("NewApi")
private Notification buildNotification() {
Notification.Builder builder = null;
Notification notification = null;
if (android.os.Build.VERSION.SDK_INT >= 26) {
//Android O上对Notification进行了修改,如果设置的targetSDKVersion>=26建议使用此种方式创建通知栏
if (null == notificationManager) {
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
String channelId = getPackageName();
if (!isCreateChannel) {
NotificationChannel notificationChannel = new NotificationChannel(channelId,
NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
notificationChannel.enableLights(true);//是否在桌面icon右上角展示小圆点
notificationChannel.setLightColor(Color.BLUE); //小圆点颜色
notificationChannel.setShowBadge(true); //是否在久按桌面图标时显示此渠道的通知
notificationManager.createNotificationChannel(notificationChannel);
isCreateChannel = true;
}
builder = new Notification.Builder(getApplicationContext(), channelId);
} else {
builder = new Notification.Builder(getApplicationContext());
}
builder.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle(Utils.getAppName(this))
.setContentText("定位Srevice正在后台运行")
.setContentIntent(PendingIntent.getActivity(this, 0, this.getPackageManager().getLaunchIntentForPackage(this.getPackageName()), PendingIntent.FLAG_UPDATE_CURRENT))
.setWhen(System.currentTimeMillis());
if (android.os.Build.VERSION.SDK_INT >= 16) {
notification = builder.build();
} else {
return builder.getNotification();
}
return notification;
}
}
后台持续定位开始报错:
当程序切换到后台,或黑屏几分钟后,就开始报错获取不到位置;
错误码:12,错误信息:缺少定位权限 请到http://lbs.amap.com/api/android-location-sdk/guide/utilities/errorcode/查看错误码说明,错误详细信息:后台定位服务没有开启,请在设置中打开后台定位服务开关#1207;
我把错误打印日志拉出来几条看一下:
2020-03-31 16:54:22.996 22627-22627/com.ccb.socketdemo I/Location: Service定位成功,经 度 : 121.548713,纬 度 : 31.32618,定位时间: 2020-03-31 16:50:30,回调时间: 2020-03-31 16:54:22
2020-03-31 16:54:25.049 22627-22627/com.ccb.socketdemo I/Location: Service定位失败,经 度 : 0.0,纬 度 : 0.0,定位时间: 1970-01-01 08:00:00,错误码:12,错误信息:缺少定位权限 请到http://lbs.amap.com/api/android-location-sdk/guide/utilities/errorcode/查看错误码说明,错误详细信息:后台定位服务没有开启,请在设置中打开后台定位服务开关#1207,错误描述:后台定位服务没有开启,请在设置中打开后台定位服务开关#1207,回调时间: 2020-03-31 16:54:25
2020-03-31 16:54:27.008 22627-22627/com.ccb.socketdemo I/Location: Service定位失败,经 度 : 0.0,纬 度 : 0.0,定位时间: 1970-01-01 08:00:00,错误码:12,错误信息:缺少定位权限 请到http://lbs.amap.com/api/android-location-sdk/guide/utilities/errorcode/查看错误码说明,错误详细信息:后台定位服务没有开启,请在设置中打开后台定位服务开关#1207,错误描述:后台定位服务没有开启,请在设置中打开后台定位服务开关#1207,回调时间: 2020-03-31 16:54:27
2020-03-31 16:54:29.020 22627-22627/com.ccb.socketdemo I/Location: Service定位成功,经 度 : 121.548723,纬 度 : 31.326164,定位时间: 2020-03-31 16:54:19,回调时间: 2020-03-31 16:54:29
我换了好多种保护后台定位方法:
- 前台服务中持续定位 --失败
- Activity+通知栏 持续定位 -- 失败
- 保活服务(前台服务+无声音乐+双服务互相启动+像素保活)中持续定位 -- 失败
- 我把高德的定位Demo下载试了一下,也是会出现这个问题;
于是,我向高德官方提交了问题工单:
关于后台持续定位的答复:
高德的答复是:目前大部分系统会冻结或关闭后台服务,导致后台服务无法正常运行。 目前建议您与对应的厂商进行联系,为您的APP开通白名单权限,保证您的APP在后台运行可以正常使用;
后续:
您的意思是您的APP一直在前台运行没有在后台运行吗?如果一直在前台运行可以根据返回的日志,查看一下相关的定位服务是否被关闭,目前看来是因为后台运行导致定位服务被关闭了。
8.0的设备关于后台服务可以参考如下FAQ:
https://lbs.amap.com/faq/basis/location/43320/?wd=8.0&cateId=&page=&detail=true
8.0以后的版本就需要系统层做设置,SDK层是无法进行干涉的,非常抱歉。
后来:
这个问题终归是没有解决;
后来根据报错1207的日志发现了一个规律 ;
在后台持续定位一段时间后 报错:缺少定位权限 , 然后在1~3分钟之内又可以重新获取到位置 , 然后正常定位10分钟左右,再次报错:缺少定位权限 ,然后在1~3分钟之内又可以重新获取到位置;
当时我的做法是如果报错缺少定位权限1207 ,在5分钟之内可以获取到位置信息,就继续上报位置;如果连续报错缺少定位权限1207 5分钟之后 ,提示用户切换APP到前台 ; 同时在前台时就告知用户尽量保持APP在前台;(当时我做的是位置实时上报的功能,类似于打车软件);
个人感觉,高德地图在后台持续定位 , 被手机系统回收 禁止获取位置信息, 然后高德SDK再通过某种方式强制打开定位 , 然后在被手机系统回收 ; 然后再打开 , 再回收 、 再打开 、 回收 、 打开 、 回收 ; 哈哈.......
2020-03-31 16:54:22.996 22627-22627/com.ccb.socketdemo I/Location: Service定位成功,经 度 : 121.548713,纬 度 : 31.32618,定位时间: 2020-03-31 16:50:30,回调时间: 2020-03-31 16:54:22
2020-03-31 16:54:25.049 22627-22627/com.ccb.socketdemo I/Location: Service定位失败,经 度 : 0.0,纬 度 : 0.0,定位时间: 1970-01-01 08:00:00,错误码:12,错误信息:缺少定位权限 请到http://lbs.amap.com/api/android-location-sdk/guide/utilities/errorcode/查看错误码说明,错误详细信息:后台定位服务没有开启,请在设置中打开后台定位服务开关#1207,错误描述:后台定位服务没有开启,请在设置中打开后台定位服务开关#1207,回调时间: 2020-03-31 16:54:25
2020-03-31 16:54:27.008 22627-22627/com.ccb.socketdemo I/Location: Service定位失败,经 度 : 0.0,纬 度 : 0.0,定位时间: 1970-01-01 08:00:00,错误码:12,错误信息:缺少定位权限 请到http://lbs.amap.com/api/android-location-sdk/guide/utilities/errorcode/查看错误码说明,错误详细信息:后台定位服务没有开启,请在设置中打开后台定位服务开关#1207,错误描述:后台定位服务没有开启,请在设置中打开后台定位服务开关#1207,回调时间: 2020-03-31 16:54:27..............
持续 1~3 分钟获取不到位置 , 然后重新获取位置;
...............
2020-03-31 16:54:29.020 22627-22627/com.ccb.socketdemo I/Location: Service定位成功,经 度 : 121.548723,纬 度 : 31.326164,定位时间: 2020-03-31 16:54:19,回调时间: 2020-03-31 16:54:29