Contents

Accessory features

Declare and handle the features that carry data between your accessory and your app.

Overview

With the exception of Wi-Fi network sharing, every scenario Accessory Transport Extension supports for moving data between a connected accessory and an iPhone relies on the feature model. You implement an AccessoryDataProvider extension that declares the features you support, and the system routes each feature’s data to the handler you write. Each session is scoped to one feature. The framework defines the complete set of features, and you can’t add your own, though a worker feature lets you carry data in a format your app defines.

Other frameworks extend the feature model to add their own features. The exception is the accessory worker and accessory GPU worker, which the Accessory Transport Extension framework defines directly:

Notification forwarding

Delivers iOS system notifications to your accessory. See NotificationsForwarding and Receiving iOS notifications on an accessory.

Live Activity forwarding

Delivers Live Activity status updates and alerts to your accessory. See LiveActivityForwarding.

Audio accessory head tracking

Forwards head-position sensor data from an audio accessory you develop to the system’s spatial audio renderer. See AudioAccessoryHeadTracking.

Accessory worker

Carries data in a format your app defines between your data provider and transport extensions. See AccessoryWorker and Sending data to an accessory in the background.

Accessory GPU worker

Carries data, like an accessory worker, under a sandbox profile that permits GPU access. See AccessoryGPUWorker.

For a framework-defined feature, such as notification forwarding, the system starts the session. For example, an incoming iOS system notification starts a notification-forwarding session without a call from your app.

Worker features differ from framework-defined features in two ways. Your app defines the format for both sending and receiving, and your transport extension starts every session in response to an event from your accessory. Enroll a worker feature for each accessory by calling AccessoryWorker/requestAuthorization(for:). When your app enrolls a feature, the enrollment takes effect immediately without prompting the person. An enrolled features stays enrolled for the life of the accessory’s pairing. Other features use the authorization flow of their owning framework.

Declare a feature

To use a feature:

  1. Add the feature’s identifier to your data provider extension’s EXCapabilities key.

  2. Declare the feature in your extension’s extensionPoint body with a closure that creates your handler.

  3. Implement the handler to respond to the feature’s events.

  4. For a worker feature, enroll the feature for the accessory from your app during initial pairing with AccessorySetupKit, or from your transport extension, and then open the session from your transport extension.

Open a worker feature session

A feature session carries data for a single feature. It’s distinct from the AccessoryTransportSession that connects your transport extension to the system for one accessory. Every feature defines a capability that conforms to AccessoryFeatureSession, and is launched in the data provider. Worker features also utilize a transport extension, which conforms to AccessoryFeatureRuntimeSession. For the other features, the system delivers data to your transport extension through messageReceived(_:completion:).

To open the data provider’s feature session, call makeFeatureSession(_:) from your transport extension when your accessory reports a change, then call activate(). The system permits one live session per feature for each accessory. For more information on worker features, see Sending data to an accessory in the background.

Confirm the start of a session

The system calls sessionStarted(_:) once your feature session is ready to run.

Returning from activate() doesn’t mean the session started. If your app hasn’t enrolled the feature for the accessory, activate() returns without an error and the session stays registered, with no timeout. Check the feature’s enrollment status (for example, with AccessoryWorker/authorizationStatus(for:)) before opening a session, rather than relying on an error.

Topics

Declaring features

Managing feature sessions

Checking feature authorization

Supporting background work