WWDC Quick Look 💓 By SwiftGGTeam
Meet AccessorySetupKit

Meet AccessorySetupKit

元の動画を見る

ハイライト

アクセサリのセットアップ体験は長年の課題でした。従来のフローは Bluetooth 権限の許可、場合によってはアクセサリの Wi-Fi ホットスポットへの参加、Bluetooth ペアリング——各ステップが摩擦となります。iOS 18 の AccessorySetupKit はこれらすべてを 1 つのシステム picker 画面に集約します。


主要内容

Bluetooth アクセサリのペアリングに何ステップ必要?iOS 17 以前の答え:Bluetooth 権限を要求、システムダイアログを待つ、ユーザーが許可、デバイスをスキャン、場合によっては Wi-Fi ホットスポットに個別参加、Bluetooth ペアリングを開始——各ステップでユーザーを失う可能性があります。Apple の調査でも、アクセサリ初回セットアップ時の摩擦がユーザー離脱の最大原因です。

iOS 18 の AccessorySetupKit はフローを 1 タップに圧縮。App が showPicker() を呼ぶと、システムが独立プロセスで近くのアクセサリをスキャン、提供した製品画像と名称で picker に表示し、ユーザーがタップすればペアリング完了。Bluetooth と Wi-Fi のアクセス権限はこの 1 タップで同時に付与——個別の権限ダイアログは不要。

プライバシー設計がこのフレームワークの核心。picker は独立プロセスで動作し、App は発見ルールと表示素材のみ送信。Bluetooth スキャンに直接触れません。picker では App が定義した製品名/画像とアクセサリがブロードキャストするハードウェア名の両方を表示し、ユーザーが真正性を確認できます。ペアリング後の通信は CoreBluetooth と NetworkExtension の標準 API をそのまま使用——新しい通信方式を学ぶ必要はありません。

詳細

AccessorySetupKit 利用の第一歩は Info.plist でサポート技術と発見ルールを宣言。AccessorySetupKit - Supports 配列に Bluetooth(または Wi-Fi)を追加し、Bluetooth Services にアクセサリがブロードキャストする GATT service UUID を入力(04:12)。

核心 API は ASAccessorySession。session を作成・有効化し、イベントコールバックを登録(06:02):

import AccessorySetupKit

// Create a session
var session = ASAccessorySession()

// Activate session with event handler
session.activate(on: DispatchQueue.main, eventHandler: handleSessionEvent(event:))

// Handle event
func handleSessionEvent(event: ASAccessoryEvent) {
    switch event.eventType {
    case .activated:
        print("Session is activated and ready to use")
        print(session.accessories)
    default:
        print("Received event type \(event.eventType)")
    }
}

キーポイント:

  • ASAccessorySession は picker 表示、イベント受信、アクセサリ管理の中心オブジェクト
  • activate(on:eventHandler:) には DispatchQueue とイベントコールバックが必要
  • .activated イベントは session が準備完了。既存の session.accessories を読み取るか、新しいペアリングフローを開始可能

次に ASPickerDisplayItem を作成し、各アクセサリバリアントに名称、画像、発見ルールを指定(07:23):

// Create descriptor for pink dice
let pinkDescriptor = ASDiscoveryDescriptor()
pinkDescriptor.bluetoothServiceUUID = pinkUUID
// Create descriptor for blue dice
let blueDescriptor = ASDiscoveryDescriptor()
blueDescriptor.bluetoothServiceUUID = blueUUID

// Create picker display items
let pinkDisplayItem = ASPickerDisplayItem(
    name: "Pink Dice",
    productImage: UIImage(named: "pink")!,
    descriptor: pinkDescriptor
)
let blueDisplayItem = ASPickerDisplayItem(
    name: "Blue Dice",
    productImage: UIImage(named: "blue")!,
    descriptor: blueDescriptor
)

キーポイント:

  • ASDiscoveryDescriptor は発見ルールを 1 オブジェクトにまとめる。システムは記述子内の全ルールに一致するアクセサリをフィルタ
  • Bluetooth と Wi-Fi の両方をサポートするアクセサリは同一 descriptor に両方のルールを設定可能。1 タップで両方のアクセス権限を取得
  • 異なるバリアント(色違いなど)はそれぞれ独立した descriptor と display item が必要

showPicker() でアクセサリ選択器を表示(08:10):

// Invoke accessory picker
Button {
    session.showPicker(for: [pinkDisplayItem, blueDisplayItem]) { error in
        if let error {
            // Handle error
        }
    }
} label: {
    Text("Add Dice")
}

キーポイント:

  • showPicker(for:) は display item 配列を受け取り、picker は全記述子に対応するアクセサリを同時スキャン
  • picker は独立プロセスで動作。App は Bluetooth スキャンに直接触れない
  • コールバックの error で picker 表示不可(システム制限など)を処理

ユーザーが picker でアクセサリを選択すると、App は accessoryAdded イベントを受信(09:26):

// Handle event
func handleSessionEvent(event: ASAccessoryEvent) {
    switch event.eventType {

    case .accessoryAdded:
        let newDice: ASAccessory = event.accessory!

    case .accessoryChanged:
        print("Accessory properties changed")

    case .accessoryRemoved:
        print("Accessory removed from system")

    default:
        print("Received event with type: \(event.eventType)")
    }
}

キーポイント:

  • .accessoryAddedASAccessory オブジェクトを含み、ペアリング済みアクセサリの全情報を保持
  • .accessoryChanged はアクセサリ属性変更時(設定で表示名を変更など)に発火
  • .accessoryRemoved はユーザーまたは App がアクセサリを削除したときに発火

ペアリング完了後、CoreBluetooth でアクセサリと通信(10:22):

// Connect to accessory using CoreBluetooth
let central = CBCentralManager(delegate: self, queue: nil)

func centralManagerDidUpdateState(_ central: CBCentralManager) {
    switch central.state {
    case .poweredOn:
        let peripheral = central.retrievePeripherals(withIdentifiers: [newDice.bluetoothIdentifier]).first
        central.connect(peripheral)
    default:
        print("Received event type \(event.eventType)")
    }
}

func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
    peripheral.delegate = self
    peripheral.discoverServices(pinkUUID)
}

キーポイント:

  • Info.plist で AccessorySetupKit サポートを宣言しているため、Bluetooth 権限の要求は不要
  • CBCentralManager の状態は App にペアリング済みアクセサリがある場合のみ .poweredOn になる
  • ASAccessorybluetoothIdentifier から CBPeripheral 識別子を取得し、retrievePeripherals(withIdentifiers:) で peripheral オブジェクトを取得
  • スキャン API も利用可能だが、App とペアリング済みのアクセサリのみ返す

既存アクセサリの移行には ASMigrationDisplayItem を使用(11:58):

// Create migration items
let pinkMigration = ASMigrationDisplayItem(name: "Pink Dice", productImage: UIImage(named: "pink")!, descriptor: pinkDescriptor)
pinkMigration.peripheralIdentifier = pinkPeripheral.identifier

// Present picker with migration items
session.showPicker(for: [pinkMigration]) { error in
    if let error {
        // Handle error
    }
}

キーポイント:

  • ASMigrationDisplayItemASPickerDisplayItem のサブクラス。既存アクセサリを AccessorySetupKit 管理へ移行
  • peripheralIdentifier を既存 CBPeripheral の identifier に設定
  • showPicker が移行項目のみの場合、システムは移行を通知する情報ページを表示。非移行項目と混在する場合、ユーザーが新しいアクセサリを選択・設定したときのみ移行が発生

製品画像の表示にもデザイン規範あり。picker は製品画像に 180×120 pt のコンテナを提供。画像背景は透明にし、ライト/ダークモードに対応。透明ボーダーの幅がコンテナ内のスケーリングに影響——ボーダーが広いほどアクセサリは小さく見える(12:54)。

重要ポイント

  • 何をするか:Bluetooth/Wi-Fi アクセサリ App に AccessorySetupKit を導入し、従来の Bluetooth 権限要求フローを置き換え。なぜ価値があるか:ペアリングを多段階から 1 ステップに短縮し離脱率を下げ、プライバシーも向上——App はグローバル Bluetooth 権限が不要。始め方:Info.plist に AccessorySetupKit - Supports と発見ルールを追加。ASAccessorySession を作成。ASPickerDisplayItem で表示項目を設定。showPicker() を呼び出し。

  • 何をするか:既存アクセサリ App に移行フローを実装し、旧権限モデルから AccessorySetupKit 管理へ移行。なぜ価値があるか:Bluetooth 権限を既に許可した既存ユーザーは自動移行されない。移行しないと新しい権限管理の細かい制御を享受できない。始め方ASMigrationDisplayItem に既存 peripheral の identifier を渡し、showPicker で移行プロンプトを表示。

  • 何をするか:picker 内の表示素材を最適化し、ライト/ダークモードで製品画像が鮮明に。なぜ価値があるか:picker の製品画像はユーザーがアクセサリを識別・検証する主要手段。画像の不鮮明さはペアリング完了率に直結。始め方:180×120 pt コンテナサイズの高解像度画像を準備。背景透明、透明ボーダー幅でスケール調整。両モードで視覚テスト。

  • 何をするか:Bluetooth と Wi-Fi の両方をサポートするアクセサリは、1 つの discovery descriptor に両インターフェースルールを設定。なぜ価値があるか:1 タップで Bluetooth と Wi-Fi の両アクセス権限を取得。2 回のペアリングフローを回避。始め方:同一 ASDiscoveryDescriptorbluetoothServiceUUID と Wi-Fi SSID を設定。picker が両技術のペアリングを自動処理。

関連セッション

コメント

GitHub Issues · utterances