3

I have the following scenario: iOS app (peripheral) X OSX app (central)

  • I instantiate my peripheral manager with CBPeripheralManagerOptionRestoreIdentifierKey.
  • In my peripheral's didFinishLaunchingWithOptions I send a local notification after getting a peripheral with UIApplicationLaunchOptionsBluetoothPeripheralsKey (don't do anything with it)
  • In my peripheral's willRestoreState I also trigger a notification (don't do anything other than that)

If my peripheral app is still running in the background before it gets killed due to memory pressure, I get messages from the OSX central just fine.

After the iOS app gets killed, when OSX central sends a message, both notifications mentioned above come through on iOS, but the message I was actually expecting doens't.

I've not resintantiated my peripheralManager at any moment, where and how should I do it? I only have one peripheralManager for the entire cycle of my app.

Any suggestions are welcome.

UPDATE:

if do

let options: Dictionary = [CBPeripheralManagerOptionRestoreIdentifierKey: "myId"]
peripheralManager = CBPeripheralManager(delegate: self, queue: nil, options: options)

in willRestoreState, my apps just lose connection

Lee Andrew
  • 798
  • 7
  • 28

1 Answers1

2

Right, after having re-viseted all topics on this matter 100 times I've finally figured it out, here is exactly how it should be implemented:

in AppDelegate's didFinishLaunchingWithOptions:

if let options = launchOptions {
    if let peripheralManagerIdentifiers: NSArray = options[UIApplicationLaunchOptionsBluetoothPeripheralsKey] as? NSArray {

        //Loop through peripheralManagerIdentifiers reinstantiating each of your peripheralManagers
        //CBPeripheralManager(delegate: corebluetooth, queue: nil, options: [CBPeripheralManagerOptionRestoreIdentifierKey: "identifierInArray"])

    }
    else {
        //There are no peripheralManagers to be reinstantiated, instantiate them as you normally would
    }
}
else {
    //There is nothing in launchOptions, instantiate them as you normally would
}

At this point, willRestoreState should start getting called, however, there will be no centrals in your array of centrals if you have one to manage all centrals subscribed to your characteristics. Since all my centrals are always subscribed to all of my characteristics in one single service I have, I simply loop though all subscribedCentrals in any of the characteristics re-adding them to my array of centrals.

Please modify this according to your needs.

In willRestoreState:

var services = dict[CBPeripheralManagerRestoredStateServicesKey] as! [CBMutableService]

if let service = services.first {

    if let characteristic = service.characteristics?.first as? CBMutableCharacteristic {

        for subscribedCentral in characteristic.subscribedCentrals! {
            self.cbCentrals.append(subscribedCentral as! CBCentral)
        }

    }

}

After this you should be ok to call any methods you have prepared to talk to any central, even if you deal with several of them simultaneously.

Good luck!

Lee Andrew
  • 798
  • 7
  • 28
  • Do you need to create/init the CBPeripheralManager (or CBCentralManager) from the AppDelegate? I currently have it in a separate singleton class and it's not working for me. – rosem Mar 31 '16 at 18:03
  • I also have it in a separate class, not kept in a static variable in AppDelegate though, it's an instance variable kept in AppDelegate, instantiated when the app launches, every time I need to access it from another class, I have to get a reference to AppDelegate and access my variable from there. Probably not the best implementation for a singleton but it works, I mite refactor it eventually to use a static variable in AppDelegate instead and access it through a sharedInstance. Basically, I have a similar setup to yours... – Lee Andrew Mar 31 '16 at 18:50
  • You are able to continue scanning for a device with this code when the app is terminated? I can't get it to work so far, it never finds the devices when the app is terminated. Works find when active or in background through. I did not set a custom queue however (using nil) on the Central Manager. I wonder if that is causing the problem as the main queue (default for nil) is gone at that point? – rosem Mar 31 '16 at 19:10