iosswiftcore-bluetoothios-bluetoothcbcentralmanager

Scan for peripherals with services returns nothing


I'm trying to scan for a specific device by it's service uuid - in this case JBL speaker, in future cases, I would like to scan for devices inside a car. At first, I scanned for nearby peripherals with nil.

self.centralManager?.scanForPeripherals(withServices: nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey:true])

Once I found my speaker (this is the data I get):

peripheral identifier =  0BD95D98-D979-67DA-F3AA-C6C03781E70B
discovered peripheral =  <CBPeripheral: 0x283ed4000, identifier = 0BD95D98-D979-67DA-F3AA-C6C03781E70B, name = JBL Flip 4, state = disconnected>
advertisement data =  ["kCBAdvDataRxSecondaryPHY": 0, "kCBAdvDataTimestamp": 643124133.584141, "kCBAdvDataIsConnectable": 1, "kCBAdvDataManufacturerData": <5700d11e 0100ff58>, "kCBAdvDataRxPrimaryPHY": 0, "kCBAdvDataLocalName": JBL Flip 4]
kCBAdvDataManufacturerData =  {length = 8, bytes = 0x5700d11e0100ff58}

I connected to the speaker, and when I got the didConnect callback I called for discover services:

func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        
        self.connectedPeripheral = peripheral
        peripheral.delegate = self
        
        peripheral.discoverServices(nil)
}

When didDiscoverServices services returned I saw the following output:

services =  Optional([<CBService: 0x281adc700, isPrimary = YES, UUID = 65786365-6C70-6F69-6E74-2E636F6D0000>, <CBService: 0x281adcb40, isPrimary = YES, UUID = FE8F>])

At this point, I wanted to use the service uuids that I got, and to scan for the JBL speaker. So instead of called for scanForPeripherals with nil, I used an array with the services like this:

self.centralManager?.scanForPeripherals(withServices: [CBUUID(string: "FE8F"), CBUUID(string: "65786365-6C70-6F69-6E74-2E636F6D0000")], options: [CBCentralManagerScanOptionAllowDuplicatesKey:true])

Then I relaunched the app, but this time I didn't find any device. Why is this so?


Solution

  • See the doc of scanForPeripherals(withServices:options:):

    You can provide an array of CBUUID objects — representing service UUIDs — in the serviceUUIDs parameter. When you do, the central manager returns only peripherals that advertise the services you specify

    The service you got 65786365-6C70-6F69-6E74-2E636F6D0000, you got it AFTER you made before a connection to it (didConnect), and after "scanning more infos on the device" (discoverServices).
    But it was not advertising it, it was not telling everyone that it has a service with that UUID. It keeps it secret. So you can't scan for it.