Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Practical CoreBluetooth

Avatar for Yoav Schwartz Yoav Schwartz
September 17, 2015

Practical CoreBluetooth

An overview over the CoreBluetooth framework including many practical tips that can help developers.

Avatar for Yoav Schwartz

Yoav Schwartz

September 17, 2015

Other Decks in Programming

Transcript

  1. What is BLE anyways? • Low power - can last

    months or even years on a single battery • Standard - Bluetooth 4.0 • Low cost - small, cheap and simple
  2. • Introduced iOS 5 • Wraps all of the BLE

    protocol into familiar iOS patterns CoreBluetooth?
  3. CBCentralManager • Discovering and managing peripheral connections • Tip #1

    - A manager cannot be used at all until the delegate receives a didUpdateState to .PoweredOn • manager = CBCentralManager(delegate:self, queue:nil, options: nil) • func centralManagerDidUpdateState(central: CBCentralManager!)
  4. Scanning for devices • Discovering and managing peripherals • Tip

    #2 - Keep strong references to discovered peripherals, otherwise the system will throw them away • manager.scanForPeripheralsWithServices([CBUUID], options: nil) • manager.stopScan() • func centralManager(central: CBCentralManager!, didDiscoverPeripheral peripheral: CBPeripheral!, advertisementData: [NSObject : AnyObject]!, RSSI: NSNumber!)
  5. Connecting to a peripheral • Tip #3 - Even though

    the protocol defines a timeout to the connection, apple choose to ignore it and continues indefinitely • Tip #4 - If you don’t keep a strong reference to the peripheral, the OS will automatically assume your’e not interested and drop the connection • manager.connectPeripheral(peri, options: nil) • manager.cancelPeripheralConnection(peripheral) - called both to cancel and disconnect • func centralManager(central: CBCentralManager!, didConnectPeripheral peripheral: CBPeripheral!) • func centralManager(central: CBCentralManager!, didDisconnectPeripheral peripheral: CBPeripheral!, error: NSError!)
  6. Make the peripheral useful • Discovering the services offered •

    Tip #5 - This delegate is called on the same thread as set on the central manager • peripheral.discoverServices([CBUUID]) • func peripheral(peripheral: CBPeripheral!, didDiscoverServices error: NSError!) • peripheral.services
  7. Useful, but we can do better • Discovering and reading

    the characteristics • Tip #6 - Unlike android, apple don’t distinguish between a read and a notification, Both call the didUpdateValueForCharacteritic. • peripheral.discoverCharacteristics(nil, forService: (service as CBService)) • func peripheral(peripheral: CBPeripheral!, didDiscoverCharacteristicsForService service: CBService!, error: NSError!) • peripheral.readValueForCharacteristic(characteristic) • peripheral.setNotifyValue(true, forCharacteristic: characteristic) • func peripheral(peripheral: CBPeripheral!, didUpdateValueForCharacteristic characteristic: CBCharacteristic!, error: NSError!)
  8. Finally, writing something • Writing values to characteristics • peripheral.writeValue(data:

    NSData!, forCharacteristic: CBCharacteristic!, type: CBCharacteristicWriteType) • characteristic.properties - OptionSet type • characteristic.isNotifying • func peripheral(peripheral: CBPeripheral!, didWriteValueForCharacteristic characteristic: CBCharacteristic!, error: NSError!)
  9. Subclassing CBPeripheral??? If only it was only that simple •

    Every operation will always return the basic CBPeripheral held magically somewhere in the CoreBluetooth stack • Composition to the rescue! • Object that is initialised with a CBPeripheral • Used to interact with the peripheral, keep a reference to it and act as it’s delegate
  10. Connecting to the peripheral and the CBPeripheralDelegate • KVO to

    the rescue! • Instead of the didConnect and didDisconnect we observe the peripheral’s state property • We use the object we used in the previous slide as our CBPeripheralDelegate and give it the connection responsibility • Warning! - Since CBPeripheral doesn’t inherit from NSObject, KVO compliance is not guaranteed, however, it works, as this is standard behaviour
  11. Determine proximity Deciding is in range • In the object

    in charge of the peripheral, keep a stack of the time/RSSI of the advertisements • Use the stack to determine proximity. The bigger the RSSI, the closer the device is. • In range is a bit more complicated, I use an average of the RSSI’s weighted by how long ago we got them (Sort of low pass filter) • Many possible implementations, very similar to determining WIFI strength for example • Gotcha! - Connected peripherals do not advertise, you have to call readRSSI manually to get a reading
  12. Now what? • Apple’s CoreBluetooth Programming Guide • WWDC 2013

    session on CoreBluetooth • WWDC 2012 session on CoreBluetooth • Altconf 2015 session on CoreBluetooth
  13. Bonus • The iOS device can also be a peripheral

    itself! This is however too much to cover in a single talk • Even if you have no idea how to get/program a bluetooth chip, you can be a “firmware developer”. Implement any mock device using a second iOS device.