Get Beacon Messages

Your app can subscribe to Bluetooth Low Energy (BLE) beacon messages using the same mechanism that is used to subscribe to messages published by other nearby devices.

By default, beacon subscriptions work only when your app is in the foreground. When your app goes to the background, the subscriptions automatically stop scanning for beacons. See Background Scanning for details about how to enable background scanning.

To subscribe to beacons, set the deviceTypesToDiscover parameter to kGNSDeviceBLEBeacon in the subscription parameters. The following snippet demonstrates how to do this:

Objective-C

id<GNSSubscription> beaconSubscription = [messageManager
    subscriptionWithMessageFoundHandler:myMessageFoundHandler
                     messageLostHandler:myMessageLostHandler
                            paramsBlock:^(GNSSubscriptionParams *params) {
                              params.deviceTypesToDiscover = kGNSDeviceBLEBeacon;
                            }];

Swift

let beaconSubscription = messageManager.subscriptionWithMessageFoundHandler(
    myMessageFoundHandler, messageLostHandler: myMessageLostHandler,
    paramsBlock: { (params: GNSSubscriptionParams!) in
      params.deviceTypesToDiscover = .BLEBeacon
    })

The above subscription only discovers beacons owned by your project, and receives all messages from those beacons. If you want to receive messages from beacons registered with a different namespace, you can pass a namespace in the subscription parameters. Similarly, if you want a specific type of message, you can also pass a message type for filtering. The following snippet shows how to do this:

Objective-C

id<GNSSubscription> beaconSubscription = [messageManager
    subscriptionWithMessageFoundHandler:myMessageFoundHandler
                     messageLostHandler:myMessageLostHandler
                            paramsBlock:^(GNSSubscriptionParams *params) {
                              params.deviceTypesToDiscover = kGNSDeviceBLEBeacon;
                              params.messageNamespace = @"com.mycompany.mybeaconservice";
                              params.type = @"mybeacontype";
                            }];

Swift

let beaconSubscription = messageManager.subscriptionWithMessageFoundHandler(
    myMessageFoundHandler, messageLostHandler: myMessageLostHandler,
    paramsBlock: { (params: GNSSubscriptionParams!) in
      params.deviceTypesToDiscover = .BLEBeacon
      params.messageNamespace = "com.mycompany.mybeaconservice"
      params.type = "mybeacontype"
    })

By default, a beacon subscription scans for both type of beacons, Eddystone and iBeacon. When iBeacon scanning is enabled, users will be prompted to give permission for the app to use their location data. Your app's Info.plist must include the NSLocationWhenInUseUsageDescription key with short explanation of why location is being used. See Apple's documentation for details.

If you want to scan only for Eddystone beacons, you can disable iBeacon scanning in the GNSBeaconStrategy, and iOS will not ask the user for permission to use location. The following snippet shows how to disable iBeacon scanning for the original subscription above:

Objective-C

id<GNSSubscription> beaconSubscription = [messageManager
    subscriptionWithMessageFoundHandler:myMessageFoundHandler
                     messageLostHandler:myMessageLostHandler
                            paramsBlock:^(GNSSubscriptionParams *params) {
                              params.deviceTypesToDiscover = kGNSDeviceBLEBeacon;
                              params.beaconStrategy =
                                  [GNSBeaconStrategy strategyWithParamsBlock:^(GNSBeaconStrategyParams *params) {
                                    params.includeIBeacons = NO;
                                  };
                            }];

Swift

let beaconSubscription = messageManager.subscriptionWithMessageFoundHandler(
    myMessageFoundHandler, messageLostHandler: myMessageLostHandler,
    paramsBlock: { (params: GNSSubscriptionParams!) in
      params.deviceTypesToDiscover = .BLEBeacon
      params.beaconStrategy =
          GNSBeaconStrategy(paramsBlock: { (params: GNSBeaconStrategyParams!) in
            params.includeIBeacons = false
          })
    })

By default, low power scanning is enabled, which can sometimes result in large latencies when finding Eddystone beacons. When low power mode is disabled, iBeacon scanning is used to help find Eddystone beacons, which can reduce these latencies. However, this results in greater battery usage, and iOS will ask the user for permission to use location.

The following snippet shows how to disable low power mode when scanning for Eddystone beacons.

Objective-C

id<GNSSubscription> beaconSubscription = [messageManager
    subscriptionWithMessageFoundHandler:myMessageFoundHandler
                     messageLostHandler:myMessageLostHandler
                            paramsBlock:^(GNSSubscriptionParams *params) {
                              params.deviceTypesToDiscover = kGNSDeviceBLEBeacon;
                              params.beaconStrategy =
                                  [GNSBeaconStrategy strategyWithParamsBlock:^(GNSBeaconStrategyParams *params) {
                                    params.includeIBeacons = NO;
                                    params.lowPowerPreferred = NO;
                                  };
                            }];

Swift

let beaconSubscription = messageManager.subscriptionWithMessageFoundHandler(
    myMessageFoundHandler, messageLostHandler: myMessageLostHandler,
    paramsBlock: { (params: GNSSubscriptionParams!) in
      params.deviceTypesToDiscover = .BLEBeacon
      params.beaconStrategy =
          GNSBeaconStrategy(paramsBlock: { (params: GNSBeaconStrategyParams!) in
            params.includeIBeacons = false
            params.lowPowerPreferred = false
          })
    })

When scanning for iBeacons, the iOS location permission dialog is preceded by the Nearby permission dialog. If you want to override this dialog (for instance, to provide a "preflight" dialog that explains why location permission is needed), set the permissionRequestHandler to a custom block in the subscription parameters. The following snippet shows how to do this:

Objective-C

id<GNSSubscription> beaconSubscription = [messageManager
    subscriptionWithMessageFoundHandler:myMessageFoundHandler
                     messageLostHandler:myMessageLostHandler
                            paramsBlock:^(GNSSubscriptionParams *params) {
                              params.deviceTypesToDiscover = kGNSDeviceBLEBeacon;
                              params.permissionRequestHandler = ^(GNSPermissionHandler permissionHandler) {
                                // Show your custom dialog here, and don't forget to call permissionHandler after it is dismissed
                                permissionHandler(userGavePermission);
                              };
                            }];

Swift

let beaconSubscription = messageManager.subscriptionWithMessageFoundHandler(
    myMessageFoundHandler, messageLostHandler: myMessageLostHandler,
    paramsBlock: { (params: GNSSubscriptionParams!) in
      params.deviceTypesToDiscover = .BLEBeacon
      params.permissionRequestHandler = { (permissionHandler: GNSPermissionHandler!) in
        // Show your custom dialog here, and don't forget to call permissionHandler after it is dismissed
        permissionHandler(userGavePermission);
      }
    })

Background Scanning

Since beacon scanning uses BLE, it can work in the background. Here are some things you should be aware of when deciding to use background mode:

  • There is an added battery cost for background BLE. The cost is low, but you should measure it before deciding to use background mode.
  • iOS will ask the user for permission to use location in the background if iBeacon scanning is enabled or low power mode is disabled.

To enable beacon scanning in the background, follow these additional steps:

  • Enable background mode for your subscription by passing in a properly configured GNSBeaconStrategy object. The following snippet shows how to do this:

    Objective-C

    id<GNSSubscription> beaconSubscription = [messageManager
        subscriptionWithMessageFoundHandler:myMessageFoundHandler
                         messageLostHandler:myMessageLostHandler
                                paramsBlock:^(GNSSubscriptionParams *params) {
                                  params.deviceTypesToDiscover = kGNSDeviceBLEBeacon;
                                  params.beaconStrategy = [GNSBeaconStrategy
                                      strategyWithParamsBlock:^(GNSBeaconStrategyParams *params) {
                                        params.allowInBackground = YES;
                                      }];
                                }];
    

    Swift

    let beaconSubscription = messageManager.subscriptionWithMessageFoundHandler(
        myMessageFoundHandler, messageLostHandler: myMessageLostHandler,
        paramsBlock: { (params: GNSSubscriptionParams!) in
          params.deviceTypesToDiscover = .BLEBeacon
          params.beaconStrategy =
              GNSBeaconStrategy(paramsBlock: { (params: GNSBeaconStrategyParams!) in
                params.allowInBackground = true
              })
        })
    

  • Add the required entries to your app's Info.plist:

    • UIBackgroundModes entries:

      • bluetooth-central for BLE scanning in the background.
      • location for iBeacon scanning in the background using high-power mode. You can omit this if you're doing low power scanning for Eddystone beacons only.
    • NSLocationAlwaysUsageDescription string describing why you will be tracking the user's location in the background. For example, "Your location is needed to scan for beacons in the background." See Apple's documentation for details. You can omit this if you're doing low power scanning for Eddystone beacons only.

  • Can the user enable or disable background scanning in your app? If so, you should save the background mode value to NSUserDefaults because iOS can kill your app at any time while it's in the background. Your app should do the following:

    • Save the background mode value to NSUserDefaults whenever the user changes it.
    • On startup, read it from NSUserDefaults and restore the beacon subscription if background mode is enabled.

Background Notifications

If you want your app to notify the user when beacons are discovered while in the background, you can use local notifications. For details, see background notifications.