【问题标题】:Remove fired Location-Based notification when user exits region当用户退出区域时删除触发的基于位置的通知
【发布时间】:2015-10-17 06:29:18
【问题描述】:

我已经为我的应用设置了(默认 iOS8)基于位置的通知。

UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.regionTriggersOnce = NO;
notification.userInfo = @{ @"notification_id" : @"someID" };
notification.region = region;
notification.alertBody = alertBody;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];

当用户进入指定区域时,通知正确显示在NotificationCenter中。

但是,我想在用户退出该区域时删除该通知消息,因为用户回家并查看通知中心直到他们收到如下所示的消息是没有意义的:

“你在XXXX!”

有人试过类似的吗?文档不清楚如何做到这一点。

【问题讨论】:

标签: ios objective-c geolocation cllocationmanager


【解决方案1】:

CLRegion 对象对此具有特殊属性:notifyOnEntrynotifyOnExit
您需要的一切就是以这种方式更新代码:

CLRegion *region = .... // Configure region here
region.notifyOnEntry = YES;
region.notifyOnExit = NO;  

UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.regionTriggersOnce = NO;
notification.userInfo = @{ @"notification_id" : @"someID" };
notification.region = region;
notification.alertBody = alertBody;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];

这是 Apple documentation 的解释:

@property(nonatomic, copy) CLRegion *region
给这个赋值 属性导致当用户发送本地通知 跨越区域的边界。
区域对象本身定义 用户进入或退出时是否触发通知 地区。

【讨论】:

  • 是的,但您不知道触发通知时所处的状态。您可以保存第一个传递的通知并在第二个出现时删除,但这在这里很棘手。如果您在内部安排通知,则根本不会发生任何事情,并且第一个触发的通知将在退出时。更好的方法是监控区域,但每个应用最多只能注册 20 个区域。我在下面的回答中描述了我的建议。
  • @DevAndArtist,你知道状态:它是区域状态的条目,它是在区域中配置的。如果您在安排本地通知时位于该区域内,则意味着该应用程序已启动,您可以立即显示必要的对话框。如果您需要在用户退出区域时显示通知,那么您可以另外创建具有属性的区域:notifyOnEntry = NOnotifyOnExit = YES 并为该区域安排本地通知,并设置regionTriggersOnce = YES。当用户退出当前区域时会触发一次,其他情况会在用户进入区域时触发。
  • 没错,这是另一种解决方法,但如果两个属性都设置为yes,则如果不调用requestStateForRegion,就无法知道是什么状态触发了您的通知。当然可以建立一个机制来触发两个不同的通知,然后总是取消onExit 通知和传递的onEntry 通知。我有点想念您将两个属性设置为不同的值。我的错。 :D
  • 请告诉我如何在打开关闭的应用程序后确定是否触发了基于区域的 UILocalNotification。
【解决方案2】:

昨天实在是太累了,没能及时回答完。

根据这里的一些答案,我只知道你必须做什么。我自己没有尝试过(地理围栏测试起来真的很痛苦,我知道因为我正在处理一个地理围栏项目 atm。),我以前也不必从通知中心删除已发送的通知。

我假设您的应用程序不会因整个过程而终止。所以我们不会在这里使用startMonitoringForRegion函数。

用 Swift 2.0 编写的答案(翻译成 ObjC 并不难)。

func createAndRegisterSomeNotificationSomewhere() {

    let region = CLCircularRegion(center: someCoordinates, radius: someRadius, identifier: someIdentifier)

    region.notifyOnEntry = true
    region.notifyOnExit = true

    let locationNotification = UILocalNotification()
    locationNotification.alertBody = "someAlertBody"
    locationNotification.userInfo = ["notification_id" : "someID"]
    locationNotification.regionTriggersOnce = false
    locationNotification.region = region // remember 'presentLocalNotificationNow' will not work if this value is set

    UIApplication.sharedApplication().scheduleLocalNotification(locationNotification)
}

/* CLLocationManagerDelegate provides two function */

// func locationManager(manager: CLLocationManager, didEnterRegion region: CLRegion)
// func locationManager(manager: CLLocationManager, didExitRegion region: CLRegion)

/* If I'm not mistaken they are only called for monitored regions and not location based local notifications */
/* I mean you will have to use something like: self.locationManager.startMonitoringForRegion(someCircularRegion) */
/* Correct me if I'm wrong. So consider to rebuild the following logic to ease everything if you want to monitor regions. */

/* Now when you receive your location notification */
func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {

    if let region = notification.region {

        self.locationManager.requestStateForRegion(region)

        /* based on other answers this will remove your noticaiton from NC and cancel from showing it anywhere */
        application.cancelLocalNotification(notification)
        /* but we need this notification still be scheduled because 'region.notifyOnExit = true' should fire it again later */
        application.scheduleLocalNotification(notification)
    }
}

func locationManager(manager: CLLocationManager, didDetermineState state: CLRegionState, forRegion region: CLRegion) {

    /* this is not the best solution, because it adds some latency to the dilivery code and CLRegionState can also be Unknown sometimes */
    /* I'd go with the two functions above if I only had up to 20 regions to monitor (max region limit per App, read CLLocationManager docs) */
    /* the mechanics would be more clear and save */

    switch state {

    case .Inside:

        /* create a new noticiation with the same cpecs as the cancled notification but this time withot the region */
        let sameNotificationAsAbove = UILocalNotification()
        /* if you really need to know your IDs inside userInfo so create some good mechanics to pass these before canceling */
        /* at least I would save the identifier of the region iside the noticiation */
        /* save the notification somewhere to delete it later from NC */
        self.someArrayToSaveDeliveredNotifications.append(sameNotificationAsAbove)

        /* fire the notification */
        UIApplication.sharedApplication().presentLocalNotificationNow(sameNotificationAsAbove)

    case default:

        /* if it is true that notication inside NC can be deleted just by calling 'cancelLocalNotification' function */
        /* so find your notification inside someArrayToSaveDeliveredNotifications bases on the region.identier which you saved inside userInfo */
        let notificationToCancel = self.getNotificationForIdentifier(region.identifier)

        UIApplication.sharedApplication().cancelLocalNotification(notificationToCancel)
        /* this should delete your notification from NC based on other answers */
    }
}

这是我在必要时会构建的某种伪机制,因此如果有任何错误或不正确之处,我会很高兴听到您的反馈。 :)

【讨论】:

    【解决方案3】:

    这将从通知中心清除应用的所有通知。

    [[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0];
    [[UIApplication sharedApplication] cancelAllLocalNotifications];
    

    【讨论】:

    • 我想知道是否可以在通知中心显示特定通知后将其删除。有点像 Facebook Messenger 应用,但使用的是基于位置的通知。
    【解决方案4】:

    如果您按住 UILocalNotification 对象,您似乎可以清除特定通知。使用您在上面的示例中创建的通知对象,您可以调用

    [[UIApplication sharedApplication] cancelLocalNotification:notification];
    

    清除通知。

    【讨论】:

    • 我可以将 UILocalNotification 存储在 NSUserDefaults 中吗?我收到“非财产清单”错误。当用户退出该区域时,我需要在后台模式下从 NotificationCenter 中删除通知。根据我所看到的搜索结果(以及 Foursquare 等示例),这可能根本不可能。
    • 不,您可以在 NSUserDefaults 中存储的唯一数据类型是 NSDictionary、NSArray、NSData、NSNumber 和 NSString。
    【解决方案5】:

    看起来很简单的解决方案。请按照以下步骤对您有所帮助。

    • 创建一项后台服务,该服务将在后台继续工作以检查您的位置。
    • 当您进入某个区域时,会触发您已经完成的本地通知。干得好。
    • 但是当您离开该区域时(使用输入位置详细信息检查后台服务,例如现在位置与用户进入该区域时的位置详细信息相匹配)。使用空数据触发新的本地通知。而且它还会从通知窗口中清除通知。

    【讨论】:

    • 我看到的行为是带有空数据的 UILocalNotification (empty alertBody) 被忽略。如果 alertBody 存在,它会被添加到通知列表中。
    • @vrasidas:只需添加一个主体添加计数 0 和描述是空字符串。并尝试。
    • 在 applicationDidFinishLaunching 中测试:UILocalNotification *localNotif = [[UILocalNotification alloc] init]; localNotif.fireDate = [[NSDate date] dateByAddingTimeInterval:10]; localNotif.alertBody = @"THIS IS A LOCAL NOTIFICATION"; [[UIApplication sharedApplication] scheduleLocalNotification:localNotif]; UILocalNotification *localNotif2 = [[UILocalNotification alloc] init]; localNotif2.fireDate = [[NSDate date] dateByAddingTimeInterval:15]; localNotif2.alertBody = @""; [[UIApplication sharedApplication] scheduleLocalNotification:localNotif2];
    • 这显示了 10 秒后的第一个通知,但第二个被忽略了。我假设 UILocalNotifications 在由区域触发时表现相似。
    【解决方案6】:

    您应该触发一个后台方法,该方法仅应在设备离开该位置时调用。这可以通过为区域创建图层并在它超出边界时立即触发来实现。

    在该方法中,您可以清除相应应用的所有通知

    [[UIApplication sharedApplication] cancelLocalNotification:notification];
    

    或者可以通过调用来清除特定的通知

    UIApplication* application = [UIApplication sharedApplication];
    NSArray* scheduledNotifications = [NSArray arrayWithArray:application.scheduledLocalNotifications];
    application.scheduledLocalNotifications = scheduledNotifications;
    

    您将收到适用于特定应用的所有有效通知。删除特定区域的特定通知。

    【讨论】:

      【解决方案7】:

      CLLocationManagerDelegate 委托具有一组基于设备位置触发的方法。比如;

      -(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
      -(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
      -(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region
      

      在您的情况下,您必须做的是触发以下回调时;

      -(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
      

      从通知中心删除您的通知

      【讨论】:

        猜你喜欢
        • 2014-08-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-02
        • 2012-04-19
        • 2012-03-07
        • 1970-01-01
        • 2014-03-18
        • 1970-01-01
        相关资源
        最近更新 更多