遇到一个需求,要求监测若干区域,设备进入这些区域则要上传数据,且可以后台监测,甚至app被杀死也要监测。发现oc的地理围栏技术完美匹配这个需求,任务做完了,把遇到的坑记录下来,也许能帮到你呢。

要做这个需求,我们需要把任务分成两大块,一块是支持后台监测且app被杀掉也要持续监测,另一块是如何进行区域监测。

而区域监测我们有3种方法完成:

1,oc自有的,利用CLLocationManager监测若干CLCircularRegion区域

2,高德地图旧版地理围栏,利用AMapLocationManager监测若干AMapLocationCircleRegion区域。其实是对CLLocationManager进行简单封装,用法也和CLLocationManager基本一致

3,高德地图新版地理围栏,有个专门进行区域监测的管理类AMapGeoFenceManager,该方法对区域监测做了很多优化。

当围栏创建完毕,且围栏创建成功时会启动定位,这部分无需您来设置,SDK内部执行。 定位机制:通过“远离围栏时逐渐降低定位频率”来降低电量消耗,“离近围栏时逐渐提高定位频率”来保证有足够的定位精度从而完成围栏位置检测。需要注意,在iOS9及之后版本的系统中,如果您希望程序在后台持续检测围栏触发行为,需要保证manager的allowsBackgroundLocationUpdates为YES,设置为YES的时候必须保证 Background Modes 中的 Location updates 处于选中状态,否则会抛出异常。

一 如何实现后台定位且被杀掉也能持续定位

1 实现后台定位

1.1 工程配置

  • iOS8之前
    如果想要定位需要在plist文件中位置key  Privacy - Location Usage Description默认只在前台定位,如果想开启后台定位需要在开启后台模式

    Snip20150825_1.png
  • iOS8
    需要在plist文件中配置NSLocationWhenInUseUsageDescription(前台定位)
    NSLocationAlwaysUsageDescription(前后台定位) 注:可以两个都配置上

1.2 用户权限请求(代码实现)

利用CLLocationManager的实例去请求权限,如果使用的是高德地图,就用AMapLocationManager或者AMapGeoFenceManager的实例去请求。需要注意的是,不管使用哪一个类,只要有一个去请求权限就可以了。

//请求前台定位权限
- (void)requestWhenInUseAuthorization __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_8_0);
//请求前后台定位权限,即使当前权限为前台定位也会生效
- (void)requestAlwaysAuthorization __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_8_0);
    • 注意:如果是前台定位权限,但是开始了后台模式,在后台也是可以定位的,但是屏幕的上边会有蓝条,提示用户是哪个应用在定位

    • iOS 9
      如果想要在后台定位,除了配置NSLocationAlwaysUsageDescription(前后台定位)外,还需要手动设置allowsBackgroundLocationUpdates = YES

    • 指定定位是否会被系统自动暂停属性也要设置为NO。pausesLocationUpdatesAutomatically = NO;

2 实现app被杀掉也能定位

如果你申请了后台定位权限且用户同意,那么当你的定位请求被触发的时候,比如位置移动1000米重新定位,系统会自动唤醒你的app,在application:didFinishLaunchingWithOptions方法中,

UIApplicationLaunchOptionsLocationKey
就是被定位唤醒

在被唤醒后一定要创建你的定位或监测的对象。这样才能响应到定位监测的回调。在我的例子里,self.regionManager是一个单例,只要app启动,就会创建并且开始检测,这一步至关重要,是实现app被杀掉也能定位的最关键步骤。

你在被唤醒的这段时间可以做一些简单操作,可以保存定位信息,上传监测数据等。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self locationTest:launchOptions];
return YES;
} - (void)locationTest:(NSDictionary *)launchOptions {
[self.regionManager starMonitorRegion];
if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
[self.regionManager saveMessage:@"被区域监测唤醒"];
} } - (RegionManager *)regionManager {
return [RegionManager shareInstance];
}

以上就是如何实现后台定位且被杀掉也能定位。接下来我们讨论如何进行区域监测。

二  区域监测,也称地理围栏,或者临近警告

如果希望iOS设备进出某个区域发出通知,那么这种区域监测的功能也被称为临近警告。所谓临近警告的示意图如图所示。

临近警告的示意图

1 oc自有的地理围栏实现

利用CoreLocation就可以实现地理围栏,

  1.1 创建CLLocationManager对象,该对象负责获取定位相关信息,并为该对象设置一些必要的属性。

-(CLLocationManager *)locationM
{
if (!_locationM) {
_locationM = [[CLLocationManager alloc] init];
_locationM.delegate = self;
_locationM.desiredAccuracy = kCLLocationAccuracyBest;
_locationM.distanceFilter = ;
// 主动请求定位授权
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
[_locationM requestAlwaysAuthorization];
#endif
//这是iOS9中针对后台定位推出的新属性 不设置的话 可是会出现顶部蓝条的哦(类似热点连接)
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
[_locationM setAllowsBackgroundLocationUpdates:YES];
#endif _locationM.pausesLocationUpdatesAutomatically = NO;
}
return _locationM;
}

  1.2 为CLLocationManager指定delegate属性,该属性值必须是一个实现CLLocationManagerDelegate协议的对象,实现CLLocationManagerDelegate协议的对象.实现CLLocationManagerDelegate协议时可根据需要实现协议中特定的方法.

// 进入指定区域以后将弹出提示框提示用户

-(void)locationManager:(CLLocationManager *)manager
didEnterRegion:(CLRegion *)region {
NSString *message;
for (StudentInfoModel *student in self.studentArray) { if ([region.identifier isEqualToString:student.qingqingUserId]) {
message = [NSString stringWithFormat:@"进入轻轻家教第%d中心区域",[student.qingqingUserId intValue]/+];
}
}
[[[UIAlertView alloc] initWithTitle:@"区域检测提示"
message:message delegate:nil
cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
} // 离开指定区域以后将弹出提示框提示用户 -(void)locationManager:(CLLocationManager *)manager
didExitRegion:(CLRegion *)region {
NSString *message;
for (StudentInfoModel *student in self.studentArray) {
if ([region.identifier isEqualToString:student.qingqingUserId]) {
message = [NSString stringWithFormat:@"离开轻轻家教第%d中心区域",[student.qingqingUserId intValue]/+];
}
}
[[[UIAlertView alloc] initWithTitle:@"区域检测提示" message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
} /**
* 监听区域失败时调用
*
* @param manager 位置管理者
* @param region 区域
* @param error 错误
*/
-(void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error
{ NSLog(@"监听区域失败");
}

  1.3调用CLLocationManager的startMonitoringForRegion:方法进行区域监测.区域监测结束时,可调用stopMonitoringForRegion:方法结束区域监测.可以监测多个区域,数量没有上线,不过要考虑性能。

- (void)starMonitorRegion {
//监听最近联系的20个家长 测试数据
for (int i = ; i < ; i++) {
StudentInfoModel *student = [[StudentInfoModel alloc] init];
CLLocationCoordinate2D companyCenter;
companyCenter.latitude = 31.200546;
companyCenter.longitude = 121.599263 + i*0.005;
student.location = companyCenter;
student.qingqingUserId = [NSString stringWithFormat:@"%d",i*];
[self.studentArray addObject:student];
[self regionObserve:student];
} } - (void)regionObserve:(StudentInfoModel *)student {
if([CLLocationManager locationServicesEnabled]) { // 定义一个CLLocationCoordinate2D作为区域的圆
// 使用CLCircularRegion创建一个圆形区域,
// 确定区域半径
CLLocationDistance radius = ;
// 使用前必须判定当前的监听区域半径是否大于最大可被监听的区域半径
if(radius > self.locationM.maximumRegionMonitoringDistance) {
radius = self.locationM.maximumRegionMonitoringDistance;
}
CLRegion* fkit = [[CLCircularRegion alloc] initWithCenter:student.location
radius:radius identifier:student.qingqingUserId];
// 开始监听fkit区域
[self.locationM startMonitoringForRegion:fkit];
// 请求区域状态(如果发生了进入或者离开区域的动作也会调用对应的代理方法)
[self.locationM requestStateForRegion:fkit]; } else { // 使用警告框提醒用户
[[[UIAlertView alloc] initWithTitle:@"提醒"
message:@"您的设备不支持定位" delegate:self
cancelButtonTitle:@"确定" otherButtonTitles: nil] show]; }
}

2 高德地图的旧版地理围栏

  旧版地理围栏和oc自有的用法基本一致,这里就不累赘。CLLocationManager换成AMapLocationManager,CLCircularRegion换成AMapLocationCircleRegion。文章结尾会有demo下载。

3 高德地图的新版地理围栏

  新版的高德地图对地理围栏进行了优化,把地理围栏从AMapLocationManager中剥离,有了自己单独的管理类AMapGeoFenceManager。当围栏创建完毕,且围栏创建成功时会启动定位,这部分无需您来设置,SDK内部执行。 定位机制:通过“远离围栏时逐渐降低定位频率”来降低电量消耗,“离近围栏时逐渐提高定位频率”来保证有足够的定位精度从而完成围栏位置检测。需要注意,在iOS9及之后版本的系统中,如果您希望程序在后台持续检测围栏触发行为,需要保证manager的allowsBackgroundLocationUpdates为YES,设置为YES的时候必须保证 Background Modes 中的 Location updates 处于选中状态,否则会抛出异常。

  • AMapGeoFenceManager创建,并设置相关属性

    - (AMapGeoFenceManager *)geoFenceManager {
    if (!_geoFenceManager) {
    _geoFenceManager = [[AMapGeoFenceManager alloc] init];
    _geoFenceManager.delegate = self;
    _geoFenceManager.activeAction = AMapGeoFenceActiveActionInside | AMapGeoFenceActiveActionOutside; //设置希望侦测的围栏触发行为,默认是侦测用户进入围栏的行为,即AMapGeoFenceActiveActionInside,这边设置为进入,离开触发回调
    _geoFenceManager.allowsBackgroundLocationUpdates = YES; //允许后台定位
    _geoFenceManager.pausesLocationUpdatesAutomatically = NO;
    }
    return _geoFenceManager;
    }
  • 监听区域,可以多个
    // 清除上一次创建的围栏
    - (void)doClear {
    [self.geoFenceManager removeAllGeoFenceRegions]; //移除所有已经添加的围栏,如果有正在请求的围栏也会丢弃
    } - (void)starMonitorRegions{
    if([CLLocationManager locationServicesEnabled]) {
       [self doClear];
    //监听最近联系的20个家长 测试数据
    for (int i = ; i < kObserveStudentNum ; i++) {
    StudentInfoModel *student = [[StudentInfoModel alloc] init];
    CLLocationCoordinate2D companyCenter;
    companyCenter.latitude = 31.200546;
    companyCenter.longitude = 121.599263 + i*0.005;
    student.location = companyCenter;
    student.qingqingUserId = [NSString stringWithFormat:@"%d",i*];
    [self monitorRegion:student];
    }
    } else {
    DDLogInfo(@"定位服务.定位不可用");
    #if DEBUG
    [QQThemeAlertView showWithTitle:@"定位不能用了" message:@"设备不支持定位,找开发!" options:@[@"我知道了"] block:nil];
    #endif
    }
    } - (void)monitorRegion:(StudentInfoModel *)studentInfo {
    // 确定区域半径和圆心
    CLLocationCoordinate2D regionCenter;
    regionCenter.latitude = studentInfo.latitude;
    regionCenter.longitude = studentInfo.longitude;
    //该区域的唯一标识
    NSString *customID = [NSString stringWithFormat:@"%lf+%lf",studentInfo.latitude,studentInfo.longitude];
    [self.geoFenceManager addCircleRegionForMonitoringWithCenter:regionCenter radius:kRegionRadius customID:customID];
    }
  • 实现manager的delegate方法

    #pragma mark - AMapGeoFenceManagerDelegate
    
    //添加地理围栏完成后的回调,成功与失败都会调用
    - (void)amapGeoFenceManager:(AMapGeoFenceManager *)manager didAddRegionForMonitoringFinished:(NSArray<AMapGeoFenceRegion *> *)regions customID:(NSString *)customID error:(NSError *)error { if (error) {
    DDLogInfo(@"区域检测.添加地理围栏失败%@",error);
    } else {
    AMapGeoFenceRegion *region = [regions firstObject];
    DDLogInfo(@"区域检测.添加地理围栏成功%@",region.customID);
    //[self saveMessage:[NSString stringWithFormat:@"区域检测.添加地理围栏成功%@",region.customID]];
    }
    } //地理围栏状态改变时回调,当围栏状态的值发生改变,定位失败都会调用
    - (void)amapGeoFenceManager:(AMapGeoFenceManager *)manager didGeoFencesStatusChangedForRegion:(AMapGeoFenceRegion *)region customID:(NSString *)customID error:(NSError *)error {
    if (error) {
    DDLogInfo(@"区域检测.定位失败%@",error);
    }else{
    DDLogInfo(@"区域检测.状态改变%@",[region description]);
    [self saveMessage:[NSString stringWithFormat:@"区域检测.状态改变%ld",[region fenceStatus]]];
    switch (region.fenceStatus) {
    case AMapGeoFenceRegionStatusInside:
    {
    //在区域内
    }
    break;
    case AMapGeoFenceRegionStatusOutside:
    {
    //在区域外 }
    break;
    case AMapGeoFenceRegionStatusStayed:
    {
    //停留超过十分钟 }
    break; default: {
    //未知
    }
    break;
    }
    }
    }
  •   

到此,地理围栏技术讲解结束,遇到的坑:

1 新版地理围栏,高德文档写区域监测半径大于0即可,然而我用模拟器测试,跑gpx文件模拟路线,大于250m才有回调,自己修改模拟器customLocation位置,大于500m才有回调,目前位置还没有搞明白。有遇到同样问题欢迎讨论。

2 要实现app被杀死持续监测区域,一定要知道当你进入监测区域,系统会唤醒app,在application:didFinishLaunchingWithOptions方法中要有处理定位回调的实例。不然只能实现后台监测。

DEMO下载:

1 利用oc自有CLLocationManager监测区域DEMO:https://github.com/wangdachui/monitorRegion

2 高德地图的地理围栏,官方DEMO已经写得很详细,注释也很清除。看了高德的注释也让我明白了CLLocationManager监测区域的实现,赞一个。DEMO地址:http://lbs.amap.com/api/ios-location-sdk/download/

iOS地理围栏技术的应用的更多相关文章

  1. HMS Core地理围栏能力助你实现指定范围人群的精准消息推送

    精准推送是移动端产品留存阶段的主要运营手段,精准推送常常会与用户画像紧密结合,针对用户的喜好.画像,采用不同策略,但基于用户所属区域推送消息却很难实现.目前市面上大多数第三方消息推送服务商,在系统未深 ...

  2. 【Android Developers Training】 106. 创建并检测地理围栏

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  3. 基于百度地图SDK和Elasticsearch GEO查询的地理围栏分析系统(1)

    本文描述了一个系统,功能是评价和抽象地理围栏(Geo-fencing),以及监控和分析核心地理围栏中业务的表现. 技术栈:Spring-JQuery-百度地图WEB SDK 存储:Hive-Elast ...

  4. 地理围栏算法解析(Geo-fencing)

    地理围栏算法解析 http://www.cnblogs.com/LBSer/p/4471742.html 地理围栏(Geo-fencing)是LBS的一种应用,就是用一个虚拟的栅栏围出一个虚拟地理边界 ...

  5. 转:基于IOS上MDM技术相关资料整理及汇总

    一.MDM相关知识: MDM (Mobile Device Management ),即移动设备管理.在21世纪的今天,数据是企业宝贵的资产,安全问题更是重中之重,在移动互联网时代,员工个人的设备接入 ...

  6. 基于百度地图SDK和Elasticsearch GEO查询的地理围栏分析系统(2)-查询实现

    在上一篇博客中,我们准备好了数据.现在数据已经以我们需要的格式,存放在Elasticsearch中了. 本文讲述如何在Elasticsearch中进行空间GEO查询和聚合查询,以及如何准备ajax接口 ...

  7. 基于百度地图SDK和Elasticsearch GEO查询的地理围栏分析系统(3)-前端实现

    转载自:http://www.cnblogs.com/Auyuer/p/8086975.html MoonLight可视化订单需求区域分析系统实现功能: 在现实生活中,计算机和互联网迅速发展,人们越来 ...

  8. Python一行代码处理地理围栏

    最近在工作中遇到了这个一个需求,用户设定地理围栏,后台获取到实时位置信息后通过与围栏比较,判断是否越界等. 这个过程需要用到数据协议为GEOjson,通过查阅资料后,发现python的shapely库 ...

  9. 基于IOS上MDM技术相关资料整理及汇总

    (转自:http://www.mbaike.net/special/1542.html) 一.MDM相关知识:MDM (Mobile Device Management ),即移动设备管理.在21世纪 ...

随机推荐

  1. MyBatis注解配置动态SQL

    MySQL创建表 DROP TABLE IF EXISTS `tb_employee`; CREATE TABLE `tb_employee` ( `id` int(11) NOT NULL AUTO ...

  2. http协议的八种请求类型

    GET:向特定的资源发出请求. POST:向指定资源提交数据进行处理请求(例如提交表单或者上传文件).数据被包含在请求体中.POST请求可能会导致新的资源的创建和/或已有资源的修改. OPTIONS: ...

  3. React Starter Kit 中文文档

    最近没事又翻译了个玩意. Github上的一个Star 非常高的 React 样板程序. 由Node.js,Express,GraphQL和React构建,可选加入Redux等,并可以包含Webpac ...

  4. java获得路径的多种方式

    本文讲解java语言中获得运行时路径的多种方式,包括java项目.java web项目.jar.weblogic等多种场景. 一.this.getClass().getClassLoader().ge ...

  5. 【代码学习】GD库中图片缩印

    bool imagecopyresampled ( resource $dst_image, resource $src_image, int $dst_x, int $dst_y, int $src ...

  6. bzoj4766 文艺计算姬

    Description "奋战三星期,造台计算机".小W响应号召,花了三星期造了台文艺计算姬.文艺计算姬比普通计算机有更多的艺术细胞.普通计算机能计算一个带标号完全图的生成树个数, ...

  7. uoj#228 基础数据结构练习题

    题面:http://uoj.ac/problem/228 正解:线段树. 我们可以发现,开根号时一个区间中的数总是趋近相等.判断一个区间的数是否相等,只要判断最大值和最小值是否相等就行了.如果这个区间 ...

  8. [原创]ssget过滤动态块的方式

    Autocad在2006增加了新的动态块功能,方便了对块的动态修改,但是修改动态块后,块名会变成一个匿名块,导致无法通过块名来快速过滤. 明经论坛上有人通过全选块后再来遍历筛选,我通过研究简化了这个问 ...

  9. Mirantis MCP 1.0:OpenStack 和 Kubernetes 整合的第一步

    1.前言 Mirantis 公司在2014年9月14日宣布收购 TCPCloud,然后宣布在2017年第一季度会推出全新的私有云产品.从那时候开始,我就一直满怀期待.终于,今年4月19日,Mirant ...

  10. Excel 数据导出

    Web  controller /// <summary> /// 导出数据 /// </summary> /// <param name="UserID&qu ...