图像与设计
为 iOS/iPadOS 26.4+…
当配套 app 注册音频配件、app extension 上报佩戴状态或连接源变化,或需要处理 AccessoryControlDevice 能力与错误时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
为 iOS/iPadOS 26.4+ 第特定
解决思路
- Setup:先通过 AccessorySetupKit 在蓝牙上配对 accessory,得到 `ASAccessory` 对象,再进入 AudioAccessoryKit 注册流程。
- Setup:在容器 app 和 app extension 中按需导入 `AccessorySetupKit` 与 `AudioAccessoryKit`。
- Setup:将 deployment target 设为 iOS 26.4+ 或 iPadOS 26.4+。
- Setup:当前 Xcode 26.6 工具链中 AudioAccessoryKit 存在于 device SDK 而不在 iPhone Simulator 26.5 SDK;使用物理设备 destination 构建该 target。
- Setup:如果 app 其余部分必须为 Simulator 构建,隔离 target membership,或用 `#if canImport(AudioAccessoryKit)` 守卫 import 和实现,并提供 simulator stub。
- Session:通过 AccessorySetupKit 配对完成后,在容器 app 中把描述 capabilities 和初始状态的 `AccessoryControlDevice.Configuration` 传给 `AccessoryControlDevice.register(accessory, configuration)`。
- Session:注册配置示例:`AccessoryControlDevice.Configuration(devicePlacement: .offHead, deviceCapabilities: [.audioSwitching, .placement])`。
- Session:在 app extension 中用 `try AccessoryControlDevice.current(for: accessory)` 取得 device,再读取 `device.configuration` 获取当前配置;`current(for:)` 仅 app-extension 可用。
- Session:在 app extension 中只更新注册时声明过 capability 的字段;先确认注册声明了该能力,复制并修改 `device.configuration`,再 `try await device.update(config)`。
- Session:`update(_:)` 不返回配置值;仅在调用成功后更新 app 侧镜像。
- Session:`update(_:)` 失败时按 `AccessoryControlDevice.Error` 处理;该方法是 app-extension-only。
- Audio Switching:在标准注册流程中声明 `.audioSwitching` 以启用自动音频切换。
- Audio Switching:仅当 accessory 能报告持续 placement 变化时,才声明 `.placement` 并提供初始 placement。
- Audio Switching:常用 capabilities:`.audioSwitching` 表示设备支持自动音频切换,`.placement` 表示设备可报告物理 placement;按需组合。
- Audio Switching:除非 accessory 能持续向系统更新真实 placement 状态,否则不要声明 `.placement`。
- Placement:从 app extension 报告 accessory 物理位置以帮助系统做路由决策;每当 accessory 检测到位置变化就更新 placement。
- Placement:`AccessoryControlDevice.Placement` 四个值为 `.inEar` 在耳内(如 earbuds)、`.onHead` 在头上(如 headband headphones)、`.overTheEar` 罩耳(如 over-ear headphones)、`.offHead` 未佩戴。
- Placement:用 `config.devicePlacement = .inEar` 更新 placement,并在标准 current→copy→update 序列中应用。
- Placement:常见转换:用户戴上时 `.offHead` 到 `.onHead` 或 `.inEar`,取下时 `.onHead` 或 `.inEar` 到 `.offHead`。
- Placement:每次检测到 placement 变化都及时更新,以保证音频路由响应。
- Connected Audio Sources:对于可同时连接多个蓝牙设备的 accessory,从 app extension 告知系统哪些设备已连接,使系统从正确 source 路由音频。
- Connected Audio Sources:用 `Data` 提供已连接设备的蓝牙地址,设置 `config.primaryAudioSourceDeviceIdentifier = primaryBTAddress` 和 `config.secondaryAudioSourceDeviceIdentifier = secondaryBTAddress`。
- Connected Audio Sources:示例主蓝牙地址 `Data([0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC])`,次地址 `Data([0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45])`。
- Connected Audio Sources:蓝牙连接状态变化(新设备连接、现有设备断开)时更新 primary 和 secondary source identifiers,然后调用标准 `update(_:)` 序列。
- Connected Audio Sources:配置字段包括 `deviceCapabilities`(`Capabilities`,已声明能力)、`devicePlacement`(`Placement?`,当前物理 placement)、`primaryAudioSourceDeviceIdentifier`(`Data?`,主连接蓝牙设备地址)、`secondaryAudioSourceDeviceIdentifier`(`Data?`,次连接蓝牙设备地址)。
- Feature Discovery:在 app extension 中通过 `device.configuration.deviceCapabilities` 查询已声明 capabilities。
- Feature Discovery:用 `caps.contains(.audioSwitching)` 判断设备是否支持自动音频切换,用 `caps.contains(.placement)` 判断是否能报告物理 placement。
- Feature Discovery:读取 `device.configuration.devicePlacement` 判断是否佩戴:`.inEar`、`.onHead`、`.overTheEar` 视为正在佩戴,`.offHead` 视为未佩戴,处理 `@unknown default`。
- Error Handling:处理 `AccessoryControlDevice.Error`:`.accessoryNotCapable` 表示 accessory 不支持请求的 capability;`.invalidRequest` 表示请求参数无效;`.invalidated` 表示设备注册已失效;`.unknown` 表示未指定错误。
- Error Handling:注册和更新调用用 `do/catch` 捕获 `AccessoryControlDevice.Error` 并 switch:`.accessoryNotCapable` 检查硬件能力,`.invalidRequest` 检查注册参数,`.invalidated` 重新协调容器 app 注册,`.unknown` 记录、暴露或传播。
- Error Handling:不要推断 `.invalidated` 或 `.unknown` 是 transient。
- Error Handling:修正无效 capabilities 或请求参数;丢弃 invalidated handle,并通知容器 app 在适当时候重新评估注册;暴露 unspecified errors。
- Error Handling:需要完整 disposition 和 invalidation handoff 时查阅 `references/audioaccessorykit-patterns.md#error-recovery-patterns`。
- Common Mistakes:不要在通过 AccessorySetupKit 配对之前注册;只注册已完成 AccessorySetupKit 配对返回的 `ASAccessory`。
- Common Mistakes:如果注册声明了 `.placement`,extension 必须在每次检测到转换时用标准更新序列更新 placement。
- Common Mistakes:多设备 accessory 的蓝牙连接状态变化不能忽略;连接变化时清除或替换 primary 和 secondary source identifiers,避免陈旧标识降低切换准确性。
- Common Mistakes:不要忽略 invalidated 错误;错误做法是直接 `try await device.update(config)` 且不处理抛出的 `.invalidated`。
- Common Mistakes:正确做法是 `do { try await device.update(config) } catch AccessoryControlDevice.Error.invalidated { await notifyContainerAppToReevaluateRegistration(accessory) }`,丢弃 handle 并让容器重新评估注册。
- Review:确认 Accessory 在 AudioAccessoryKit 注册前已通过 AccessorySetupKit 配对。
- Review:确认同时导入 `AccessorySetupKit` 和 `AudioAccessoryKit`。
- Review:确认容器 app 用 `AccessoryControlDevice.Configuration` 调用 `register(_: _:)`。
- Review:确认 app extension 调用 `current(for:)` 和 `update(_:)`。
- Review:确认注册配置中的 capabilities 与实际硬件支持匹配。
- Review:确认 updates 只触碰注册时声明过能力的字段。
- Review:确认 `.placement` capability 伴随持续 placement 更新。
- Review:确认及时报告 placement 转换(戴上/取下)。
- Review:确认蓝牙连接变化时更新 audio source device identifiers。
- Review:确认处理所有 `AccessoryControlDevice.Error` 情况,包括 `@unknown default`。
- Review:确认 `update(_:)` 调用使用 `try await` 并处理错误。
- Review:确认 invalidated device references 触发容器 app 注册恢复。
- Review:确认 deployment target 设为 iOS 26.4+ 或 iPadOS 26.4+。
- References:扩展模式(注册流程、placement 监控、多设备协调)见 `references/audioaccessorykit-patterns.md`;API 细节见 AudioAccessoryKit 和 AccessoryControlDevice 的 Apple 文档。
- Beta:AudioAccessoryKit 是 iOS 26.4 新增,依赖具体 API 细节前重新检查当前 Apple 文档。
适用边界 · 注意事项
- 不用于通用 AVAudioSession 路由。
- 不用于 Bluetooth transport。
- 不用于初次 accessory pairing;初次配对应使用 AccessorySetupKit。