audioaccessorykit

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

AudioAccessoryKit

AudioAccessoryKit

Automatic audio switching and intelligent audio routing for third-party audio accessories. Enables companion apps to register audio accessories with the system, report device placement, and declare capabilities so the system can seamlessly switch audio output. Available iOS 26.4+ / Swift 6.3.
Beta-sensitive. AudioAccessoryKit is new in iOS 26.4 and may change before GM. Re-check current Apple documentation before relying on specific API details.
AudioAccessoryKit builds on top of AccessorySetupKit. The accessory must first be paired via AccessorySetupKit before it can be registered for audio features. The central type is
AccessoryControlDevice
, which manages registration, capability declaration, and ongoing state updates.
为第三方音频配件提供自动音频切换和智能音频路由能力。支持配套应用向系统注册音频配件、上报设备佩戴位置、声明设备能力,从而让系统可以无缝切换音频输出。适用于iOS 26.4+ / Swift 6.3。
测试版敏感提示 AudioAccessoryKit是iOS 26.4新增框架,在GM版发布前可能发生变更。在依赖特定API细节前,请重新查阅苹果官方当前文档。
AudioAccessoryKit基于AccessorySetupKit构建。配件必须先通过AccessorySetupKit完成配对,才能注册音频相关功能。核心类型为
AccessoryControlDevice
,负责管理注册、能力声明和持续状态更新。

Contents

目录

Setup

设置

Prerequisites

前置条件

  1. Pair the accessory over Bluetooth using AccessorySetupKit. This yields an
    ASAccessory
    object.
  2. Import both frameworks in the companion app:
swift
import AccessorySetupKit
import AudioAccessoryKit
  1. 使用AccessorySetupKit通过蓝牙配对配件,获取
    ASAccessory
    对象。
  2. 在配套应用中导入两个框架:
swift
import AccessorySetupKit
import AudioAccessoryKit

Framework Availability

框架支持版本

PlatformMinimum Version
iOS26.4+
iPadOS26.4+
平台最低版本
iOS26.4+
iPadOS26.4+

Session Management

会话管理

Registering an Accessory

注册配件

After pairing via AccessorySetupKit, register the accessory with
AccessoryControlDevice
by specifying the capabilities it supports:
swift
let accessory: ASAccessory  // Obtained from AccessorySetupKit pairing

let capabilities: AccessoryControlDevice.Capabilities = [.audioSwitching, .placement]
try await AccessoryControlDevice.register(accessory, capabilities)
Registration activates the specified capabilities and tells the system to begin routing audio to the accessory.
通过AccessorySetupKit完成配对后,调用
AccessoryControlDevice
注册配件并指定其支持的能力:
swift
let accessory: ASAccessory  // 从AccessorySetupKit配对流程中获取

let capabilities: AccessoryControlDevice.Capabilities = [.audioSwitching, .placement]
try await AccessoryControlDevice.register(accessory, capabilities)
注册会激活指定的能力,并通知系统开始将音频路由到该配件。

Retrieving the Current Configuration

获取当前配置

Access the device's current configuration at any time using the static
current(for:)
method:
swift
let device = try AccessoryControlDevice.current(for: accessory)
let currentConfig = device.configuration
This returns the
AccessoryControlDevice
instance associated with the paired
ASAccessory
. The device exposes both the
accessory
reference and the current
configuration
.
随时可以通过静态方法
current(for:)
访问设备当前配置:
swift
let device = try AccessoryControlDevice.current(for: accessory)
let currentConfig = device.configuration
该方法会返回与已配对
ASAccessory
关联的
AccessoryControlDevice
实例,设备实例同时暴露
accessory
引用和当前
configuration

Updating Configuration

更新配置

Push configuration changes to the system with
update(_:)
:
swift
let device = try AccessoryControlDevice.current(for: accessory)
var config = device.configuration

config.devicePlacement = .onHead
try await device.update(config)
The update call is async and can throw
AccessoryControlDevice.Error
on failure.
调用
update(_:)
向系统推送配置变更:
swift
let device = try AccessoryControlDevice.current(for: accessory)
var config = device.configuration

config.devicePlacement = .onHead
try await device.update(config)
更新调用是异步方法,失败时会抛出
AccessoryControlDevice.Error

Audio Switching

音频切换

Automatic audio switching lets the system intelligently route audio output to the correct device based on placement and connected sources.
自动音频切换功能让系统可以基于佩戴位置和已连接源,智能将音频输出路由到正确设备。

Enabling Audio Switching

启用音频切换

Declare the
.audioSwitching
capability during registration:
swift
let capabilities: AccessoryControlDevice.Capabilities = [.audioSwitching]
try await AccessoryControlDevice.register(accessory, capabilities)
For full automatic switching (including placement-based routing), include both capabilities:
swift
let capabilities: AccessoryControlDevice.Capabilities = [.audioSwitching, .placement]
try await AccessoryControlDevice.register(accessory, capabilities)
在注册时声明
.audioSwitching
能力:
swift
let capabilities: AccessoryControlDevice.Capabilities = [.audioSwitching]
try await AccessoryControlDevice.register(accessory, capabilities)
如果需要完整自动切换能力(包括基于佩戴位置的路由),需要同时声明两个能力:
swift
let capabilities: AccessoryControlDevice.Capabilities = [.audioSwitching, .placement]
try await AccessoryControlDevice.register(accessory, capabilities)

Capabilities

能力说明

AccessoryControlDevice.Capabilities
is an option set with two members:
CapabilityPurpose
.audioSwitching
Device supports automatic audio switching
.placement
Device can report its physical placement
Both capabilities can be combined. Audio switching works without placement, but providing placement enables more intelligent routing decisions.
AccessoryControlDevice.Capabilities
是选项集,包含两个成员:
能力用途
.audioSwitching
设备支持自动音频切换
.placement
设备可以上报自身物理佩戴位置
两个能力可以组合使用。音频切换功能不需要佩戴位置支持,但提供佩戴位置可以让系统做出更智能的路由决策。

Device Placement

设备佩戴位置

Report the physical position of the accessory to help the system make routing decisions. Update placement whenever the accessory detects a position change.
上报配件的物理位置可以帮助系统做出路由决策,每当配件检测到位置变化时都要更新佩戴位置。

Placement Values

佩戴位置枚举值

AccessoryControlDevice.Placement
defines four cases:
PlacementMeaning
.inEar
Accessory is seated in the ear (e.g., earbuds)
.onHead
Accessory is on the head (e.g., headband headphones)
.overTheEar
Accessory is over the ear (e.g., over-ear headphones)
.offHead
Accessory is not being worn
AccessoryControlDevice.Placement
定义了四种取值:
位置含义
.inEar
配件佩戴在耳内(例如入耳式耳机)
.onHead
配件佩戴在头上(例如头戴式压耳耳机)
.overTheEar
配件包裹耳朵(例如头戴式包耳耳机)
.offHead
配件未被佩戴

Updating Placement

更新佩戴位置

swift
let device = try AccessoryControlDevice.current(for: accessory)
var config = device.configuration

config.devicePlacement = .inEar
try await device.update(config)
Common transitions:
  • .offHead
    to
    .onHead
    or
    .inEar
    when the user puts on the accessory
  • .onHead
    or
    .inEar
    to
    .offHead
    when removed
  • Update promptly on every detected change for responsive audio routing
swift
let device = try AccessoryControlDevice.current(for: accessory)
var config = device.configuration

config.devicePlacement = .inEar
try await device.update(config)
常见状态转换:
  • 当用户佩戴配件时,从
    .offHead
    切换到
    .onHead
    .inEar
  • 当用户摘下配件时,从
    .onHead
    .inEar
    切换到
    .offHead
  • 每次检测到变化都要及时更新,以保证音频路由响应及时

Connected Audio Sources

已连接音频源

For accessories that connect to multiple Bluetooth devices simultaneously, inform the system which devices are connected. This lets the system route audio from the appropriate source.
对于可以同时连接多个蓝牙设备的配件,需要通知系统当前连接的设备有哪些,让系统可以从合适的来源路由音频。

Setting Audio Source Identifiers

设置音频源标识符

Provide the Bluetooth address of connected devices as
Data
:
swift
let device = try AccessoryControlDevice.current(for: accessory)
var config = device.configuration

let primaryBTAddress = Data([0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC])
config.primaryAudioSourceDeviceIdentifier = primaryBTAddress

let secondaryBTAddress = Data([0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45])
config.secondaryAudioSourceDeviceIdentifier = secondaryBTAddress

try await device.update(config)
Update these identifiers when the Bluetooth connection state changes (new device connects, existing device disconnects).
将已连接设备的蓝牙地址作为
Data
传入:
swift
let device = try AccessoryControlDevice.current(for: accessory)
var config = device.configuration

let primaryBTAddress = Data([0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC])
config.primaryAudioSourceDeviceIdentifier = primaryBTAddress

let secondaryBTAddress = Data([0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45])
config.secondaryAudioSourceDeviceIdentifier = secondaryBTAddress

try await device.update(config)
当蓝牙连接状态变化时(新设备连接、已有设备断开)要更新这些标识符。

Configuration Properties

配置属性说明

AccessoryControlDevice.Configuration
contains all configurable state:
PropertyTypePurpose
deviceCapabilities
Capabilities
Declared device capabilities
devicePlacement
Placement?
Current physical placement
primaryAudioSourceDeviceIdentifier
Data?
Primary connected Bluetooth device address
secondaryAudioSourceDeviceIdentifier
Data?
Secondary connected Bluetooth device address
AccessoryControlDevice.Configuration
包含所有可配置状态:
属性类型用途
deviceCapabilities
Capabilities
声明的设备能力
devicePlacement
Placement?
当前物理佩戴位置
primaryAudioSourceDeviceIdentifier
Data?
已连接主蓝牙设备地址
secondaryAudioSourceDeviceIdentifier
Data?
已连接次蓝牙设备地址

Feature Discovery

能力发现

Querying Capabilities

查询能力

After registration, inspect the device's declared capabilities through its configuration:
swift
let device = try AccessoryControlDevice.current(for: accessory)
let caps = device.configuration.deviceCapabilities

if caps.contains(.audioSwitching) {
    // Device supports automatic audio switching
}

if caps.contains(.placement) {
    // Device reports physical placement
}
注册完成后,可以通过设备配置查看其声明的能力:
swift
let device = try AccessoryControlDevice.current(for: accessory)
let caps = device.configuration.deviceCapabilities

if caps.contains(.audioSwitching) {
    // 设备支持自动音频切换
}

if caps.contains(.placement) {
    // 设备支持上报物理佩戴位置
}

Checking Placement

检查佩戴位置

Read the current placement to determine if the accessory is being worn:
swift
let device = try AccessoryControlDevice.current(for: accessory)

if let placement = device.configuration.devicePlacement {
    switch placement {
    case .inEar, .onHead, .overTheEar:
        // Accessory is being worn
        break
    case .offHead:
        // Accessory is not being worn
        break
    @unknown default:
        break
    }
}
读取当前佩戴位置判断配件是否被佩戴:
swift
let device = try AccessoryControlDevice.current(for: accessory)

if let placement = device.configuration.devicePlacement {
    switch placement {
    case .inEar, .onHead, .overTheEar:
        // 配件正被佩戴
        break
    case .offHead:
        // 配件未被佩戴
        break
    @unknown default:
        break
    }
}

Error Handling

错误处理

AccessoryControlDevice.Error
covers failure cases during registration and updates:
ErrorCause
.accessoryNotCapable
Accessory does not support the requested capability
.invalidRequest
Request parameters are invalid
.invalidated
Device registration has been invalidated
.unknown
An unspecified error occurred
Handle errors from registration and update calls:
swift
do {
    try await AccessoryControlDevice.register(accessory, capabilities)
} catch let error as AccessoryControlDevice.Error {
    switch error {
    case .accessoryNotCapable:
        // Accessory hardware does not support requested capabilities
        break
    case .invalidRequest:
        // Check registration parameters
        break
    case .invalidated:
        // Re-register the device
        break
    case .unknown:
        // Log and retry
        break
    @unknown default:
        break
    }
}
AccessoryControlDevice.Error
覆盖了注册和更新过程中的失败场景:
错误原因
.accessoryNotCapable
配件不支持请求的能力
.invalidRequest
请求参数无效
.invalidated
设备注册已失效
.unknown
发生未定义错误
处理注册和更新调用的错误:
swift
do {
    try await AccessoryControlDevice.register(accessory, capabilities)
} catch let error as AccessoryControlDevice.Error {
    switch error {
    case .accessoryNotCapable:
        // 配件硬件不支持请求的能力
        break
    case .invalidRequest:
        // 检查注册参数
        break
    case .invalidated:
        // 重新注册设备
        break
    case .unknown:
        // 记录日志并重试
        break
    @unknown default:
        break
    }
}

Common Mistakes

常见错误

DON'T: Register before pairing with AccessorySetupKit

不要:在通过AccessorySetupKit配对前注册

swift
// WRONG -- accessory not yet paired
let rawAccessory = ASAccessory()
try await AccessoryControlDevice.register(rawAccessory, [.audioSwitching])

// CORRECT -- use the ASAccessory from a completed pairing session
session.activate(on: .main) { event in
    if event.eventType == .accessoryAdded, let accessory = event.accessory {
        Task {
            try await AccessoryControlDevice.register(accessory, [.audioSwitching])
        }
    }
}
swift
// 错误 -- 配件尚未完成配对
let rawAccessory = ASAccessory()
try await AccessoryControlDevice.register(rawAccessory, [.audioSwitching])

// 正确 -- 使用完成配对流程返回的ASAccessory
session.activate(on: .main) { event in
    if event.eventType == .accessoryAdded, let accessory = event.accessory {
        Task {
            try await AccessoryControlDevice.register(accessory, [.audioSwitching])
        }
    }
}

DON'T: Declare placement capability without updating placement

不要:声明了佩戴位置能力但从不更新位置

swift
// WRONG -- registers placement but never updates it
try await AccessoryControlDevice.register(accessory, [.audioSwitching, .placement])
// System never receives placement data, reducing switching accuracy

// CORRECT -- update placement promptly after registration
try await AccessoryControlDevice.register(accessory, [.audioSwitching, .placement])
let device = try AccessoryControlDevice.current(for: accessory)
var config = device.configuration
config.devicePlacement = .offHead
try await device.update(config)
swift
// 错误 -- 注册了佩戴位置能力但从未更新
try await AccessoryControlDevice.register(accessory, [.audioSwitching, .placement])
// 系统从未收到佩戴位置数据,会降低切换准确性

// 正确 -- 注册后及时更新佩戴位置
try await AccessoryControlDevice.register(accessory, [.audioSwitching, .placement])
let device = try AccessoryControlDevice.current(for: accessory)
var config = device.configuration
config.devicePlacement = .offHead
try await device.update(config)

DON'T: Ignore connection state changes for multi-device accessories

不要:忽略多设备配件的连接状态变化

swift
// WRONG -- set audio source identifiers once and never update
config.primaryAudioSourceDeviceIdentifier = someAddress
try await device.update(config)
// Device disconnects, but system still thinks it's the primary source

// CORRECT -- update identifiers when connections change
func onDeviceDisconnected() {
    var config = device.configuration
    config.primaryAudioSourceDeviceIdentifier = nil
    Task { try await device.update(config) }
}
swift
// 错误 -- 仅设置一次音频源标识符从不更新
config.primaryAudioSourceDeviceIdentifier = someAddress
try await device.update(config)
// 设备断开连接,但系统仍然认为它是主音频源

// 正确 -- 连接状态变化时更新标识符
func onDeviceDisconnected() {
    var config = device.configuration
    config.primaryAudioSourceDeviceIdentifier = nil
    Task { try await device.update(config) }
}

DON'T: Forget to handle the invalidated error

不要:忘记处理失效错误

swift
// WRONG -- ignores invalidation, keeps using stale device reference
try await device.update(config)  // Throws .invalidated, unhandled

// CORRECT -- catch invalidation and re-register
do {
    try await device.update(config)
} catch AccessoryControlDevice.Error.invalidated {
    try await AccessoryControlDevice.register(accessory, capabilities)
}
swift
// 错误 -- 忽略失效错误,继续使用过期的设备引用
try await device.update(config)  // 抛出.invalidated错误,未处理

// 正确 -- 捕获失效错误并重新注册
do {
    try await device.update(config)
} catch AccessoryControlDevice.Error.invalidated {
    try await AccessoryControlDevice.register(accessory, capabilities)
}

Review Checklist

审核清单

  • Accessory paired via AccessorySetupKit before AudioAccessoryKit registration
  • Both
    AccessorySetupKit
    and
    AudioAccessoryKit
    imported
  • Capabilities declared at registration match actual hardware support
  • .placement
    capability accompanied by ongoing placement updates
  • Placement transitions (on/off head) reported promptly
  • Audio source device identifiers updated on Bluetooth connection changes
  • All
    AccessoryControlDevice.Error
    cases handled, including
    @unknown default
  • update(_:)
    calls use
    try await
    and handle errors
  • Invalidated device references re-registered when needed
  • Deployment target set to iOS 26.4+ or iPadOS 26.4+
  • 配件在AudioAccessoryKit注册前已通过AccessorySetupKit完成配对
  • 已同时导入
    AccessorySetupKit
    AudioAccessoryKit
  • 注册时声明的能力与硬件实际支持的能力匹配
  • 声明
    .placement
    能力的同时会持续更新佩戴位置
  • 佩戴位置变化(戴上/摘下)会及时上报
  • 蓝牙连接变化时会更新音频源设备标识符
  • 已处理所有
    AccessoryControlDevice.Error
    case,包括
    @unknown default
  • update(_:)
    调用使用
    try await
    并处理错误
  • 失效的设备引用会在需要时重新注册
  • 部署目标设置为iOS 26.4+或iPadOS 26.4+

References

参考资料