遇到一个需求,要求监测若干区域,设备进入这些区域则要上传数据,且可以后台监测,甚至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. Vue 表单验证插件

    verify github:https://github.com/liuyinglong/verifynpm:https://www.npmjs.com/package/vue-verify-plug ...

  2. JavaScript分支语句if, else if, switch 案例详解

      if语句主要是在需要判断,或者在可知有多少种情形时使用的语句.A==B?"A等于B";"A不等于B"; 基本结构:           if(判断条件){ ...

  3. 一个例子简要说明include和require的区别

    先编辑command.php文件 echo 'hello'.PHP_EOL; 然后编辑console.php文件 for($i=1;$i<=3;++$i){ require 'command1. ...

  4. JQuery插件之Animate.css和 jquery-aniview

    Animate.css 一款强大的预设css3动画库 简介 animate.css 是一个来自国外的 CSS3 动画库,它预设了抖动(shake).闪烁(flash).弹跳(bounce).翻转(fl ...

  5. jdk源码剖析五:JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)

    目录 1.背景 2.为什么废弃永久代(PermGen) 3.深入理解元空间(Metaspace) 4.总结 ========正文分割线===== 一.背景 1.1 永久代(PermGen)在哪里? 根 ...

  6. jQuery修炼心得-DOM节点的插入

    1. 内部插入append()与appendTo() append:这个操作与对指定的元素执行原生的appendChild方法,将它们添加到文档中的情况类似. appendTo:实际上,使用这个方法是 ...

  7. 蓝桥杯-无穷分数-java

    /* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ...

  8. ThinkPHP 框架模型

     1 在MainController.class.php 控制器中有一个test的方法,同时还有一个deng的方法,我想在test方法中使用deng方法  表示为 <?php namespace ...

  9. ASP.NET Core开发之HttpContext

    ASP.NET Core中的HttpContext开发,在ASP.NET开发中我们总是会经常用到HttpContext. 那么在ASP.NET Core中要如何使用HttpContext呢,下面就来具 ...

  10. pdf.js实现在HTML下直接浏览pdf文档,无需插件即可实现

    近期,有一个朋友做B端,服务器存了大量的金融类数据,很多都是pdf文档,他现在的做法是,先将pdf文档转换成flash,再放到浏览器上给用户浏览,但是他告诉我,这种体验太差了,而且很好资源,空间已经快 ...