2

I created an app which is a ble peripheral running on my iPhone. This peripheral is advertising and integrates services and characteristics. With nrfConnect or other scan ble apps I can connect and see all created services/characteristics as long as my app is in foreground. In order to have the background mode enabled I followed the official documentation : https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html

Today when I kill manually the app the background mode works and I can see my peripheral (without his local name because iOS remove it, but I can recognize the mac address given by nrfConnect). My issue is when I try to connect to the peripheral when the app is killed and in background mode. All services are missing!! The Apple's documentation explains that we can restore services in background using the willRestoreState delegate method and set CBPeripheralManagerRestoredStateServicesKey when initialising the CBPeripheralManager. I did all of these steps but services are not restored... If someone has an idea?

Here is my complete code of my AppDelegate file :

import UIKit
import CoreBluetooth

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CBPeripheralManagerDelegate {

    var window: UIWindow?
    var peripheralManager: CBPeripheralManager!
    var deviceName = "DIGITALBLEND"
    var dataToBeAdvertised: [String: [CBUUID]]!

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        self.window = UIWindow(frame: UIScreen.main.bounds)
        self.window?.backgroundColor = UIColor.white
        
        UIView.transition(with: self.window!, duration: 0.5, options: UIView.AnimationOptions.transitionCrossDissolve, animations: {
            self.window?.rootViewController = ViewController()
            self.window?.makeKeyAndVisible()
        }, completion: nil)
        
        let optionsPeripheral = [
            CBPeripheralManagerOptionRestoreIdentifierKey: self.deviceName,
            CBPeripheralManagerRestoredStateServicesKey: [
                CBUUID(string: "1ABB0000-542A-3BA1-C243-6F5AAF168DB7"),
                CBUUID(string: "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"),
                CBUUID(string: "0xFE59"),
            ],
            ] as [String : Any]
        
        self.peripheralManager = CBPeripheralManager(delegate: self, queue: nil, options: optionsPeripheral)
        
        
        return true
    }
    
    // MARK: Peripheral Manager Functions
    
    func startAdvertising() {
        
        //Start advertising
        let advertisementData = [
            CBAdvertisementDataLocalNameKey: self.deviceName,
        ]
        
        if self.peripheralManager.isAdvertising == false {
            self.peripheralManager.startAdvertising(advertisementData)
        }
        
    }
    
    func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?) {
        
        if peripheral.isAdvertising{
            print("My Device Started Advertising")
        }
        
    }
    
    
    func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
        
        if peripheral.state == .poweredOn {
            
            //Add services
            self.createServices()
            
        } else {
            print("Bluetooth is not active")
        }
    }
    
    func createServices() {
        
        //Primary Service
        let primaryServiceUUID = CBUUID(string: "1ABB0000-542A-3BA1-C243-6F5AAF168DB7")
        let primaryService = CBMutableService(type: primaryServiceUUID, primary: true)
        
        //Nordic UARD Service
        let nusUUID = CBUUID(string: "6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
        let nusService = CBMutableService(type: nusUUID, primary: true)
        
        //Secure DFU Service
        let dfuUUID = CBUUID(string: "0xFE59")
        let dfuService = CBMutableService(type: dfuUUID, primary: true)
        
        //Create characteristics
        self.createCharacteristic_PRIMARY(service: primaryService)
        self.createCharacteristic_NUS(service: nusService)
        self.createCharacteristic_DFU(service: dfuService)
        
    }
    
    func createCharacteristic_PRIMARY(service : CBMutableService) {
        
        let permissions: CBAttributePermissions = [.readable, .writeable]
        
        //Characteristic 1
        let characteristicUUID_1 = CBUUID(string: "1ABB0001-542A-3BA1-C243-6F5AAF168DB7")
        let properties_1: CBCharacteristicProperties = [.read, .write]
        let characteristic_1 = CBMutableCharacteristic(
            type: characteristicUUID_1,
            properties: properties_1,
            value: nil,
            permissions: permissions)
        
        //Characteristic 2
        let characteristicUUID_2 = CBUUID(string: "1ABB0002-542A-3BA1-C243-6F5AAF168DB7")
        let properties_2: CBCharacteristicProperties = [.notify, .read, .write]
        let characteristic_2 = CBMutableCharacteristic(
            type: characteristicUUID_2,
            properties: properties_2,
            value: nil,
            permissions: permissions)

        //Add characteristic to service
        service.characteristics = [characteristic_1, characteristic_2]
        
        self.peripheralManager.add(service)
    }
    
    func createCharacteristic_NUS(service : CBMutableService) {
        
        let permissions: CBAttributePermissions = [.readable, .writeable]
        
        //Characteristic 1 - RX
        let characteristicUUID_1 = CBUUID(string: "6E400002-B5A3-F393-E0A9-E50E24DCCA9E")
        let properties_1: CBCharacteristicProperties = [.write]
        let characteristic_1 = CBMutableCharacteristic(
            type: characteristicUUID_1,
            properties: properties_1,
            value: nil,
            permissions: permissions)
        
        //Characteristic 2 - TX
        let characteristicUUID_2 = CBUUID(string: "6E400003-B5A3-F393-E0A9-E50E24DCCA9E")
        let properties_2: CBCharacteristicProperties = [.notify]
        let characteristic_2 = CBMutableCharacteristic(
            type: characteristicUUID_2,
            properties: properties_2,
            value: nil,
            permissions: permissions)
        
        //Add characteristic to service
        service.characteristics = [characteristic_1, characteristic_2]
        
        self.peripheralManager.add(service)
    }
    
    func createCharacteristic_DFU(service : CBMutableService) {
        
        let permissions: CBAttributePermissions = [.readable, .writeable]
        
        //Characteristic 1 - Buttonless DFU
        let characteristicUUID_1 = CBUUID(string: "8EC90003-F315-4F60-9FB8-838830DAEA50")
        let properties_1: CBCharacteristicProperties = [.indicate, .write]
        let characteristic_1 = CBMutableCharacteristic(
            type: characteristicUUID_1,
            properties: properties_1,
            value: nil,
            permissions: permissions)
        
        //Add characteristic to service
        service.characteristics = [characteristic_1]
        
        self.peripheralManager.add(service)
    }
    
    func peripheralManager(_ peripheral: CBPeripheralManager, didAdd service: CBService, error: Error?) {
        
        if error == nil{
            print("success publishing the service")
            self.startAdvertising()
        } else {
            print(error?.localizedDescription ?? "error publishing service")
        }
    }
    
    // CENTRAL read from TX
    func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveRead request: CBATTRequest) {
        print("salut")
    }
    
    // CENTRAL read from RX
    func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveWrite requests: [CBATTRequest]) {
        
    }
    
    func peripheralManager(_ peripheral: CBPeripheralManager, willRestoreState dict: [String : Any]) {
        
        self.peripheralManager = peripheral
        
        //  Note: restoring CBPeripheralManager services only works on iOS 11.2+
        guard let services = dict[CBPeripheralManagerRestoredStateServicesKey] as? [CBMutableService] else {
            return
        }

        for service in services {
            self.peripheralManager.add(service)
        }
        
    }
}
Silvering
  • 756
  • 1
  • 6
  • 33

0 Answers0