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)
}
}
}