-->

How long is a CBPeripheral's stored UUID valid

2020-07-25 10:37发布

问题:

I've been playing with Corebluetooth and I've learnt that besides going through the tedious process of scanning for a peripheral every time I want to connect, I can also store the peripheral's UUID and use it with retrievePeripheralsWithIdentifiers and connectPeripheral for further reconnections.

Turns out that it only works for a certain amount of time, apparently the peripheral has its UUID updated, therefore the stored one can be considered expired.

I haven't been able to find any consistent documentation on this, so I'm not sure how long it lasts for.

Is there any way around this in order to allow later reconnections faster than scanning for peripherals all over again?

回答1:

In my opinion, directly holding onto the CBPeripheral objects in an NSArray or NSDictionary is the easiest way. Connect and disconnect as many times as you would like (without scanning each time) to a CBPeripheral once it is retained. The only thing you have to be mindful of is the CBCentralManager's state. You will receive state changes by implementing the CBCentralManagerDelegate centralManagerDidUpdateState: method. If the state changes to anything except CBCentralManagerStatePoweredOn then you need to get rid of all of your retained CBPeripheral objects and do another scan once the state turns back on.

According to the apple docs:

If the state moves below CBCentralManagerStatePoweredOff, all CBPeripheral objects obtained from this central manager become invalid and must be retrieved or discovered again.

However, I would suggest invalidating/releasing all of your CBPeripheral objects if the state moves below CBCentralManagerStatePoweredOn. It is no secret that CoreBluetooth is a little buggy and this has seemed to help me avoid "invalid CBPeripheral" warnings in the past.

If you would like to identify a specific CBPeripheral after the app is reset or the device is shut down or even a network settings reset (cache reset) then you will need to have a custom implementation that uniquely identifies another device not based on anything CoreBluetooth offers you for free.

Here is how I do it in one of my apps:

  1. Alloc/Init a NSUUID object the first time the app is launched and save it in NSUserDefaults as a NSString. Think of this UUID as a pseudo-MAC address for your app. This UUID will remain constant for the lifetime of the app.
  2. centralManager discovers a CBPeripheral, connects, and then reads the value for a specific characteristic
  3. CBPeripheral device responds to the request with its non-bluetooth-related UUID from step 1. I also include a whole bunch of user provided information in this step along with the UUID.
  4. centralManager saves this UUID (and any other information you include) using Core Data or NSUserDefaults if it hasn't already.
  5. Repeat steps 2-4 for all newly discovered CBPeripherals.

Now, whenever centralManager discovers a CBPeripheral it can check its local database of UUIDs and determine which device is related to this CBPeripheral without a doubt.

See Paulw11's answer for how reconnect while in the background. Note that if your app has been quit by the user (swipe the app's preview up after pressing the home button twice), any long term "connects" will be cancelled even if the app is restarted.