当应用程序未运行时,iBeacon通知

57

我成功制作了一个iBeacon,在我的iPhone进入beacon的覆盖范围时触发本地推送通知,当应用程序在后台模式下运行时,完美运作。

我的问题是:即使应用程序没有运行,甚至不在后台模式下,我是否可以触发通知?

我认为这是可能的,但我不确定。如果是这样,我该如何实现呢?

谢谢!


我在这里解释了在后台发现iBeacons的过程:https://dev59.com/rGIk5IYBdhLWcg3wl_Ap#19152814。希望能有所帮助。 - manishnath
дҪ еҸҜд»Ҙи°ғз”ЁCLLocationManagerзҡ„requestStateForRegion:е®һдҫӢж–№жі•жқҘзЎ®е®ҡеә”з”ЁзЁӢеәҸеҗҜеҠЁж—¶дҪ жҳҜеҗҰеңЁеҢәеҹҹеҶ…жҲ–еӨ–гҖӮ - Tobias
@Lapidus,你能否给我一些想法,如何在后台触发信标?我在这方面遇到了问题,需要帮助。 - sinh99
6个回答

68

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

当你创建了一个CLBeaconRegion并开始对其进行监控后,位置服务会跟踪你的手机是否在区域内,即使你的应用程序没有运行。如果你的应用程序在转换期间没有运行,iOS将在后台启动你的应用程序几秒钟,以调用相应的CLLocationManagerDelegate方法。

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

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

编辑3:从iOS 13开始,您必须确保用户实际授予后台权限,而不是操作系统在向用户呈现的对话框中大力推广的“仅一次”或“使用时”权限。有关详细信息,请参见此处

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

我在这篇博客文章中发表了关于所有这些内容如何工作的详细讨论。


仍然无法工作,原因不明。我尝试将iPad配置为信标,并使用iPhone进行监控。当应用程序在后台运行时,它可以正常工作。但是当应用程序没有运行时,它根本不做任何事情。我正在使用苹果的AirLocate,没有做出任何更改。我错过了什么吗?如有帮助,不胜感激。 - Dinesh Reddy Parne
是的,我做了。我在监控菜单上启用了所有选项。 - Dinesh Reddy Parne
大卫,你是用什么方式测试的?我自己开始监视一个被配置为信标的区域。我关闭了监听信标的设备上的应用程序,并杀死了信标。然后打开信标,以查看设备上监听信标的AirLocate应用程序是否启动。但是没有发生任何事情。我的方法有问题吗? - Dinesh Reddy Parne
好的,我无法使用AirLocate进行复现 - 只有在我的应用程序中才能复现。我仍在调查可能的差异。 - davidgyoung
2
@davidgyoung 好的,经过我能想到的所有测试,不知何故,在设备重新启动后,- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region 会被触发,但 didEnterRegion 不会。我已将逻辑移到了那个方法中。非常奇怪。 - Ted Avery
显示剩余18条评论

18

好的,我已经成功地解决了这个问题,并对其进行了实验,下面是答案。如果您的应用在前台运行时正常工作(假设),则需要执行以下操作才能在应用程序终止后越过信标区域边界时调用您的应用程序:

  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也与此问题无关。仅当用户打开iOS设备显示器(即按“主页”或左上角按钮)时,才会使用notifyEntryStateOnDisplay。如果用户执行此操作并且notifyEntryStateOnDisplayTRUE,并且设备位于您正在监视的信标区域内,则会在此时在显示器上收到通知。如果将此属性设置为FALSE,则不会。

当然,您需要运行iOS 7.1才能正确地执行此操作。

有关详细信息,请访问苹果公司的文档


3
谢谢!将CLLocation的代理添加到AppDelegate中,+1! - M to the K
使用class_addMethodclass_addProtocol可以动态地将CLLocationManagerDelegate协议添加到AppDelegate中吗? - Joe Beuckman
当相关的Core Location方法被iBeacon触发,并且应用程序之前已经终止,您知道是否首先调用applicationDidFinishLaunchingWithOptions:吗? - UberJason
我可以确认这个答案适用于Estimote信标(使用Estimote SDK)。 - adbie
@TNBtech,您能否告诉我它在iOS8上是否可用?因为我已经在iOS8上测试过了,但是它无法工作,所以请告诉我确切的问题是什么? - Nikunj Jadav

10

您需要将CLBeaconRegion的notifyEntryStateOnDisplay设置为YES,系统才能在iBeacon进出事件时唤醒您的应用程序。

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


4
您的评论似乎只适用于iOS 7.0。随着iOS 7.1的推出,该应用程序似乎仍然会唤醒:http://beekn.net/2014/03/apple-ios-7-1-launches-major-ibeacon-improvement/ - Pedro Rolo
从iOS 7开始,情况已经不再是这样了。 - Alasdair Allan
这次我们能否执行像网络服务这样的任务? - Vinu David Jose

6

只需将您的iOS版本升级到7.1并设置“notifyEntryStateOnDisplay=YES”,即使您的应用程序未运行,它也应该像魔术般工作。我之前遇到了这个问题,但一旦我升级了系统,问题就解决了!享受吧..


我建议你在AppDelegate中设置这个。 - Hugh Mbaezue
谢谢,这对我没有用,但是后来我发现我的iOS版本是7.0.4,这就解释了为什么 :) 谢谢 - Has AlTaiar

2

是的,我们可以在应用被杀死或后台状态下展示本地通知,只需要按照以下步骤操作:

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服务吗? - Vinu David Jose

2
我能让这个工作的唯一方法是通过监视主要位置更改,这似乎行得通。但请注意,我尚未测试过所有设备或用例场景。

用户问如何在应用程序完全未运行时执行此操作。当应用程序完全未运行时,它是否有任何访问位置服务的权限? - Andrew
1
是的,它有这个功能。操作系统显然会唤醒订阅此服务的应用程序,即使在应用程序从未启动过的情况下重新启动。现在确切的主要位置更改标准我无法确定,但对于我执行的测试用例(进入信标区域),它可以正常工作并提示用户选择启动应用程序。 - Ronny Khan
我认为这是基站的变更。 - NickG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接