Post

Replies

Boosts

Views

Activity

EAAccessory support over Lighting Audio Module in iOS 11 is unstable
I have noticed various strange behaviours with the EAAccessory interface on iOS 11 (Betas 5 and 6 **update and now in the full production version 11.0.2 **)). I wonder if anyone else has had these issues? Everything worked OK on iOS 10.I am communicating with an accessory over a lightning socket (via a LAM), and get the following behaviour:1. Connecting to a device, EAAccessoryManager returns a connected EAAccessory (an EASession can be established, and data received, although this doesn't always happen), but then immediately disconnects from the EAAccessory, and then returns another connected EAAccessory.2. After opening an EASession on this new EAAccessory, no communications to the device is possible (sending data over the OutputStream doesn't result in the data getting to the accessory)3. On switching away from the app and back again, either:a) the app crashesorb) the input stream reports endEncountered and the output stream just seems to stop working, it never reports hasSpaceAvailable again.Some simplified code which illustrates this problem is below:import UIKitimport ExternalAccessoryclass ViewController: UIViewController, StreamDelegate { var connectedAccessory: EAAccessory? var eaSession: EASession? let supportedProtocolName = "My.Supported.Protocol" @IBOutlet weak var logTextView: UITextView! @IBOutlet weak var sendButton: UIButton! override func viewDidLoad() { super.viewDidLoad() log("loaded") // Do any additional setup after loading the view, typically from a nib. NotificationCenter.default.addObserver( forName: NSNotification.Name.EAAccessoryDidConnect, object: nil, queue: nil, using: accessoryConnected) NotificationCenter.default.addObserver( forName: NSNotification.Name.EAAccessoryDidDisconnect, object: nil, queue: nil, using: accessoryDisconnected) EAAccessoryManager.shared().registerForLocalNotifications() // Maybe we're already connected if let connectedAccessory = EAAccessoryManager.shared().connectedAccessories.first { self.connectedAccessory = connectedAccessory openSession() } } private func accessoryConnected(_ notification: Notification) { log("accessoryConnected") for accessory in EAAccessoryManager.shared().connectedAccessories { log("accessory: \(accessory)") log("") } // Connect to the first one (only expect there to be one for this test) self.connectedAccessory = EAAccessoryManager.shared().connectedAccessories.first openSession() } private func openSession() { guard let connectedAccessory = self.connectedAccessory else { return } self.eaSession = EASession( accessory: connectedAccessory, forProtocol: self.supportedProtocolName) openStream(eaSession?.inputStream) openStream(eaSession?.outputStream) } private func openStream(_ stream: Stream?) { stream?.delegate = self stream?.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode) stream?.open() } public func stream(_ stream: Stream, handle streamEvent: Stream.Event) { switch streamEvent { case Stream.Event.openCompleted: log("\(stream) openCompleted") if (eaSession?.inputStream?.streamStatus == Stream.Status.open && eaSession?.outputStream?.streamStatus == Stream.Status.open) { log("both input and output are open") } case Stream.Event.hasBytesAvailable: log("hasBytesAvailable") readAll() case Stream.Event.hasSpaceAvailable: log("hasSpaceAvailable") case Stream.Event.errorOccurred: log("\(stream) errorOccurred") closeSession() case Stream.Event.endEncountered: log("\(stream) endEncountered") closeSession() default: log("\(stream) default") closeSession() } } private func readAll() { let bufferSize = 128 var numberOfBytesRead = 0 repeat { var buffer = [UInt8](repeating: 0, count: bufferSize) numberOfBytesRead = eaSession!.inputStream!.read(&buffer, maxLength: buffer.count) if (numberOfBytesRead > 0) { log("read:\(buffer)") } } while (numberOfBytesRead == 128) } @IBAction func sendDataButtonPressed(_ sender: UIButton) { sendData() } private func sendData() { let data: [UInt8] = [1, 0, 0, 0, 16, 0, 0, 0, 0, 3] log("Sending: \(data)") self.eaSession?.outputStream?.write(data, maxLength: data.count) } private func closeSession() { closeStream(eaSession?.inputStream) closeStream(eaSession?.outputStream) eaSession = nil } private func closeStream(_ stream: Stream?) { stream?.close() stream?.remove(from: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode) stream?.delegate = nil } private func accessoryDisconnected(_ notification: Notification) { log("accessoryDisconnected") for accessory in EAAccessoryManager.shared().connectedAccessories { log("accessory: \(accessory)") log("") } guard let accessory = notification.userInfo?[EAAccessoryKey] as? EAAccessory else { return } log("disconnected accessory: \(accessory)") log("") closeSession() } private func log(_ msg: String) { self.logTextView.insertText("\(msg)\n") scrollLogToEnd() } private func scrollLogToEnd() { let stringLength = self.logTextView.text.characters.count self.logTextView.scrollRangeToVisible(NSMakeRange(stringLength - 1, 0)) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. }}
9
0
15k
Aug ’17