地理围栏

简介

鹰眼的地理围栏服务,将根据轨迹判断终端是否进出围栏,并实时推送报警至观察者。


鹰眼iOS SDK提供了一系列与地理围栏相关的功能。通过 BTKFenceAction 类中相应的接口发起请求,响应通过 BTKFenceDelegate 协议中对应的方法回调给开发者。


鹰眼iOS SDK中的地理围栏分为客户端地理围栏和服务端地理围栏,二者都支持创建、删除、修改、查询操作。使用鹰眼iOS SDK,还可以查询指定终端实体与指定地理围栏的位置关系,查询指定终端实体的历史报警信息。当某终端实体的轨迹触发了地理围栏之后,报警信息会通过 BTKTraceDelegate 的 -(void)onGetPushMessage:(BTKPushMessage *)message; 方法回调给开发者。

坐标系的说明

目前中国主要有以下三种坐标系:


WGS84:为一种大地坐标系,也是目前广泛使用的GPS全球卫星定位系统使用的坐标系。

GCJ02:是由中国国家测绘局制订的地理信息系统的坐标系统。由WGS84坐标系经加密后的坐标系。

BD09:为百度坐标系,在GCJ02坐标系基础上再次加密。其中bd09ll表示百度经纬度坐标,bd09mc表示百度墨卡托米制坐标

非中国地区地图,统一使用WGS84坐标。


鹰眼iOS SDK默认的输入输出坐标均为百度经纬度坐标系(bd09ll),同时可通过”coordType” ,”coordTypeInput”,”coordTypeOutput”(以各方法参数介绍为准)控制输入输出的坐标类型,鹰眼将自动完成转换。

使用场景

鹰眼服务中,地理围栏主要有以下3种使用场景

物流时效监控:司机APP集成鹰眼SDK持续追踪轨迹。车辆管理人员通过服务端为每个司机创建出发地和目的地站点围栏,一旦监控对象进出围栏,鹰眼支持向鹰眼SDK 和 开发者服务端 推送报警信息。


路线偏离报警:鹰眼v3.0新增路线围栏,可设定车辆行驶路线和偏离距离,一旦车辆偏离超过设定的距离,鹰眼围栏将推送报警。


用车行业运营区域监控:利用鹰眼多边形地理围栏和行政区围栏功能,设置运营区域围栏,一旦判断车辆进/出运营区触发报警。

概念说明

围栏的种类

鹰眼iOS SDK提供了两个端的地理围栏:客户端地理围栏和服务端地理围栏。

1. 客户端地理围栏的管理、计算、报警触发均在客户端的鹰眼iOS SDK内部完成,无需联网即可完成地理围栏的运算。

2. 服务端地理围栏的管理、计算、报警触发都在鹰眼服务端完成,依赖于轨迹点及时上传至服务端才能完成围栏的各种操作。因此要想完整地使用服务端地理围栏的功能,使用SDK的设备必须时刻保持联网状态,否则将无法及时触发服务端地理围栏,报警信息也无法及时推送至客户端。与客户端地理围栏相比,服务端地理围栏支持将报警信息推送。


开发者可根据业务场景选择两类围栏中的一类,或两类同时使用,互为补充。


围栏的形状


目前鹰眼iOS SDK的服务端地理围栏支持圆形、多边形、线形、行政区4种围栏形状,客户端地理围栏支持圆形围栏。四种形状的围栏报警行为如下:

1. 圆形围栏:支持设置圆形围栏,一旦进出圆形范围则推送报警。

2. 多边形围栏:支持设置多边形围栏,一旦进出多边形围栏则推送报警。

3. 线形围栏:支持设置折线围栏,一旦偏离或回到设定路线则推送报警。

4. 行政区围栏:支持通过传入行政区名称,创建以行政区边界为界的围栏。


围栏报警去噪的说明

无论是GPS定位还是网络定位都存在误差(也就是常说的定位漂移问题),噪点会造成围栏误报警。 目前鹰眼围栏进行了去噪处理,同时开放了 denoiseAccuracy 去噪精度参数供开发者在创建围栏时设置,围栏运算时,一旦判断轨迹点的定位精度大于此去噪精度,则不参与围栏运算。比如设置denoiseAccuracy=30,则定位精度大于30米的轨迹点都不会参与围栏计算。


在此提供各定位模式的平均精度供开发者参考:

1. 设备在空旷的室外时定位精度均值为几米

2. 设备在室内打开Wi-Fi开关的情况下,Wi-Fi定位的精度均值为十几米到几十米

3. 设备在室内但关闭Wi-Fi开关的情况下,基站定位的精度均值为几百米到几千米

服务端围栏

使用鹰眼iOS SDK可以创建、删除、更新、查询服务端地理围栏。SDK将轨迹上传至服务端时,服务端会进行相应的计算,若有围栏报警被触发,则通过长连接将报警信息推送至SDK;SDK还可以主动发起请求来查询指定监控对象的状态以及报警历史纪录等。需要注意的是:SDK中使用服务端地理围栏的功能时,必须要求网络畅通。若网络不畅,轨迹信息无法及时上传至服务端,围栏计算和推送均无法正常运行。

创建围栏

通过 BTKFenceAction 类中的 -(void)createServerFenceWith:(BTKCreateServerFenceRequest *)request delegate:(id<BTKFenceDelegate>)delegate; 方法创建服务端地理围栏。该方法中的请求对象为 BTKCreateServerFenceRequest 类型,该类提供了4个构造方法,分别用于创建不同形状的地理围栏,其主要区别在于fence参数的类型:

BTKServerCircleFence 代表服务端圆形地理围栏;

BTKServerPolygonFence 代表服务端多边形地理围栏;

BTKServerPolylineFence 代表服务端线形地理围栏;

BTKServerDistrictFence 代表服务端行政区域地理围栏;

下面的代码片段表示,创建一个名称为“server_circle_fence” 的服务端圆形地理围栏,圆心坐标为东经116.3134度、北纬40.0478度,围栏半径为50米。它的监控对象为“entityA”,且当entityA这个终端实体的定位精度大于50米的轨迹点不参与此围栏的计算。

// 圆心
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(40.0478, 116.3134);
// 构造将要创建的新的围栏对象
BTKServerCircleFence *fence = [[BTKServerCircleFence alloc] initWithCenter:center radius:50 coordType:BTK_COORDTYPE_BD09LL denoiseAccuracy:50 fenceName:@"server_circle_fence" monitoredObject:@"entityA"];
// 构造请求对象
BTKCreateServerFenceRequest *circleRequest = [[BTKCreateServerFenceRequest alloc] initWithServerCircleFence:fence serviceID:100000 tag:21];
// 发起创建请求
[[BTKFenceAction sharedInstance] createServerFenceWith:circleRequest delegate:self];


删除围栏

通过 BTKFenceAction 类中的 -(void)deleteServerFenceWith:(BTKDeleteServerFenceRequest *)request delegate:(id<BTKFenceDelegate>)delegate; 方法删除服务端地理围栏。

以下代码片段表示,删除监控对象为终端实体 “entityA” 的所有服务端地理围栏。

// 构造请求对象
BTKDeleteServerFenceRequest *request = [[BTKDeleteServerFenceRequest alloc] initWithMonitoredObject:@"entityA" fenceIDs:nil serviceID:100000 tag:22];
// 发起删除请求
[[BTKFenceAction sharedInstance] deleteServerFenceWith:request delegate:self];


更新围栏

通过 BTKFenceAction 类中的 -(void)updateServerFenceWith:(BTKUpdateServerFenceRequest *)request delegate:(id<BTKFenceDelegate>)delegate; 方法修改服务端地理围栏。围栏的形状类型无法更新,比如只能修改某个多边形围栏的顶点,而无法将其直接更新为圆形围栏。若想把某个多边形围栏更新为圆形围栏,应该先删除此多边形围栏,再新建一个圆形围栏。

以下代码片段表示,将fenceID为138的服务端圆形地理围栏的圆心修改为东经116.2134度、北纬40.1478度,半径修改为60米。且这个围栏的名称改为“server_fence_60”,监控对象改为终端实体“entityB”,去噪精度改为60米。

// 新的圆心
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(40.1478, 116.2134);
// 新的圆形围栏
BTKServerCircleFence *fence = [[BTKServerCircleFence alloc] initWithCenter:center radius:60 coordType:BTK_COORDTYPE_BD09LL denoiseAccuracy:60 fenceName:@"server_fence_60" monitoredObject:@"entityB"];
// 构建请求对象
BTKUpdateServerFenceRequest *request = [[BTKUpdateServerFenceRequest alloc] initWithServerCircleFence:fence fenceID:138 serviceID:100000 tag:23];
// 发起更新请求
[[BTKFenceAction sharedInstance] updateServerFenceWith:request delegate:self];


查询围栏

通过 BTKFenceAction 类中的 -(void)queryServerFenceWith:(BTKQueryServerFenceRequest *)request delegate:(id<BTKFenceDelegate>)delegate; 方法查询服务端地理围栏。该方法可以根据指定的监控对象或围栏ID,列出满足条件的地理围栏。

以下代码片段表示,查询监控对象为终端实体“entityA” 的所有服务端地理围栏。

// 构建请求对象
BTKQueryServerFenceRequest *request = [[BTKQueryServerFenceRequest alloc] initWithMonitoredObject:@"entityA" fenceIDs:nil outputCoordType:BTK_COORDTYPE_BD09LL serviceID:100000 tag:24];
// 发送查询请求
[[BTKFenceAction sharedInstance] queryServerFenceWith:request delegate:self];

实时状态查询

鹰眼iOS SDK支持查询指定监控对象的状态。监控对象即某个终端实体,监控对象的状态是指其相对其上的地理围栏的位置关系:是在圆形或多边形围栏的内部还是外部,是否偏离了线形围栏等。SDK提供了2个方法用于查询监控对象的状态:

使用-(void)queryServerFenceStatusWith:(BTKQueryServerFenceStatusRequest *)request delegate:(id<BTKFenceDelegate>)delegate; 方法,查询被监控对象的状态时,被监控对象的位置以其上传至服务端的最新轨迹点为准。

以下代码片段表示,查询终端实体“entityA” 和所有监控该终端实体的服务端地理围栏的位置关系。

// 构建请求对象
BTKQueryServerFenceStatusRequest *request = [[BTKQueryServerFenceStatusRequest alloc] initWithMonitoredObject:@"entityA" fenceIDs:nil ServiceID:100000 tag:25];
// 发起查询请求
[[BTKFenceAction sharedInstance] queryServerFenceStatusWith:request delegate:self];

使用-(void)queryServerFenceStatusByCustomLocationWith:(BTKQueryServerFenceStatusByCustomLocationRequest *)request delegate:(id<BTKFenceDelegate>)delegate; 方法,可以假设被监控对象处于某自定义的位置坐标时,其和地理围栏的位置关系。

以下代码片段表示,假设“entityA”这个终端实体在东经120.44度,北纬40.11度的话,该终端实体和其上的fenceID为17、23、29的这几个服务端地理围栏的位置关系,只有这几个地理围栏的监控对象是“entityA”这个终端实体时才有意义,如果不知道有哪些地理围栏在监控“entityA”这个终端实体,则fenceIDs属性传入nil即可。

// 被监控对象的模拟位置
CLLocationCoordinate2D customLocation = CLLocationCoordinate2DMake(40.11, 120.44);
// 地理围栏ID列表
NSArray *fenceIDs = @[@17, @23, @29];
// 构建请求对象
BTKQueryServerFenceStatusByCustomLocationRequest *request = [[BTKQueryServerFenceStatusByCustomLocationRequest alloc] initWithmonitoredObject:@"entityA" CustomLocation:customLocation coordType:BTK_COORDTYPE_BD09LL fenceIDs:fenceIDs serviceID:100000 tag:28];
// 发起查询请求
[[BTKFenceAction sharedInstance] queryServerFenceStatusByCustomLocationWith:request delegate:self];


历史报警查询

鹰眼iOS SDK支持查询指定时间段内,服务端地理围栏的历史报警记录。SDK提供了以下2个方法:

使用-(void)queryServerFenceHistoryAlarmWith:(BTKQueryServerFenceHistoryAlarmRequest *)request delegate:(id<BTKFenceDelegate>)delegate; 方法,查询某监控对象的历史报警信息。

以下代码片段表示,查询“entityA”这个终端实体上的所有服务端地理围栏,在过去12小时内的所有报警纪录。

NSUInteger endTime = [[NSDate date] timeIntervalSince1970];
// 构建请求对象
BTKQueryServerFenceHistoryAlarmRequest *request = [[BTKQueryServerFenceHistoryAlarmRequest alloc] initWithMonitoredObject:@"entityA" fenceIDs:nil startTime:(endTime - 12 * 60 * 60) endTime:endTime outputCoordType:BTK_COORDTYPE_BD09LL ServiceID:100000 tag:26];
// 发起查询请求
[[BTKFenceAction sharedInstance] queryServerFenceHistoryAlarmWith:request delegate:self];
使用 -(void)batchQueryServerFenceHistoryAlarmWith:(BTKBatchQueryServerFenceHistoryAlarmRequest *)request delegate:(id<BTKFenceDelegate>)delegate; 方法,批量查询某个service下,所有的历史报警信息。

以下代码片段表示,查询100000这个service下,所有的终端实体上的所有服务端地理围栏,在过去12小时内的报警历史纪录。

NSUInteger endTime = [[NSDate date] timeIntervalSince1970];
// 构建请求对象
BTKBatchQueryServerFenceHistoryAlarmRequest *request = [[BTKBatchQueryServerFenceHistoryAlarmRequest alloc] initWithStartTime:endTime - 12 * 60 * 60 endTime:endTime outputCoordType:BTK_COORDTYPE_BD09LL pageIndex:1 pageSize:10 ServiceID:100000 tag:27];
// 发起查询请求
[[BTKFenceAction sharedInstance] batchQueryServerFenceHistoryAlarmWith:request delegate:self];

报警推送

当服务端围栏被触发之后,会通过长连接将报警信息推送给SDK,SDK会通过 BTKActionDelegate 协议的 -(void)onGetPushMessage:(BTKPushMessage *)message; 方法将报警信息推送给开发者。因此服务端围栏的报警推送要求网络畅通。当接收报警的手机断网或网络状态不好时,会导致报警推送失败,鹰眼服务端将在后续的10分钟之内每隔15s推送一次,直至收到成功响应。若10分钟之后仍未成功,将不再推送,但报警记录将存储在鹰眼服务端。为避免因此造成报警漏接收,开发者可定期使用历史报警查询接口同步报警信息。

以下的代码片段展示了报警信息的解析方法:

-(void)onGetPushMessage:(BTKPushMessage *)message {
    NSLog(@"收到推送消息,消息类型: %@", @(message.type));
    if (message.type == 0x03) {
        BTKPushMessageFenceAlarmContent *content = (BTKPushMessageFenceAlarmContent *)message.content;
        if (content.actionType == BTK_FENCE_MONITORED_OBJECT_ACTION_TYPE_ENTER) {
            NSLog(@"被监控对象 %@ 进入 服务端地理围栏 %@ ", content.monitoredObject, content.fenceName);
        } else if (content.actionType == BTK_FENCE_MONITORED_OBJECT_ACTION_TYPE_EXIT) {
            NSLog(@"被监控对象 %@ 离开 服务端地理围栏 %@ ", content.monitoredObject, content.fenceName);
        }
    }
}


客户端围栏

客户端围栏的所有功能,均在SDK内部完成,不依赖网络。只要开启服务且开始采集之后,每个轨迹点参与客户端围栏的计算,若触发报警,会直接通过 BTKActionDelegate 协议的 -(void)onGetPushMessage:(BTKPushMessage *)message; 方法将报警信息推送给开发者。客户端围栏的历史报警信息也将存储在SDK中,开发者可以通过相应的方法查询客户端围栏的历史报警纪录。客户端历史报警纪录最多保存7天。

客户端地理围栏的管理,主要是指客户端围栏的新建、删除、修改、查询操作。


创建围栏

通过 BTKFenceAction 类中的 -(void)createLocalFenceWith:(BTKCreateLocalFenceRequest *)request delegate:(id<BTKFenceDelegate>)delegate; 方法创建客户端地理围栏。目前客户端地理围栏只有圆形,因此BTKCreateLocalFenceRequest 类只提供了1个构造方法 -(instancetype)initWithLocalCircleFence:(BTKLocalCircleFence *)fence tag:(NSUInteger)tag;,用于创建圆形地理围栏。

以下代码片段表示,创建一个名称为 “local_fence_A” 的客户端圆形地理围栏,圆心位于东经116.3134度、北纬40.0478度,半径为100米。它监控 “entityA” 这个终端实体,且没有设置去噪精度,也就是所有以“entityA”身份开启轨迹服务并开始采集后,采集到的轨迹点都会参与此地理围栏的计算。

// 围栏圆心
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(40.0478, 116.3134);
// 新的客户端地理围栏对象
BTKLocalCircleFence *localFence = [[BTKLocalCircleFence alloc] initWithCenter:center radius:100 coordType:BTK_COORDTYPE_BD09LL denoiseAccuracy:0 fenceName:@"local_fence_A" monitoredObject:@"entityA"];
// 构建请求对象
BTKCreateLocalFenceRequest *request = [[BTKCreateLocalFenceRequest alloc] initWithLocalCircleFence:localFence tag:21];
// 创建客户端地理围栏
[[BTKFenceAction sharedInstance] createLocalFenceWith:request delegate:self];


删除围栏

通过 BTKFenceAction 类中的 -(void)deleteLocalFenceWith:(BTKDeleteLocalFenceRequest *)request delegate:(id<BTKFenceDelegate>)delegate; 方法删除客户端地理围栏。

以下代码片段表示,删除所有以“entityA” 这个终端实体为监控对象的客户端地理围栏。

// 构建请求对象
BTKDeleteLocalFenceRequest *request = [[BTKDeleteLocalFenceRequest alloc] initWithMonitoredObject:@"entityA" fenceIDs:nil tag:22];
// 删除客户端地理围栏
[[BTKFenceAction sharedInstance] deleteLocalFenceWith:request delegate:self];


修改围栏

通过 BTKFenceAction 类中的 -(void)updateLocalFenceWith:(BTKUpdateLocalFenceRequest *)request delegate:(id<BTKFenceDelegate>)delegate; 方法修改客户端地理围栏。

以下代码片段表示,将fenceID为15的客户端地理围栏的名称修改为“local_fence_A”,监控对象改为“entityB”,围栏的圆心坐标改为东经116.5167度,北纬40.1486度,围栏半径改为158米。同时将该客户端地理围栏的去噪精度改为10米,即定位精度超过10米的轨迹点将不再参与围栏计算。

// 新的围栏圆心
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(40.1486, 116.5167);
// 新的客户端圆形地理围栏对象
BTKLocalCircleFence *localFence = [[BTKLocalCircleFence alloc] initWithCenter:center radius:158 coordType:BTK_COORDTYPE_BD09LL denoiseAccuracy:10 fenceName:@"local_fence_A" monitoredObject:@"entityB"];
// 构建请求对象
BTKUpdateLocalFenceRequest *request = [[BTKUpdateLocalFenceRequest alloc] initWithLocalFenceID:15 localCircleFence:localFence tag:23];
// 更新客户端地理围栏
[[BTKFenceAction sharedInstance] updateLocalFenceWith:request delegate:self];


查询围栏

通过 BTKFenceAction 类中的 -(void)queryLocalFenceWith:(BTKQueryLocalFenceRequest *)request delegate:(id<BTKFenceDelegate>)delegate; 方法查询客户端地理围栏。该方法可以根据指定的监控对象或围栏ID,列出满足条件的地理围栏。

以下代码片段表示,查询所有监控对象为“entityA”的客户端地理围栏。

// 构建请求对象
BTKQueryLocalFenceRequest *request = [[BTKQueryLocalFenceRequest alloc] initWithMonitoredObject:@"entityA" fenceIDs:nil tag:24];
// 查询客户端地理围栏
[[BTKFenceAction sharedInstance] queryLocalFenceWith:request delegate:self];


实时状态查询

鹰眼iOS SDK支持查询指定监控对象和客户端围栏的位置关系。开发者可以借此查询当前终端是在客户端地理围栏的内部还是外部。

使用-(void)queryLocalFenceStatusWith:(BTKQueryLocalFenceStatusRequest *)request delegate:(id<BTKFenceDelegate>)delegate; 方法,查询被监控对象的状态时,被监控对象的位置以其最后一次采集的位置为准。假设 “entityA” 和 “entityB” 均创建了客户端地理围栏,先使用 “entityA” 的身份开启轨迹服务后采集轨迹一段时间,在坐标A处停止轨迹服务,再以 “entityB” 的身份开启轨迹服务并开始采集轨迹,若当设备已经移动到坐标B处,查询被监控对象 “entityA” 的状态,则会按照A处的坐标来计算 “entityA” 相对其客户端地理围栏的位置关系。因为每个采集到的轨迹点,仅属于当前开启轨迹服务时,所指定的那个终端实体(entityName)。

以下代码片段表示,查询终端实体 “entityA” 和所有以 “entityA” 为监控对象的客户端地理围栏的位置关系。

// 构建请求对象
BTKQueryLocalFenceStatusRequest *request = [[BTKQueryLocalFenceStatusRequest alloc] initWithMonitoredObject:@"entityA" fenceIDs:nil tag:111];
// 发起查询请求
[[BTKFenceAction sharedInstance] queryLocalFenceStatusWith:request delegate:self];

使用-(void)queryLocalFenceStatusByCustomLocationWith:(BTKQueryLocalFenceStatusByCustomLocationRequest *)request delegate:(id<BTKFenceDelegate>)delegate; 方法,可以假设被监控对象处于某自定义的位置坐标时,其和客户端地理围栏的位置关系。

以下代码片段表示,假设“entityA”这个终端实体在东经116.5167度,北纬40.1486度的话,该终端实体和其上所有客户端地理围栏的位置关系。

// 被监控对象的模拟位置
CLLocationCoordinate2D customLocation = CLLocationCoordinate2DMake(40.1486, 116.5167);
// 构建请求对象
BTKQueryLocalFenceStatusByCustomLocationRequest *request = [[BTKQueryLocalFenceStatusByCustomLocationRequest alloc] initWithmonitoredObject:@"entityA" CustomLocation:customLocation coordType:BTK_COORDTYPE_BD09LL fenceIDs:nil tag:42];
// 发起查询请求
[[BTKFenceAction sharedInstance] queryLocalFenceStatusByCustomLocationWith:request delegate:self];


历史报警查询

鹰眼iOS SDK支持查询指定监控对象,在指定时间段内,客户端地理围栏的历史报警记录。使用-(void)queryLocalFenceHistoryAlarmWith:(BTKQueryLocalFenceHistoryAlarmRequest *)request delegate:(id<BTKFenceDelegate>)delegate; 方法,查询某监控对象的历史报警信息。客户端地理围栏的历史报警纪录最多保存7天。SDK会不定时地清空7天以前的历史报警纪录,因此超出此时间范围的历史报警纪录不保证可以查询到。

以下代码片段表示,查询名称为 “entityA” 的终端实体,在过去1小时内的历史报警纪录。

NSUInteger endTime = [[NSDate date] timeIntervalSince1970] - 3600;
// 构建请求对象
BTKQueryLocalFenceHistoryAlarmRequest *request = [[BTKQueryLocalFenceHistoryAlarmRequest alloc] initWithMonitoredObject:@"entityA" fenceIDs:nil startTime:endTime - 60 * 60 endTime:endTime tag:333];
// 发起查询请求
[[BTKFenceAction sharedInstance] queryLocalFenceHistoryAlarmWith:request delegate:self];


报警推送

客户端地理围栏不依赖网络,因此每个采集到的轨迹点,都会在第一时间参与客户端围栏的计算,若触发报警,则和服务端报警一样,通过 BTKActionDelegate 协议的 -(void)onGetPushMessage:(BTKPushMessage *)message; 方法将报警信息推送给开发者。不同的是,BTKPushMessage 中表示推送消息类型的 type 字段的值不同。

以下代码片段展示了,如何解析推送信息中的客户端地理围栏报警推送。

-(void)onGetPushMessage:(BTKPushMessage *)message {
    NSLog(@"收到推送消息,消息类型: %@", @(message.type));
    if (message.type == 0x04) {
        BTKPushMessageFenceAlarmContent *content = (BTKPushMessageFenceAlarmContent *)message.content;
        if (content.actionType == BTK_FENCE_MONITORED_OBJECT_ACTION_TYPE_ENTER) {
            NSLog(@"被监控对象 %@ 进入 客户端地理围栏 %@ ", content.monitoredObject, content.fenceName);
        } else if (content.actionType == BTK_FENCE_MONITORED_OBJECT_ACTION_TYPE_EXIT) {
            NSLog(@"被监控对象 %@ 离开 客户端地理围栏 %@ ", content.monitoredObject, content.fenceName);
        }
    }
}