user3838337
user3838337

Reputation: 41

WillRestoreState not called when app killed by the system

Im trying to create an application which connects to a BP cuff. I want to enable state restoration in the app so that even if the app is killed by the system the app can still be invoked when the BP cuff is available and transmitting. Here are some of the things I have tried so far.

1) Adding a resource identifier to centralManager init and assigning a background serial queue to it

var ble_dispatchQueue = DispatchQueue(label: "com.xyz.ios.ble")
        let opts = [CBCentralManagerOptionShowPowerAlertKey : true,    CBCentralManagerOptionRestoreIdentifierKey:
            "ios.xyz.ble.peripheral.identifier"] as [String : Any]

        self.centralManager = CBCentralManager(delegate : self, queue : ble_dispatchQueue, options : opts)

2) implementing willRestoreState and centralManagerDidUpdateState

   func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) {

    print("will restore state called")
    if let peripheralsObject = dict[CBCentralManagerRestoredStatePeripheralsKey] {
        // 2
        let peripherals = peripheralsObject as! Array<CBPeripheral>
        // 3
        if peripherals.count > 0 {
            // 4
            self.peripheralDevice = peripherals[0]
            // 5
            self.peripheralDevice?.delegate = self
        }
    }
}

centralManagerDidUpdateState :

func centralManagerDidUpdateState(_ central: CBCentralManager) {

    if central.state != .poweredOn {
        self.peripheralDevice = nil
        return
    }
    startScan()

    // 1

    guard let peripheral = self.peripheralDevice else {
        return
    }
    // 2
    guard peripheral.state == .connected else {
        return
    }
    // 3
    guard let peripheralServices = peripheral.services else {
        return
    }
    // 4
    serviceUUID = deviceParameters.deviceTypeUUIDs![0]

    if let serviceIndex = peripheralServices.index(where: {$0.uuid == serviceUUID}) {
        let ANDService = peripheralServices[serviceIndex]
        let characteristicUUIDs = deviceParameters.deviceCharacteristicUUIDs
        if let cUUIDs = characteristicUUIDs, let characteristics = ANDService.characteristics {
            // 6
            for i in 0..<cUUIDs.count {
                if let characteristicIndex = characteristics.index(where : {$0.uuid == cUUIDs[i]}) {
                    let characteristic = characteristics[characteristicIndex]
                    // 7
                    if !characteristic.isNotifying {
                        peripheral.setNotifyValue(true, for: characteristic)
                    } else {
                        peripheral.readValue(for: characteristic)
                    }
                } else {
                    // 8
                    peripheral.discoverCharacteristics(characteristicUUIDs, for: ANDService)
                }
            }
        }
    } else {
        // 5
        peripheral.discoverServices([serviceUUID])
    }

}

The way Im trying to test it is by calling :-

kill(getpid(), SIGKILL);

to simulate process killing by the system. I'm not fiddling with bluetooth state / airplane mode or phone reboot. Im initializing my centralManager inside didLaunchWithOptions I have breakpoints at didLaunchWithOptions which gets called everytime the BP cuff is ready to connect and at willRestoreState which never gets called.

Can someone please suggest what else I can do to invoke willRestoreState?

Upvotes: 2

Views: 1936

Answers (1)

Lee Irvine
Lee Irvine

Reputation: 3347

You need to add a restoration id to your CBCentralManager or the delegate method is never called.

let options = [CBCentralManagerOptionRestoreIdentifierKey: "my-central"]
self.centralManager = CBCentralManager(delegate: self, queue: nil, options: options)

Once you've done that willRestoreState is always called when the CBCentralManager is instantiated.

Also, make sure you have UIBackgroundModes (Array) with 'bluetooth-central' as an item in your Info.plist.

Upvotes: 4

Related Questions