Writing to L2Cap socket when app runs in background

TLDR; Why is my app crashing when I write to a L2Cap socket when the app is running in the background(i.e phone is locked)?

I am currently working on an application that is required to write to L2Cap sockets while the iPhone is locked. The phone acts as a BLE peripheral and accepts L2Cap connections from an external device.

While the app runs in the foreground, everything works as expected; i.e the external device connects to the app on a L2Cap socket and the app writes to the sockets and closes the socket.

While the app run in the background, the external device successfully connects and opens a connection, however the app crashes when attempting to write to the socket. The only error message received is:

Terminated due to signal 13

I am using CBPeripheralManager to publish the L2Cap socket and CBPeripheralManagerDelegate to assign streams when a device connects. Then I use the StreamDelegate to wait until it's possible to write. See the following code snippet:

class BleController: CBPeripheralManagerDelegate, StreamDelegate {

  var peripheralManager: CBPeripheralManager = 
    CBPeripheralManager(delegate: self, queue: nil, 
    options: [CBPeripheralManagerOptionRestoreIdentifierKey:
    "<identifier_key>"])

  var outPutStream:OutputStream!, inPutStream:InputStream!

  func peripheralManager(_ peripheral: CBPeripheralManager,
                           didOpen channel: CBL2CAPChannel?,
                           error: Error?) {
      self.outPutStream = channel.outputStream
      self.outPutStream.delegate = self
      self.outPutStream.schedule(in: .main, forMode: .default)
      self.outPutStream.open()

      self.inPutStream = channel.inputStream
      self.inPutStream.delegate = self
      self.inPutStream.schedule(in: .main, forMode: .default)
      self.inPutStream.open()
  }

  func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
    switch eventCode {
      case Stream.Event.hasSpaceAvailable:
        /* Excluding creation of data object */
        sendL2CAPInfo(aStream as! OutputStream, data)
    }
  }

  func sendL2CAPInfo(_ outStream: OutputStream, _ data: Data) {
    // Crashes on this line when running in background
    let bytesWritten = data.withUnsafeBytes {outStream.write($0, 
                         maxLength: data.count)}
  }

  func peripheralManager(_ peripheral: CBPeripheralManager,
      willRestoreState dict: [String : Any]) {
    /* Empty function */
  }
}

As far as Signing and Capabilities go I have enabled Uses Bluetooth LE accessories, Acts as a Bluetooth LE accessory and Background processing.

I have understood it as the peripheral manager can handle background events by using the restore state option. Therefore, I have defined the specified the restore identifier key in the creation of the peripheral manager and defined required function (although this function is empty). However, I have noticed from logs that the restore state function is not called when a connection event happens and the app is running in the background. The only time the restore function is called is upon startup of the app.

Does anyone have any knowledge for why the app crashes when writing to the L2Cap socket when the app is running in the background?

Thank you in advance.

Hi @adum, I'm currently in the same situation as you described in your post. Did you manage to find a solution?

Cheers

Does it matter whether the peripheral hosts the service or the iPhone?

Writing to L2Cap socket when app runs in background
 
 
Q