Ranging beacons works always when the app is running, either in the foreground or in the background. However, as soon as the user navigates away from the app or locks the screen, iOS will suspend the app. At this point, ranging stops working until the app is woken up again—which can happen for numerous reasons, e.g.:
- the most obvious—the user opens the app again,
- you're doing monitoring and an enter/exit event comes, waking the app into the background for a few seconds so that it can handle the event,
- you're using background app refresh and iOS wakes the app into the background to allow it to fetch fresh content,
- etc.
In other words, ranging works just fine in the background, but iOS apps simply aren't given the luxury of running in the background for extended periods of time.
Note that this "ranging works in the background" is different from what most people and resources call "monitoring working in the background". When you start monitoring for beacons, it's the iOS itself that performs the duty, not your app. As a result, even if the app gets suspended or terminated, iOS itself still monitors for beacons. If an enter/exit event happens, iOS will then launch your app to handle the event. Because of that, for long-term beacon detection, monitoring is the recommended way.
To be strict, we should be saying that "ranging works when the app is running (doesn't matter whether in the foreground or the background)" and "monitoring works even if the app is not running".
Short-term background ranging
It's perfectly fine and "legal" to perform short-term background ranging, within the regular background execution capabilities of an iOS app. For example:
- You can use the fact that iOS wakes/launches your app into the background for a few seconds to handle monitoring enter/exit events, and use those few seconds to range for beacons.
- You can start a background execution task to extend the time your app can spend in the background. The empirical limit as of iOS 9 seems to be 3 minutes, but you should use the backgroundTimeRemaining property to know for sure how much time your app has in the background before iOS force-terminates it. You can use all this time in the background to perform ranging.
Imagine for example that you enter a venue, and monitoring triggers an enter event. iOS wakes your app into the background to handle the event, but only gives it a few seconds to do that. The app can then start a background task to extend this time, and start ranging to determine whether the user is moving further into the venue (getting closer to the beacon), or just peeked inside it and immediately leaves. Once you establish that, perform an appropriate action and finish the background task, so that iOS puts the app back to sleep and doesn't forcefully terminate it.
Continuous background ranging
If short-term background ranging is not enough, you need to find a way to keep your app running in the background longer by using Background Modes. However, keep in mind that the use of Background Modes is heavily regulated by Apple! They only accept apps using Background Modes when it's justified—e.g., an app using the "audio" background mode needs to be playing music in the background, etc.
The only Background Mode which remotely makes sense in the context of beacons is the "location" background mode. Even then though, there must be clear value for the end user coming from the use of background ranging, value that can't be fulfilled at all with monitoring. You’ll also have to lay this value out in the review process. Users should also be provided with an easy way to opt-out of this kind of service.
If you’re planning to use the "location" background mode to do long-term ranging without a major user benefit (for example just to track user’s movements for your analytics—i.e., you're the beneficiary, not the user), you will most certainly have your app rejected.
Also, keep in mind the power consumption and performance implications of having your app continuously running in the background with ranging enabled (which keeps the radio going). Nobody wants their app uninstalled because users found out it eats up their battery and slows their device down. For the "location" background mode, Apple requires you to add a boilerplate "Continued use of GPS running in the background can dramatically decrease battery life." line to your app description.
I'm aware of the downsides and the risk of rejection from the App Store, how can I do it anyway?
If you're sure you need persistent background ranging for beacons, you'll need to activate the Background Modes capability for your application—specifically, the Location Updates mode.
Note that for startRangingBeaconsInRegion to work in the background you'll also need to start Standard Location Updates via CLLocationManager's startUpdatingLocation (meaning you need both a CLLocationManager and an ESTBeaconManager in your app).
Note: In iOS 9, you also need to set the allowsBackgroundLocationUpdates property of your CLLocationManager to true.
Note: Even with background location updates running, iOS can still suspend the app if it doesn't detect any changes in the location. (Quote from Apple: "Enabling this mode does not prevent the system from suspending the app, but it does tell the system that it should wake up the app whenever there is new location data to deliver.")
Does it work on Android, too?
Unlike iOS, Android doesn't restrict background processing. We still recommend against running ranging in the background for the very same reasons—battery consumption, performance, and privacy. If you're absolutely convinced you need it to provide the best user experience to the user of your app, you can simply start ranging, and it'll continue even if the user leaves the app.