Bluetooth Best Practices
The Core Bluetooth framework provides classes for communicating with devices that support Bluetooth low energy wireless technology. When developing an app that interacts with a Bluetooth device, remember that Bluetooth shares the device’s radio with other forms of wireless communication, such as Wi-Fi, to transmit signals over the air. Also, interacting with a Bluetooth device doesn’t just use energy on the iOS device. It uses energy on the Bluetooth device too. If you make your iOS app energy efficient, the Bluetooth device will also benefit.
In general, minimize use of the radio whenever possible to reduce impact on other resources and the device’s battery. This can be done by buffering data instead of streaming it, and by batching transactions. The following additional guidelines will help you reduce unnecessary radio use.
Scan for Devices Only When Needed
When you call the scanForPeripheralsWithServices:options:
method of the CBCentralManager
class to discover remote peripherals that are advertising services, the device uses its radio to listen for advertising devices until explicitly told to stop. Unless you need to discover more devices, stop scanning for other devices once you have found one you want to connect to. Use the stopScan
method of the CBCentralManager
class to stop scanning for other devices. See Listing 17-1.
Objective-C
-(void)beginScanningForDevice {
// Create a Core Bluetooth Central Manager object
self.myCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil];
// Scan for peripherals
[self.myCentralManager scanForPeripheralsWithServices:nil options:nil];
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
// Connect to the newly discovered device
// Stop scanning for devices
[self.myCentralManager stopScan];
}
Swift
func beginScanningForDevice() {
// Create a Core Bluetooth Central Manager object
self.myCentralManager = CBCentralManager(delegate: self, queue: nil, options: nil)
// Scan for peripherals
self.myCentralManager.scanForPeripheralsWithServices(nil, options: nil)
}
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [NSObject: AnyObject]!, RSSI: NSNumber!) {
// Connect to the newly discovered device
// Stop scanning for devices
self.myCentralManager.stopScan()
}
Minimize Processing of Duplicate Device Discoveries
Remote peripheral devices may send out multiple advertising packets per second to announce their presence to listening apps. By default, these packets are combined into a single event and delivered to your app once per peripheral. You should avoid changing this behavior—don’t specify the CBCentralManagerScanOptionAllowDuplicatesKey
constant as a scan option when calling the scanForPeripheralsWithServices:options:
method. Doing so results in excess events that can drain battery life.
Only Discover Services and Characteristics You Need
Peripheral devices provide services related to performing specific functions—such as a Bluetooth heart monitor that offers a service for retrieving heart rate information. Services include characteristics, or attributes. For example, the heart rate service may have characteristics that provide specific measurements or data, such as the position of the sensor when a reading was obtained.
A peripheral may have many more services and characteristics than are needed to fulfill a specific use case with your app. Therefore, look for and discover the specific services and characteristics your app needs. You can do this by providing specific UUIDs (represented by CBUUID objects) to the discoverServices:
and discoverCharacteristics:forService:
methods of the CBPeripheral
class, as shown in Listing 17-2 and Listing 17-3.
Objective-C
// Look for services matching a specific set of UUIDs
[peripheral discoverServices:@[firstServiceUUID, secondServiceUUID]];
Swift
// Look for services matching a specific set of UUIDs
peripheral.discoverServices([firstServiceUUID, secondServiceUUID])
Objective-C
// Look for characterstics matching a specific set of UUIDs for a given service
[[peripheral discoverCharacteristics:@[firstCharacteristicUUID, secondCharacteristicUUID]
forService:interestingService]];
Swift
// Look for characterstics matching a specific set of UUIDs for a given service
peripheral.discoverCharacteristics([firstCharacteristicUUID, secondCharacteristicUUID], forService: interestingService)
Request Notifications Rather than Polling for Characteristic Value Changes
In most cases, your app has no way of knowing when a service’s characteristic value will change on a connected device. You could repeatedly query the device (polling) to detect changes, but a more efficient way is to register to receive notifications when changes occur.
Subscribe to the value of a characteristic by passing a value of YES
true
to the setNotifyValue:forCharacteristic:
method of the CBPeripheral
class, as shown in Listing 17-4. Whenever the characteristic’s value changes, the peripheral calls the peripheral:didUpdateValueForCharacteristic:error:
method of its delegate object.
Objective-C
-(void)subscribeToCharacteristic {
// Subscribe to a characteristic value
[self.peripheral setNotifyValue:YES forCharacteristic:interestingCharacteristic];
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
// Process the characteristic value update
}
Swift
func subscribeToCharacteristic() {
// Subscribe to a characteristic value
self.peripheral.setNotifyValue(true, forCharacteristic: interestingCharacteristic)
}
func peripheral(peripheral: CBPeripheral, didUpdateNotificationStateForCharacteristic characteristic: CBCharacteristic, error: NSError! {
// Process the characteristic value update
}
Disconnect from a Device When You No Longer Need It
To prevent your app from needlessly using the device’s radio, disconnect from a peripheral device if a characteristic has stopped providing notifications or if additional data is no longer required. Cancel any notification subscriptions by passing a value of NO
false
to the setNotifyValue:forCharacteristic:
method of the CBPeripheral
class. Then disconnect from the device by calling the cancelPeripheralConnection:
method of the CBCentralManager
class. See Listing 17-5.
Objective-C
// Unsubscribe from a characteristic value
[self.peripheral setNotifyValue:NO forCharacteristic:interestingCharacteristic];
// Disconnect from the device
[self.myCentralManager cancelPeripheralConnection:peripheral];
Swift
// Unsubscribe from a characteristic value
self.peripheral.notifyValue(false, forCharacteristic: interestingCharacteristic)
// Disconnect from the device
self.myCentralManager.cancelPeripheralConnection(peripheral)
Copyright © 2018 Apple Inc. All rights reserved. Terms of Use | Privacy Policy | Updated: 2016-09-13