-
Notifications
You must be signed in to change notification settings - Fork 372
3. Scanning peripherals
To start any interaction with bluetooth devices, you have to scan some of them first. So - get ready!
manager.scanForPeripherals(withServices: serviceIds)
.subscribe(onNext: { scannedPeripheral in
let advertisementData = scannedPeripheral.advertisementData
})
This is the simplest version of this operation. After subscribing to the observable, the scan is performed infinitely. What you receive from method is ScannedPeripheral
instance, that provides access to following information:
- Peripheral: an object that you can use to perform actions like connecting, discovering services etc.
- AdvertisementData: a strongly-typed wrapper around CBPeripheral advertisement data dictionary. Thanks to it, you no longer have to worry about all of the keys needed to pull out information.
- RSSI
Scanning operation is not cancelled by default. It's the user's responsibility to perform that when scanning in not needed anymore. The easiest solutions is just to dispose scanning:
let disposable = centralManager.scanForPeripherals(withServices: nil)
.subscribe(onNext: { print("Peripheral scaned \($0)") })
// after some time
disposable.dispose()
Here come other possibilities, thanks to awesome RxSwift operators:
manager.scanForPeripherals(withServices: [serviceIds]).take(1)
//Doing this, after first received result, scan is immediately cancelled.
Ok, that's fun, but what if you also want to apply timeout policy? That's also easy to do:
manager.scanForPeripherals(withServices: [serviceIds]).timeout(3.0, timerScheduler)
As you can see: thanks to all available RxSwift operators, you might create really interesting and complex usage scenarios in a simple way like for example retrying scans, if you receive timeout.
As describe in Manager State, in order to perform work with bluetooth, your manager should be in .poweredOn state.
Let's see how it looks with scanning:
manager.observeState()
.startWith(manager.state)
.filter { $0 == .poweredOn }
.timeout(3.0, scheduler)
.take(1)
.flatMap { _ in manager.scanForPeripherals(withServices: [serviceId]) }
Firstly, use CentralManager.state as a start value, next filter .poweredOn from states stream. Like above, we want to apply timeout policy to state changes. Also, we use take to be sure, that after getting .poweredOn state, nothing else ever will be emitted by the observable.
In the last flatMap operation, the bluetooth is ready to perform further operations.
Note: Be aware that you can only have one scanning at a time. If you do scanForPeripherals
while different scanning is in progress , you will receive .scanInProgress error.