其他
iOS 18+ 需要隐私友好地发现、授权蓝牙/Wi-Fi…
适用于 iOS 18+ 应用通过系统选择器发现并授权 BLE/Wi-Fi 配件,避免广泛蓝牙权限,并在配对后连接设备。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 57/100 ×0.15
适用场景
iOS 18+ 需要隐私友好地发现、授权特定
解决思路
- 在 Info.plist 添加 NSAccessorySetupSupports([String],必需),按需包含 Bluetooth 和/或 WiFi。
- 支持 Bluetooth 时,在 Info.plist 添加 NSAccessorySetupBluetoothServices([String]),声明应用发现的服务 UUID。
- 支持 Bluetooth 时,添加 NSAccessorySetupBluetoothNames([String]),声明要匹配的 Bluetooth 名称或子串。
- 支持 Bluetooth 时,添加 NSAccessorySetupBluetoothCompanyIdentifiers([String]),声明两字节 Bluetooth company identifiers。
- 确保 Info.plist 中的 Bluetooth 服务、名称、公司标识符与 ASDiscoveryDescriptor 中使用的值一致;未在 Info.plist 声明的标识符、名称或服务会在 AccessorySetupKit 发现期间导致崩溃。
- 支持 Wi-Fi 时,在 NSAccessorySetupSupports 中包含 WiFi,并让描述符的 SSID 规则与 Info.plist 匹配。
- 当 NSAccessorySetupSupports 声明 Bluetooth 后,创建 CBCentralManager 不再触发系统 Bluetooth 权限对话框。
- 注意 CBCentralManager 只有在应用已通过 AccessorySetupKit 配对至少一个配件后,状态才会过渡到 poweredOn。
- 用 ASDiscoveryDescriptor 定义配件匹配条件;系统会将扫描结果与描述符中的所有规则匹配,过滤出目标配件。
- 蓝牙描述符至少设置 bluetoothCompanyIdentifier 或 bluetoothServiceUUID 之一。
- 蓝牙描述符可设置 bluetoothServiceUUID,例如 CBUUID(string: '12345678-1234-1234-1234-123456789ABC')。
- 蓝牙描述符可设置 bluetoothNameSubstring 作为更窄的匹配条件。
- 蓝牙描述符可设置 bluetoothRange = .immediate,只发现紧邻设备。
- 如需按制造数据过滤,设置 bluetoothManufacturerDataBlob 和 bluetoothManufacturerDataMask,并配合 bluetoothCompanyIdentifier;blob 与 mask 长度必须相同。
- 如需按服务数据过滤,设置 bluetoothServiceDataBlob 和 bluetoothServiceDataMask,并配合 bluetoothServiceUUID;blob 与 mask 长度必须相同。
- Wi-Fi 描述符设置 ssid 或 ssidPrefix,二者只能选一个;同时设置会崩溃,ssidPrefix 必须非零长度。
- 根据物理距离需求选择 bluetoothRange:.default 为标准蓝牙范围,.immediate 仅近距离配件。
- 在描述符上设置 supportedOptions 声明配件能力,如 [.bluetoothPairingLE, .bluetoothTransportBridging]。
- supportedOptions 中 .bluetoothPairingLE 表示 BLE 配对支持;.bluetoothTransportBridging 表示 Bluetooth transport bridging;.bluetoothHID 表示 Bluetooth HID 设备。
- 创建 ASAccessorySession 管理发现生命周期。
- 调用 session.activate(on: .main) 激活会话,并传入事件回调;事件回调使用 [weak self] 避免循环引用。
- 等待 .activated 事件后再读取 session.accessories 或展示选择器。
- 在 .activated 事件中检查 session.accessories,获取此前已配对的设备。
- 处理 .accessoryAdded,从 event.accessory 获取用户新选择的配件。
- 处理 .accessoryChanged,配件属性变化,例如在 Settings 中更新显示名称。
- 处理 .accessoryRemoved,用户或应用移除了配件。
- 处理 .invalidated,会话失效且不能复用,需要创建新会话。
- 创建 ASPickerDisplayItem,包含 name、productImage 和 discovery descriptor。
- 用 UIImage(named:) 加载产品图片;加载失败时不要继续展示选择器。
- 调用 session.showPicker(for: [item]) 展示选择器,并处理返回的 error。
- 了解选择器运行在独立系统进程中;每个匹配设备显示为单独项;多个设备匹配同一描述符时会创建横向 carousel。
- 对每个 ASPickerDisplayItem 按需设置 setupOptions,例如 [.rename, .confirmAuthorization]。
- setupOptions 的 .rename 允许在设置期间重命名配件;.confirmAuthorization 在设置前显示授权确认;.finishInApp 表示配对后继续在应用内完成设置。
- 产品图片按 180x120 point 容器准备;为所有屏幕缩放提供高分辨率图片;使用透明背景适配浅色/深色模式;通过透明边框作为 padding 控制配件视觉大小;在浅色和深色模式下测试。
- 在事件处理器中处理所有 ASAccessoryEventType,包括 @unknown default。
- .activated:会话激活,可查询 session.accessories。
- .accessoryAdded:用户在选择器中选择配件。
- .accessoryChanged:配件属性更新,如重命名。
- .accessoryRemoved:配件从系统移除。
- .invalidated:会话失效,创建新会话。
- .migrationComplete:旧配件迁移完成。
- .pickerDidPresent:选择器出现在屏幕。
- .pickerDidDismiss:选择器关闭。
- .pickerSetupBridging:传输桥接设置进行中。
- .pickerSetupPairing:Bluetooth 配对进行中。
- .pickerSetupFailed:设置失败。
- .pickerSetupRename:用户正在重命名配件。
- .accessoryDiscovered:自定义过滤模式发现新配件。
- 用户选择配件时 .accessoryAdded 先于 .pickerDidDismiss 触发;若要在选择器关闭后显示自定义设置 UI,在 .accessoryAdded 中保存 accessory,在 .pickerDidDismiss 中再执行后续设置。
- 配件通过 picker 添加后,用 CoreBluetooth 继续通信;ASAccessory.bluetoothIdentifier 映射到 CBPeripheral。
- 从 accessory.bluetoothIdentifier 获取标识符。
- 创建 CBCentralManager(delegate:queue:);使用 AccessorySetupKit 时不会出现 Bluetooth 权限提示。
- 在 centralManager 进入 .poweredOn 后,用 retrievePeripherals(withIdentifiers: [btIdentifier]) 获取 peripheral。
- 调用 centralManager.connect(peripheral, options: nil) 连接配件。
- 注意 scanForPeripherals(withServices:) 只返回通过 AccessorySetupKit 配对的配件。
- 完全使用 AccessorySetupKit 时不需要 NSBluetoothAlwaysUsageDescription。
- 对 Wi-Fi 配件,使用 ASAccessory.ssid 标识网络。
- 用 NetworkExtension 的 NEHotspotConfiguration(ssid:) 创建配置。
- 通过 NEHotspotConfigurationManager.shared.apply(configuration) 加入网络,并处理 error。
- 因为配件已通过 AccessorySetupKit 发现,加入该网络不会触发标准 Wi-Fi 访问提示。
- 对已有 CoreBluetooth 授权的配件,用 ASMigrationDisplayItem 迁移到 AccessorySetupKit;这是一次性操作,将已知配件注册到新系统。
- 创建 ASMigrationDisplayItem(name:productImage:descriptor:)。
- 迁移 Bluetooth 配件时,设置 migrationItem.peripheralIdentifier = existingPeripheralUUID。
- 迁移 Wi-Fi 配件时,设置 migrationItem.hotspotSSID = "MyAccessory-WiFi"。
- 调用 session.showPicker(for: [migrationItem]) 执行迁移,并处理 error。
- 如果 showPicker 只包含迁移项,系统显示信息页而不是发现选择器。
- 如果迁移项与普通 display items 混合,只有发现并设置新配件时才发生迁移。
- 等待 .migrationComplete 后再创建 CBCentralManager;不要在迁移完成前初始化 CBCentralManager,否则会报错且选择器无法出现。
- 避免描述符标识符未在 Info.plist 声明:展示选择器前声明每个 Bluetooth 服务、名称和公司标识符。
- 避免同时设置 ssid 和 ssidPrefix:只选择一种匹配策略。
- 避免在无明确用户意图时展示选择器:仅从用户操作触发。
- 避免复用已失效的 session:创建、激活并保留新的 ASAccessorySession。
- 处理 accessory removal 事件以清理应用状态。
- 用 ASAccessory 的 bluetoothIdentifier 或 ssid 在设置后连接配件。
- 可查阅 references/accessorysetupkit-patterns.md 了解自定义过滤、批量设置、移除处理和错误恢复等扩展模式。
适用边界 · 注意事项
- 目标平台低于 iOS 18,或必须支持 Android/其他非 Apple 平台。
- 需要扫描、连接未通过系统选择器或未在 Info.plist 声明的任意 BLE 广播设备,或不想使用系统配件选择器。
- 无法使用 AccessorySetupKit 及对应 Apple 框架 CoreBluetooth/NetworkExtension 的环境。