Created
June 4, 2020 15:36
-
-
Save jhays/632dc56fc4684d88406a382bda2a8860 to your computer and use it in GitHub Desktop.
A comparison of reading from a BLE peripheral using the CoreBluetooth standard delegation pattern, and RxBluetoothKit's reactive pattern. Notice the difference in total lines of code to accomplish a single read...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// BluetoothManager.swift | |
// BluetoothExample | |
// | |
// Created by Julian Hays on 5/26/20. | |
// Copyright © 2020 PunchThrough. All rights reserved. | |
// | |
import Foundation | |
import CoreBluetooth | |
import os.log | |
@objc class BluetoothManager: NSObject { | |
public static let shared = BluetoothManager() | |
static let ble_log = OSLog(subsystem: "com.punchthrough.BluetoothExample.BluetoothManager", category: "BLE") | |
private var centralManager: CBCentralManager? = nil | |
private var connectingPeripheral: CBPeripheral? | |
private var service: CBService? = nil | |
private var characteristic: CBCharacteristic? = nil | |
private let serviceUUID = CBUUID(string: "3296991d-cc2b-4b8b-a45d-a87ae695d2f6") | |
private let characteristicUUID = CBUUID(string: "4021c51f-fad4-4e54-84cf-cfaf46fc93c5") | |
override init() { | |
super.init() | |
centralManager = CBCentralManager(delegate: self, queue: nil, options: nil) | |
// For this example, we are assuming the bluetooth state is .poweredOn | |
startScan() | |
} | |
func startScan() { | |
os_log(.info, log: BluetoothManager.ble_log, "start scan") | |
centralManager?.scanForPeripherals(withServices: [serviceUUID], options: nil) | |
} | |
} | |
// MARK: - CBCentralManagerDelegate | |
extension BluetoothManager: CBCentralManagerDelegate { | |
func centralManagerDidUpdateState(_ central: CBCentralManager) { | |
let bluetoothState = "\(central.state)" | |
os_log(.info, log: BluetoothManager.ble_log, "bluetoothState: %@", bluetoothState) | |
} | |
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) { | |
os_log(.info, log: BluetoothManager.ble_log, "peripheral: %@ \nadvertisementData: %@ \nrssi: %@", peripheral, advertisementData, RSSI) | |
central.stopScan() | |
connectingPeripheral = peripheral | |
central.connect(peripheral, options: nil) | |
} | |
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { | |
os_log(.info, log: BluetoothManager.ble_log, "didConnectPeripheral: %@", peripheral) | |
peripheral.delegate = self | |
peripheral.discoverServices([serviceUUID]) | |
} | |
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { | |
os_log(.error, log: BluetoothManager.ble_log, "didFailToConnectPeripheral: %@ \nerror: %@", peripheral, error?.localizedDescription ?? "") | |
} | |
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { | |
os_log(.info, log: BluetoothManager.ble_log, "didDisconnectPeripheral: %@ \nerror: %@", peripheral, error?.localizedDescription ?? "") | |
connectingPeripheral = nil | |
} | |
} | |
// MARK: - CBPeripheralDelegate | |
extension BluetoothManager: CBPeripheralDelegate { | |
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { | |
os_log(.info, log: BluetoothManager.ble_log, "didDiscoverServices: %@ \nerror: %@", peripheral, error?.localizedDescription ?? "") | |
guard let discoveredService = peripheral.services?.first(where: { (discovered) -> Bool in | |
return discovered.uuid.uuidString == serviceUUID.uuidString | |
}) else { | |
os_log(.error, log: BluetoothManager.ble_log, "service not found on peripheral.") | |
return | |
} | |
service = discoveredService | |
peripheral.discoverCharacteristics([characteristicUUID], for: discoveredService) | |
} | |
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { | |
os_log(.info, log: BluetoothManager.ble_log, "didDiscoverCharacteristicsFor: %@ \nerror: %@", service, error?.localizedDescription ?? "") | |
guard let discoveredCharacteristic = service.characteristics?.first(where: { (discovered) -> Bool in | |
return discovered.uuid.uuidString == characteristicUUID.uuidString | |
}) else { | |
os_log(.error, log: BluetoothManager.ble_log, "characteristic not found on service.") | |
return | |
} | |
characteristic = discoveredCharacteristic | |
peripheral.readValue(for: discoveredCharacteristic) | |
} | |
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { | |
os_log(.info, log: BluetoothManager.ble_log, "didUpdateValueFor characteristic") | |
if let value = characteristic.value { | |
var number: UInt8 = 0 | |
value.copyBytes(to:&number, count: MemoryLayout<UInt8>.size) | |
os_log(.info, log: BluetoothManager.ble_log, "Value read: %d", number) | |
} else { | |
os_log(.error, log: BluetoothManager.ble_log, "Error reading value") | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// RxBluetoothManager.swift | |
// BluetoothExample | |
// | |
// Created by Julian Hays on 5/27/20. | |
// Copyright © 2020 PunchThrough. All rights reserved. | |
// | |
import Foundation | |
import CoreBluetooth | |
import RxBluetoothKit | |
import RxSwift | |
import os.log | |
class RxBluetoothManager { | |
public static let shared = RxBluetoothManager() | |
static let rxble_log = OSLog(subsystem: "com.punchthrough.BluetoothExample.RxBluetoothManager", category: "RxBLE") | |
private let centralManager = CentralManager(queue: .main) | |
private let serviceUUID = CBUUID(string: "3296991d-cc2b-4b8b-a45d-a87ae695d2f6") | |
private let characteristicUUID = CBUUID(string: "4021c51f-fad4-4e54-84cf-cfaf46fc93c5") | |
private let disposeBag = DisposeBag() | |
func scanAndConnect() { | |
// For this example, we are assuming the bluetooth state is .poweredOn | |
centralManager.scanForPeripherals(withServices: [serviceUUID]) | |
.take(1) | |
.flatMap { $0.peripheral.establishConnection() } | |
.flatMap { $0.discoverServices([self.serviceUUID]) } | |
.flatMap { Observable.from($0) } | |
.flatMap { $0.discoverCharacteristics([self.characteristicUUID]) } | |
.flatMap { Observable.from($0) } | |
.flatMap { $0.readValue() } | |
.subscribe(onNext: { | |
if let value = $0.value { | |
var number: UInt8 = 0 | |
value.copyBytes(to:&number, count: MemoryLayout<UInt8>.size) | |
os_log(.info, log: RxBluetoothManager.rxble_log, "Value read: %d", number) | |
} else { | |
os_log(.error, log: RxBluetoothManager.rxble_log, "Error reading value") | |
} | |
}) | |
.disposed(by: disposeBag) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment