认识 AccessorySetupKit:一步完成蓝牙和 Wi-Fi 配件配对
Meet AccessorySetupKit
2024年6月10日
一句话判断
AccessorySetupKit 把蓝牙和 Wi-Fi 配件的发现、配对、授权合并成一次点击,还自带带产品图片的 picker UI——你的配件 App 终于不用再弹出那些让人困惑的蓝牙权限和 Wi-Fi 加入请求了。
这场 Session 讲了什么
配件的设置体验一直是痛点。之前的流程需要用户授权蓝牙权限、可能还要加入配件的 Wi-Fi 热点、再进行蓝牙配对——每一步都是一道摩擦。iOS 18 的 AccessorySetupKit 把这些全部压缩到一个系统级 picker 界面中。
调用 showPicker() 后,系统在独立进程中扫描附近配件,用你提供的产品图片和名称在 picker 中展示,用户点击即完成配对。蓝牙和 Wi-Fi 的访问权限在这一次点击中同时获得。配对后的配件在系统设置的”配件”行中统一管理,用户可以查看、改名、切换访问权限或移除。
隐私设计是这个框架的核心考量。picker 运行在独立进程中,你的 App 只发送发现规则和展示素材,不直接接触蓝牙扫描。用户在 picker 中看到的是你定义的产品名称和图片,以及配件广播的硬件名称——这样可以验证配件的真实性。
配对完成后,通信仍然使用 CoreBluetooth 和 NetworkExtension 的标准 API,不需要学习新的通信方式。
值得深挖的点
隐私优先的架构设计
AccessorySetupKit 的 picker 不是你 App 的一部分。你的 App 将发现规则(蓝牙 Service UUID、Wi-Fi SSID、公司标识符等)和展示素材(产品名称、产品图片)发送给 picker 进程。picker 进程负责扫描和展示,用户选择后系统完成配对。
这种设计意味着你的 App 在用户点击配对之前无法获取任何附近的蓝牙设备信息。即使配对完成,你也只能访问用户明确授权的那个特定配件,而不是附近所有蓝牙设备。这比请求全局蓝牙权限的隐私保护等级高得多。
在系统设置中,每个配件都有独立的管理页面,显示你提供的产品图片、名称和硬件广播名。用户可以精确控制哪个 App 有权访问哪个配件。这种细粒度的权限模型是未来 iOS 配件生态的发展方向。
多变体配件的发现策略
如果你的产品有多个颜色或型号变体(比如粉色骰子和蓝色骰子),每个变体广播不同的 Service UUID。你需要为每个变体创建单独的 ASPickerDisplayItem,配合对应的 ASDiscoveryDescriptor。picker 会同时扫描所有变体并分别展示,用户选择哪个就配对哪个。
Session 中的 Demo 展示了这个场景:粉色和蓝色电子骰子各自有不同的 Service UUID,picker 同时发现两个并展示。当第二个设备出现时,它还有一个从屏幕边缘”露出”的动画效果。
代码片段
创建 Session 并展示 Picker
import AccessorySetupKit
class DiceManager: NSObject, ASAccessorySessionDelegate {
let session: ASAccessorySession
override init() {
session = ASAccessorySession()
super.init()
// 激活 session,指定事件处理队列
session.activate(on: DispatchQueue.main,
eventHandler: handleEvent)
}
func showPicker() {
// 为粉色骰子创建发现描述
let pinkDescriptor = ASDiscoveryDescriptor()
pinkDescriptor.bluetoothServiceUUID = UUID(uuidString: "xxxx-xxxx-pink")!
// 为蓝色骰子创建发现描述
let blueDescriptor = ASDiscoveryDescriptor()
blueDescriptor.bluetoothServiceUUID = UUID(uuidString: "xxxx-xxxx-blue")!
// 创建展示项:名称 + 图片 + 发现规则
let pinkItem = ASPickerDisplayItem(
name: "粉色电子骰子",
image: UIImage(named: "pink-dice")!,
descriptor: pinkDescriptor
)
let blueItem = ASPickerDisplayItem(
name: "蓝色电子骰子",
image: UIImage(named: "blue-dice")!,
descriptor: blueDescriptor
)
// 展示 picker
session.showPicker(for: [pinkItem, blueItem])
}
}
场景:App 内点击”添加骰子”按钮,弹出系统 picker,同时扫描两种颜色的骰子。
坑点:showPicker 必须在 session 激活之后调用(即收到 activated 事件后)。Info.plist 中需要配置 AccessorySetupKit - Supports 字段指定蓝牙或 Wi-Fi。
处理配对事件
func handleEvent(_ event: ASAccessoryEvent) {
switch event.eventType {
case .activated:
// Session 已激活,可以查询已配对的配件
let existingAccessories = session.accessories
case .accessoryAdded(let accessory):
// 用户选择了配件,配对成功
// 使用 CoreBluetooth 连接和通信
connectToAccessory(accessory)
case .accessoryRemoved(let accessory):
// 配件被移除,清理资源
disconnectFromAccessory(accessory)
case .pickerDidDismiss:
// 用户取消了 picker
break
default:
break
}
}
func connectToAccessory(_ accessory: ASAccessory) {
// 拿到 CBPeripheral,用 CoreBluetooth 正常通信
if let peripheral = accessory.bluetoothPeripheral {
centralManager.connect(peripheral)
}
}
场景:处理用户在 picker 中的选择结果,配对成功后用 CoreBluetooth 建立连接。
Info.plist 配置
<!-- 声明支持蓝牙配件 -->
<key>AccessorySetupKit - Supports</key>
<array>
<string>Bluetooth</string>
</array>
<!-- 配置发现规则 -->
<key>Bluetooth Services</key>
<array>
<string>XXXX-XXXX-PINK</string>
<string>XXXX-XXXX-BLUE</string>
</array>
场景:告诉系统你的 App 需要查找哪些蓝牙 Service UUID 的配件。picker 进程用这些规则做扫描过滤。
最佳实践
- 配件的产品图片和名称是用户识别配件的依据,确保清晰准确
- 如果配件同时支持蓝牙和 Wi-Fi,在一个 discovery descriptor 中配置两种规则,用户一次点击获得两种访问权限
- 配对后的通信继续用 CoreBluetooth 和 NetworkExtension,不需要改变现有代码
- 将已有的蓝牙权限请求流程迁移到 AccessorySetupKit,提升用户体验和隐私保护
- 在配件的系统设置页面中展示你的产品图片,帮助用户区分不同配件
还有什么值得关注
- 配件管理页面同时出现在蓝牙设置和 Wi-Fi 设置中(取决于配件支持的技术)
ASDiscoveryDescriptor支持的组合条件非常灵活,可以在文档中查看完整列表- Sample Project 可以在 Apple 开发者网站下载,包含完整的电子骰子配对和通信示例