【问题标题】:iBeacon Notification when the app is not running应用程序未运行时的 iBeacon 通知
【发布时间】:2013-10-08 06:25:46
【问题描述】:

我设法制作了一个 iBeacon,当信标在范围内时,它会在我的 iPhone 上触发本地推送通知。当应用程序处于后台模式时,它可以完美运行。

我的问题是:即使应用程序没有运行,即使在后台也不能触发通知?

我认为这是可能的,但我不确定。 如果是这样,我怎样才能做到这一点?

谢谢!

【问题讨论】:

  • 我已经解释了在后台发现 iBeacon 的过程:stackoverflow.com/a/19152814/839566我希望它有所帮助
  • 您可以调用CLLocationManager的requestStateForRegion:实例方法来确定应用启动时您是在区域内还是区域外。
  • @Lapidus 你能告诉我你是如何在后台触发信标的吗?我发现需要帮助的问题。

标签: ios ios7 core-bluetooth ibeacon


【解决方案1】:

是的,这是可能的,而且应该是自动的。

在您创建 CLBeaconRegion 并开始对其进行监控后,定位服务将跟踪您的手机是否在该区域内,即使您的应用未运行也是如此。如果您的应用在过渡期间没有运行,iOS 将在几秒钟内将您的应用启动到后台以调用适当的 CLLocationManagerDelegate 方法。

我通过我自己的应用程序的实验发现了上述行为,但也通过 Apple 的 AirLocate 示例程序目睹了它。使用 AirLocate,如果您设置了监控区域然后重启手机,AirLocate 仍会在手机进入该区域后立即发送本地通知。

测试时要小心,因为有时在打开/关闭 iBeacon 后最多需要 4 分钟,iOS 才能识别区域状态转换。 编辑:从 iPhone 5 开始,应用程序通常会在几秒钟内使用硬件加速来检测信标,如果硬件加速不可用,则可能需要长达 15 分钟。

编辑 3: 作为 iOS 13,您必须确保用户实际授予后台权限,而不是“仅一次”或“使用时”权限,这些权限在他们呈现给用户的对话框。详情请见here

编辑 2:从 iOS 8 开始,您需要确保您已调用并成功获取 locationManager.requestAlwaysAuthorization(),因为 locationManager.requestWhenInUseAuthorization() 只允许在前台检测到信标。

我已在this blog post. 中发布了有关这一切如何运作的详细讨论

【讨论】:

  • 由于某种原因仍然无法为我工作。我尝试将 iPad 配置为信标并使用 iPhone 对其进行监控。当应用程序在后台运行时,它工作正常。但是当应用程序没有运行时,它根本不做任何事情。我正在使用 Apple 的 AirLocate,没有任何更改。我错过了什么吗?非常感谢任何帮助。
  • 在 AirLocate 中,还必须设置 notifyEntryStateOnDisplay=YES 选项才能使其正常工作。该应用程序使用监控菜单选项下的切换开关来执行此操作,您是否启用了此功能?
  • 是的,我做到了。我启用了监控菜单上的所有选项。
  • 大卫,你是如何测试这个的?我自己开始监视一个配置为信标的区域。我杀死了设备中侦听信标的应用程序,也杀死了信标。我打开信标以查看设备中的 AirLocate 应用程序是否启动了侦听信标。没啥事儿。我的方法有问题吗?
  • @davidgyoung 好的,在对我可能想到的一切进行了大量测试之后,由于某种原因,在设备重启后,- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region 将被触发,但didEnterRegion 不会。我已经将我的逻辑移到了那个方法中。很奇怪。
【解决方案2】:

好的,我已经让它正常工作并进行了试验,所以这就是答案。这是在应用终止后越过信标区域边界时调用应用所需执行的操作(假设您的应用在前台正常工作):

  1. 您必须在您的AppDelegate.m 模块中实现CLLocation 委托。这个委托是由 iOS 调用的,所以如果您在 AppDelegate.m 中没有 CLLocation 委托代码,您将无法在您的应用程序终止时响应 iOS。这就是 Apple 的 AirLocate 示例应用的作用。

所以,在AppDelegate.m 中,您需要以下内容(您还需要在CoreLocation.h 中链接):

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.

// This location manager will be used to notify the user of region state transitions when the app has been previously terminated.
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
return YES;
}
  1. AppDelegate.m内部,你需要实现locationManager didDetermineState方法,像这样:

    -(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region{
    
      UILocalNotification *notification = [[UILocalNotification alloc] init];
    
      if(state == CLRegionStateInside)
      {
        notification.alertBody = [NSString stringWithFormat:@"You are inside region %@", region.identifier];
      }
      else if(state == CLRegionStateOutside)
      {
        notification.alertBody = [NSString stringWithFormat:@"You are outside region %@", region.identifier];
      }
     else
     {
       return;
     }
    
      [[UIApplication sharedApplication] presentLocalNotificationNow:notification];
     }
    

--> 因此,如果您的应用程序已被终止(它必须至少运行一次),当设备跨越您正在监控的信标边界时,iOS 将调用您的应用程序并调用您的应用程序中的locationManager:didDetermineState 方法AppDelegate.m 模块。在此方法中,您可以设置并调用 presentLocalNotificationNow。如果发生这种情况时您的应用程序不在前台,即使它被锁定,iOS 也会在屏幕上显示通知。然后,用户将不得不调用该应用程序以获取更多信息。

我很确定内存压力与此无关。此外,设置notifyEntryStateOnDisplay 也与此问题无关。设置notifyEntryStateOnDisplay 仅在用户打开iOS 设备显示屏时使用(即点击“主页”或左上角按钮)。如果用户这样做并且notifyEntryStateOnDisplayTRUE,并且设备在您正在监视的信标区域内,那么您会在那时在显示屏上收到通知。如果此属性设置为FALSE,则不需要。

当然,您需要运行 iOS 7.1 才能使这些东西正常工作。

欲了解更多详情,请访问 Apple 的documentation

【讨论】:

  • +1 将 CLLocation 委托给 AppDelegate,谢谢!
  • CLLocationManagerDelegate 协议能否通过class_addMethodclass_addProtocol动态添加到AppDelegate中?
  • 当相关的Core Location方法被一个iBeacon触发,并且应用之前被终止时,你知道是否先调用applicationDidFinishLaunchingWithOptions:?
  • 我可以确认此答案适用于 Estimote 信标(使用 Estimote SDK)。
  • @TNBtech 你能告诉我它是否适用于iOS8吗? bcoz 我已经在 iOS8 中测试过,但它不起作用所以请告诉我确切的问题是什么?
【解决方案3】:

您需要为 CLBeaconRegion 切换 notifyEntryStateOnDisplay=YES 以便系统为 iBeacon 进入/退出事件唤醒您的应用。

但是有一个棘手的部分。如果您的应用未运行,系统只会唤醒您的应用进行信标进入/退出处理如果您的应用之前因系统内存压力而终止。如果用户通过在任务视图,系统不会唤醒你的应用。要验证此行为,请启动您的应用程序,将其置于后台,然后连续启动几个消耗内存的应用程序。在我的应用因内存压力而被系统终止之前,我启动了几个 3D 游戏。

【讨论】:

  • 您的评论似乎只适用于 iOS 7.0。使用 iOS 7.1,应用程序似乎无论如何都会唤醒:beekn.net/2014/03/…
  • 从 iOS 7 开始不再是这种情况。
  • 这次我们可以执行类似网络服务的任务吗?
【解决方案4】:

只需将您的 iOS 版本升级到 7.1 并设置“notifyEntryStateOnDisplay=YES”,即使您的应用未运行,它也应该像魅力一样工作。我之前遇到过这个问题,但是一旦我做了这个升级它就得到了解决!享受..

【讨论】:

  • 我会建议你在你的 AppDelegate 中设置这个
  • 谢谢,它对我不起作用,但后来我发现我的 iOS 版本是 7.0.4,这就解释了原因:) 谢谢
【解决方案5】:

我能够完成这项工作的唯一方法是监控主要的位置变化,这似乎可以解决问题。请注意,我尚未针对所有设备或用例场景对此进行测试。

【讨论】:

  • 当应用程序根本没有运行时,用户询问如何执行此操作。当应用完全不运行时,它是否可以访问位置服务?
  • 是的。操作系统显然会唤醒订阅此服务的应用程序,即使在应用程序从未启动过的情况下重新启动也是如此。现在我不知道主要位置更改的标准是什么,但对于我执行的进入信标区域的测试用例,它确实有效并提示用户选择启动应用程序。
  • 我觉得是换了基站
【解决方案6】:

是的,我们可以在kill状态或后台状态下显示本地通知,只需按照步骤操作即可,

1) 使用 CLLocationManager 类启动位置管理器。

locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy=kCLLocationAccuracyBest;
locationManager.distanceFilter=kCLDistanceFilterNone;

2) 像这样创建 CLBeaconRegion,

CLBeaconRegion *beacon_Region = [[CLBeaconRegion alloc] initWithProximityUUID:uuid major:mjorVa minor:minorVa identifier:identifier];
beacon_Region.notifyEntryStateOnDisplay = YES;
beacon_Region.notifyOnEntry=YES;
beacon_Region.notifyOnExit=YES;

3) 实现两个位置管理器委托方法,例如,

-didEnterRegion
-didExitRegion

即使您的应用程序被杀死或在后台,上述两种位置管理器方法也可以工作。系统将跟踪您的信标,当它超出范围时,系统将触发 didExitRegion 方法,当进入范围时,系统将触发 didEnterRegion 方法。

【讨论】:

  • 我们可以在 didEnterRegion 中执行 Web 服务吗?
猜你喜欢
  • 2013-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多