EASession(accessory:forProtocol:) always returns nil — MFI accessory iAP2

EASession(accessory:forProtocol:) always returns nil — MFI accessory iAP2

Platform: iOS 17+ | Hardware: Custom MFI-certified accessory (USB-C, iAP2) | Language: Swift


Problem

We have a custom MFI-certified accessory communicating over USB-C using ExternalAccessory. The app calls EASession(accessory:forProtocol:) after receiving EAAccessoryDidConnect but it always returns nil. We never get past session creation.


What we have verified

We captured a sysdiagnose on-device and analysed the accessoryd-packets log. The full iAP2 handshake completes successfully at the OS level:

  • USB attach succeeds
  • MFI auth certificate is present and Apple-issued
  • Auth challenge and response complete successfully
  • IdentificationInformation is accepted by iOS — protocol string and Team ID are correct
  • EAAccessoryDidConnect fires as expected
  • iOS sends StartExternalAccessoryProtocolSession — the OS-level session is established

So the hardware, MFI auth, protocol string, and Team ID are all correct. Despite this, EASession(accessory:forProtocol:) returns nil in the app.

We also confirmed:

  • Protocol string in UISupportedExternalAccessoryProtocols in Info.plist matches the accessory exactly
  • Protocol string in code matches Info.plist
  • App entitlements are correctly configured
  • EAAccessoryManager.shared().registerForLocalNotifications() is called before connection

Current connection code

@objc private func accessoryDidConnect(_ notification: Notification) { guard let accessory = notification.userInfo?[EAAccessoryKey] as? EAAccessory else { return } DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { self.tryConnectToAccessory() } }

private func tryConnectToAccessory() { DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) { for accessory in EAAccessoryManager.shared().connectedAccessories { let session = EASession(accessory: accessory, forProtocol: "<our-protocol-string>") // session is always nil here } } }


Questions

  1. The packet log shows a ~4 second gap between EAAccessoryDidConnect firing and iOS internally completing session readiness (StartExternalAccessoryProtocolSession). Is there a reliable way to know when iOS

Is it actually ready to grant an EASession, rather than using a fixed delay?

  1. Is there a delegate callback or notification that fires when the accessory protocol session is ready to be opened, rather than relying on EAAccessoryDidConnect + an arbitrary delay?

  2. Are there any known conditions on iOS 17+ under which EASession returns nil even though the iAP2 handshake completed successfully at the OS level?

  3. Is retrying EASession after a nil result a supported pattern, or does a nil result mean the session will never succeed for that connection?

Any guidance appreciated.

EASession(accessory:forProtocol:) always returns nil — MFI accessory iAP2
 
 
Q