Bluetooth and Location Services Permission Tips
An iBeacon app relies on an active Bluetooth connection to detect the beacons around it. Without bluetooth, the app wouldn’t know when to trigger certain location related features. Handling bluetooth settings and permissions on the iPhone can sometimes be tricky. If you don’t request permissions correct and check the phone’s status in the right order, development and testing can become more of a frustration than it needs to be. Here’s how each step of the process should be handled:
1 — Is the device capable of Bluetooth Low Energy (BLE)?
iBeacons run on the BLE frequency so it’s important that the device is BLE capable. BLE is available on the iPhone 4S & up, on any iPad mini or Air, and on iPad 3rd & 4th generation devices. Check for BLE capability isn’t necessary if you setup your app to require Bluetooth low energy.
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>bluetooth-le</string>
</array>
Adding the bluetooth-le
key to the UIRequiredDeviceCapabilities
array in your app’s plist restricts non-BLE capable devices from downloading your app. We restricted downloads of app to only BLE enabled devices since the app relies on iBeacon tech to function. Some apps may not revolve around iBeacon tech, in that case checking for BLE capability is an absolute necessity.
let opts = [CBCentralManagerOptionShowPowerAlertKey: false]let manager = CBCentralManager(delegate: self,
queue: nil,
options: opts)func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state != .unsupported {
//device supports BLE
}
}
After the central manager is created it calls centralManagerDidUpdateState:
on it’s delegate. As long as the central manager’s state isn’t .unsupported
BLE is supported and available to use on the device. Note the value of CBCentralManagerOptionShowPowerAlertKey
, setting it’s value to 0
ensures the user won’t be prompted with an alert. I’ll talk about presenting that alert and requesting Bluetooth permissions later. Once you know BLE is available you can continue to step 2, or disable/hide beacon related UI features if the check fails.
2 — Does the app have permission to access Location Services?
if CLLocationManager.authorizationStatus() == .NotDetermined {
//location access not authorized
}
It’s just one line of code to check the Location Services authorization status. .NotDetermined
should be the status for your app if it hasn’t requested permission. There are two levels of location access “Always” and “WhenInUse”, getting permission starts with requesting access from the user.
let manager = CLLocationManager()
manager.delegate = selfmanager.requestAlwaysAuthorization()
//OR
manager.requestWhenInUseAuthorization()
To function properly, both of these access levels require a permissions description be present in your app’s Info.plist file.
<key>NSLocationWhenInUseUsageDescription</key>
<string>...Detailed reason...</string><key>NSLocationAlwaysUsageDescription</key>
<string>...Detailed reason...</string>
iOS 8 and up require these descriptions. If the description is not present in the plisy the app will fail to prompt the user for access to Location Services. You’ll have to request for “Always” access, to be notified of iBeacon events when the app isn’t open or in the background.
If you only need iBeacon monitoring when your app is open, request “WhenInUse” access. “Always” access can scare some users. Users may deny access without realizing the implications. To undo their mistake they’ll have to go into Settings on their iPhone to re-enable access. If you need to do this, the code below will make navigating to your app’s settings page a simple task for the user.
if let url = URL(string: UIApplicationOpenSettingsURLString){
UIApplication.shared.open(settingsURL, options:[:])
}
Forcing a user to leave your app to take an action is never a good idea. To avoid permission denials make sure the description you put into the Info.plist is very descriptive. Detail how the app will use their location data and why it’s needed. It’s even better to have an in-app screen explaining the permission need. This screen acts as a request “Buffer” dialog. It provides a way for the user to trigger the permission request on their own. User initiated permission requests generally run a much lower chance of denial. Since the user initiates the request, the appearance of the system request is not a surprise and they’ve already decided to allow access before it appears.
Allowing the user a denial option on the “Buffer” dialog is can help to avoid unnecessary denials. With a deny option you can avoid showing the system level request to users not ready to allow the permission. Giving those users a way to trigger the request again from inside the app ensures only users ready to allow location access will be presented with a system level permission dialog.
3 — Are Location Services On?
switch CLLocationManager.authorizationStatus() {
case .AuthorizedAlways, .AuthorizedWhenInUse:
// locations services are on
case .NotDetermined:
// still need to request access
case .Restricted, .Denied:
// locations services off or denied
You can tell if Location Services are on after your app has requested access. If they are off however there is no easy way to turn them back on for the user. They must manually go into their settings and toggle the global location services switch. You can use the settings url code mentioned earlier to take the user directly to the Settings app. If your app supports iOS earlier than 8, that code will not work. Your best bet on iOS 7 and below is to pop up a dialog with screen by screen “directions” to the global location services switch. Including an image of the screen they need to find can be helpful.
4 — Is Bluetooth on?
let opts = [CBCentralManagerOptionShowPowerAlertKey: true]let manager = CBCentralManager(delegate: self,
queue: nil,
options: opts)
This is pretty straight forward, without bluetooth being on the phone can’t detect iBeacons. If bluetooth is off this code will pop up a dialog prompting the user to turn on Bluetooth so the app can function. If the app is not open there is no way to notify the user that something is wrong, which is where GPS comes in. An app with GPS integrated can deal with a user that has bluetooth off but has allowed location services permissions. The app will receive a GPS notification when the user enters the larger region surrounding the iBeacon. You can then check the phone’s bluetooth status and send a notification to the user’s lock screen if bluetooth is off.