$npx -y skills add dpearson2699/swift-ios-skills --skill audioaccessorykitSupport automatic audio switching for paired third-party Bluetooth headphones or earbuds with AudioAccessoryKit. Use when a companion app registers an audio accessory, an app extension reports worn/removed placement or connected source-device changes, or AccessoryControlDevice ca
| 1 | # AudioAccessoryKit |
| 2 | |
| 3 | Automatic audio switching support and intelligent audio routing inputs for |
| 4 | third-party audio accessories. Enables companion apps to register audio |
| 5 | accessory configuration with the system, and app extensions to report placement |
| 6 | and connected source changes that help the system switch audio output. |
| 7 | Available iOS 26.4+ / iPadOS 26.4+. |
| 8 | |
| 9 | > **Beta-sensitive.** AudioAccessoryKit is new in iOS 26.4. Re-check current |
| 10 | > Apple documentation before relying on specific API details. |
| 11 | |
| 12 | AudioAccessoryKit builds on top of AccessorySetupKit. The accessory must first |
| 13 | be paired via AccessorySetupKit before it can be registered for audio features. |
| 14 | The central type is `AccessoryControlDevice`, which registers a |
| 15 | `Configuration` from the container app and applies ongoing configuration updates |
| 16 | from the app extension. |
| 17 | |
| 18 | ## Contents |
| 19 | |
| 20 | - [Setup](#setup) |
| 21 | - [Session Management](#session-management) |
| 22 | - [Audio Switching](#audio-switching) |
| 23 | - [Device Placement](#device-placement) |
| 24 | - [Connected Audio Sources](#connected-audio-sources) |
| 25 | - [Feature Discovery](#feature-discovery) |
| 26 | - [Error Handling](#error-handling) |
| 27 | - [Common Mistakes](#common-mistakes) |
| 28 | - [Review Checklist](#review-checklist) |
| 29 | - [References](#references) |
| 30 | |
| 31 | ## Setup |
| 32 | |
| 33 | ### Prerequisites |
| 34 | |
| 35 | 1. Pair the accessory over Bluetooth using AccessorySetupKit. This yields an |
| 36 | `ASAccessory` object. |
| 37 | 2. Import the frameworks where needed in the container app and extension: |
| 38 | |
| 39 | ```swift |
| 40 | import AccessorySetupKit |
| 41 | import AudioAccessoryKit |
| 42 | ``` |
| 43 | |
| 44 | ### Framework Availability |
| 45 | |
| 46 | | Platform | Minimum Version | |
| 47 | |---|---| |
| 48 | | iOS | 26.4+ | |
| 49 | | iPadOS | 26.4+ | |
| 50 | |
| 51 | In the current Xcode 26.6 toolchain, AudioAccessoryKit is present in the device |
| 52 | SDK but not the iPhone Simulator 26.5 SDK. Use a physical-device destination |
| 53 | for this target. If the rest of the app must build for Simulator, isolate target |
| 54 | membership or guard the import and implementation with |
| 55 | `#if canImport(AudioAccessoryKit)` and provide a simulator stub. |
| 56 | |
| 57 | ## Session Management |
| 58 | |
| 59 | ### Registering an Accessory |
| 60 | |
| 61 | After pairing via AccessorySetupKit, register the accessory from the container |
| 62 | app by passing an `AccessoryControlDevice.Configuration` that describes the |
| 63 | capabilities and any initial state the accessory supports: |
| 64 | |
| 65 | ```swift |
| 66 | let accessory: ASAccessory // Obtained from AccessorySetupKit pairing |
| 67 | |
| 68 | let configuration = AccessoryControlDevice.Configuration( |
| 69 | devicePlacement: .offHead, |
| 70 | deviceCapabilities: [.audioSwitching, .placement] |
| 71 | ) |
| 72 | |
| 73 | try await AccessoryControlDevice.register(accessory, configuration) |
| 74 | ``` |
| 75 | |
| 76 | Registration activates the specified capabilities and gives the system the |
| 77 | configuration it needs to participate in audio routing decisions. |
| 78 | |
| 79 | ### Retrieving the Current Configuration |
| 80 | |
| 81 | In the app extension, access the device's current configuration using the |
| 82 | static `current(for:)` method: |
| 83 | |
| 84 | ```swift |
| 85 | let device = try AccessoryControlDevice.current(for: accessory) |
| 86 | let currentConfig = device.configuration |
| 87 | ``` |
| 88 | |
| 89 | This returns the `AccessoryControlDevice` instance associated with the paired |
| 90 | `ASAccessory`. The device exposes both the `accessory` reference and the |
| 91 | current `configuration`. Apple marks `current(for:)` as app-extension-only. |
| 92 | |
| 93 | ### Updating Configuration |
| 94 | |
| 95 | In the app extension, push configuration changes to the system with |
| 96 | `update(_:)`. Only update fields for capabilities that were declared during |
| 97 | registration: |
| 98 | |
| 99 | ```swift |
| 100 | let device = try AccessoryControlDevice.current(for: accessory) |
| 101 | var config = device.configuration |
| 102 | |
| 103 | config.devicePlacement = .onHead |
| 104 | try await device.update(config) |
| 105 | ``` |
| 106 | |
| 107 | Treat this as a gated write workflow: confirm registration declared the |
| 108 | capability, copy and mutate `device.configuration`, then `try await update(_:)`. |
| 109 | The method returns no configuration value; update an app-side mirror only after |
| 110 | the call succeeds. On failure, use the disposition in |
| 111 | [Error Handling](#error-handling). Apple marks `update(_:)` as |
| 112 | app-extension-only. |
| 113 | |
| 114 | ## Audio Switching |
| 115 | |
| 116 | Automatic audio switching lets the system intelligently route audio output to |
| 117 | the correct device based on placement and connected sources. |
| 118 | |
| 119 | ### Enabling Audio Switching |
| 120 | |
| 121 | Declare `.audioSwitching` during the canonical registration flow above. Include |
| 122 | `.placement` and an initial placement only when the accessory can report ongoing |
| 123 | placement changes. |
| 124 | |
| 125 | ### Capabilities |
| 126 | |
| 127 | Automatic switching commonly uses these `AccessoryControlDevice.Capabilities`: |
| 128 | |
| 129 | | Capability | Purpose | |
| 130 | |---|---| |
| 131 | | `.audioSwitching` | Device supports automatic audio switching | |
| 132 | | `.placement` | Device can report its physical placement | |
| 133 | |
| 134 | Combine capabi |