ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
AccessorySetupKitについて
AccessorySetupKitを使用して、アクセサリのセットアップ体験を向上させましょう。BluetoothまたはWi-Fiアクセサリの画像が挿入された美しいペアリングダイアログが表示されるため、設定アプリに切り替える必要がありません。特定のアプリのみをアクセサリとペアリングして、プライバシーを強化する方法を確認しましょう。既存のアクセサリを移行して、AccessorySetupKitで管理できるようにする方法も解説します。
リソース
-
ダウンロード
こんにちは AppleのBluetoothチームのYixinです
今日は AccessorySetupKitによる アクセサリセットアップ体験の向上 について説明します 最初に概要を説明し
APIについて掘り下げたうえで サンプルアプリを作成していきます
最後に アクセサリーピッカーで アクセサリを見栄えよく 表示する方法を紹介します
では 概要から始めましょう
アクセサリは私たちの生活に 非常に重要なものとなっています 健康状態をモニタリングする フィットネストラッカーから アートを形にするクリエイティブツールまで 様々なものがあります iOS 18とiPadOS 18には アクセサリのセットアップ体験を さらに向上させるための機能が 追加されています
今回導入されたAccessorySetupKitは Bluetooth/Wi-Fi対応のアクセサリを 効率的かつプライバシーに配慮した方法で 設定および管理するための まったく新しいフレームワークです
APIを呼び出すだけで 新たに導入されたアクセサリピッカーが開き アプリとペアリングできる 周辺のアクセサリが表示されます このピッカーには アクセサリを表す 忠実度の高い 独自のアートワークと わかりやすい名前が表示されます
1回タップするだけで アクセサリが安全にアプリとペアリングされ すぐに使える状態になります アクセサリが対応していれば この1回のタップでアクセサリから BluetoothとWi-Fiの両方に アクセスできるようになります
アプリでは 引き続きCoreBluetooth APIと NetworkExtension APIを使用して アクセサリと通信できます
> の 新しいには AccessorySetupKitによって管理される すべてのアクセサリが表示されます 各アクセサリの詳細ページでは 製品の画像 表示名 ハードウェア名により 簡単にアクセサリを識別できます
ユーザーはアクセサリ名を変更したり ペアリング対象アプリのアクセスを切り替えたり システムから削除したりできます
新しいデザインのアクセサリページは アクセサリが対応している テクノロジーに応じて Bluetooth設定と Wi-Fi設定でも確認できます
iOS 18/iPadOS 18では AccessorySetupKitは Bluetoothと Wi-Fi対応のアクセサリをサポートします その仕組みを確認しましょう まず 従来のアプリでの アクセサリの設定方法と AccessorySetupKitとの違いを確認します
これまでアプリは Bluetoothの使用許可をリクエストして アクセサリを検出し 接続していました
アクセサリがブロードキャストしている Wi-Fiネットワークに参加するには 別途許可を求める必要がありました
さらにBluetoothペアリングも 要求する必要がありました これに対して AccessorySetupKitでは デベロッパとユーザー両方の 負担が軽減されます 1回タップするだけで アクセサリがアプリとペアリングされ BluetoothとWi-Fi両方でアプリから アクセサリにアクセスできるようになります 新しいアクセサリピッカーでは 何を許可するのかを ユーザーがこれまで以上に簡単に確認できます アクセサリのわかりやすい名前と 製品画像に加え アクセサリが無線で広告する ハードウェア名も表示されるため タップして設定を開始する前に 正しいアクセサリかどうかを確認できます これを実現しているのが AccessorySetupKitの プライバシーに配慮したデザインです
アプリの前面に表示される アクセサリピッカーは 別のプロセスで実行されます アプリは検出ルールとアセットを ピッカープロセスに送信します これらのルールにはBluetoothとWi-Fi両方の インターフェイスを含めることができるため 1つの設定フローで アクセサリとの通信に必要な すべてのアクセス許可を取得できます
アクセサリが検出されると それがピッカーに表示され 1回タップするだけで アプリとペアリングできます
ここまでがAccessorySetupKitの概要です 次はAPIを見ていきましょう ここではデジタルサイコロを 扱うアプリを作成します サイコロで出た目をBluetoothで同期します このサンプルプロジェクトは ダウンロードすることもできます このアプリではCoreBluetoothを使用して デジタルサイコロをシミュレーションします サンプルアプリはCoreBluetoothに接続して Bluetooth GATTサービスに サブスクライブします
AccessorySetupKitを使用するには アプリのInfo.plistにエントリを追加します AccessorySetupKit - Supportsの下に Bluetoothを追加します これにより サンプルアプリが サイコロとやり取りできるようになります Wi-Fiもこの配列でサポートされています 次に アクセサリを検出するための ルールを追加します Bluetooth Services、Wi-Fi SSID またはCompany Identifiersです このサイコロは2色あります それぞれ広告する サービスUUIDが異なるため Bluetooth Servicesの下に 2つのUUIDを追加します アプリでアクセサリを使用するには 3つの手順を実行します アクセサリの検出 アクセサリの使用の認可 アクセサリとの通信です このうち検出と認可は AccessorySetupKitで対応できますが 通信については これまでのバージョンのiOSと同様に CoreBluetoothとNetworkExtensionで 処理します
AccessorySetupKitで 最初に使用するクラスは ASAccessorySessionです
これは アクセサリピッカーの表示 イベントの通知 アクセサリの管理を担う 中心的なオブジェクトです
ASAccessorySessionに ピッカーを表示するよう要求するには ASPickerDisplayItemオブジェクトの 配列を指定します
ASPickerDisplayItemでは アクセサリの名前と画像 および検出記述子を定義して スキャン方法を指定します
これにより ASAccessorySessionで showPickerを呼び出して ピッカープロセスで 検出と認可を開始できます 設定が完了すると アプリはセッションオブジェクトを介して ASAccessoryEventを受け取ります このイベントには 新しく追加されたアクセサリと アプリがやり取りする際に 必要となる情報が含まれています
コードを見てみましょう
先ほど説明したように まずASAccessorySessionを作成します
このセッションは DispatchQueueでアクティブ化され そこでAPI呼び出しを実行します また アプリがセッションからのイベントの 処理に使用するeventHandlerを指定します
セッション アクセサリ またはピッカーに関する 更新情報があると ASAccessoryEventが イベントハンドラに渡されます イベントには様々な種類があり eventTypeを確認することで 識別できます activatedイベントを セッションから accessoriesプロパティを読み取ることで アクセサリに対してクエリを実行したり 新しい設定プロセスを開始するための 信号として使用します イベントの処理については 後ほど詳しく説明します 次に 設定プロセスを 開始する方法を見てみましょう ピッカーの表示項目を作成して アクセサリピッカーを呼び出します
表示項目を作成するには 製品名 製品画像 検出記述子が必要です ASDiscoveryDescriptorクラスでは 必要なすべての検出ルールを 1つの複合オブジェクトに まとめることができます システムはスキャン結果と ディスクリプタ内のすべてのルールを照合し 対象とするアクセサリを絞り込みます ASDiscoveryDescriptorは柔軟性が高く BluetoothサービスUUIDや Wi-Fi SSIDなど多数の カスタマイズ可能なフィールドがあります 詳しくはdeveloper.apple.comの ドキュメントをご覧ください
サイコロを検出するには 検出記述子で bluetoothServiceUUIDを サイコロによってアドバタイズされる GATTサービスUUIDとして設定する必要があります
ピンクのサイコロとブルーのサイコロでは 色によってアドバタイズされる サービスUUIDが異なるため 色ごとのサービスUUIDを使用して それぞれの検出記述子を 作成する必要があります
次に サイコロの2色のバリエーションの 表示項目を作成するため 名前 画像 対応する検出記述子を渡します これにより 2色のバリエーションが 別々のアクセサリとして識別されます
ASPickerDisplayItemには 他にもプロパティがあり それらを使用して 設定環境をカスタマイズできます 詳細はドキュメントをご覧ください 最後に このサンプルアプリに ボタンを1つ追加します このボタンは アクティブ化された セッションでshowPickerを呼び出し ピンクとブルーのサイコロ用に 作成した表示項目を渡します この時点でアクセサリピッカーが表示され 検出と設定のプロセスが開始されます やってみましょう
デスク上のiPhoneはピンクのサイコロを シミュレートしています サンプルアプリで ボタンをタップすると アクセサリピッカーが アプリの前面に表示されます ピンクのサイコロがすぐに検出され 表示されます シミュレーション用の別のiPhoneで ブルーのサイコロをオンにすると それが検出されて 画面の端に アニメーションの一部が表示されます ピッカーに水平方向のカルーセルが作成され 複数のアクセサリが整然と表示されます 左右にスワイプして 今回設定するサイコロを選択できます どちらの色も可愛いのですが やはりピンクは魅力的です ピンクのサイコロを設定しましょう 接続中になり・・・完了です これでピンクのサイコロを アプリで使えるようになりました あっという間です
アクセサリピッカーにはBluetooth ペアリング用の様々なUIが表示されます アクセサリでより安全な ペアリング手法が必要な場合は 数字の比較やパスキーの入力などを 使用できます ピンクのサイコロが設定できたら 次は何でしょうか
アクセサリの使用準備ができると アプリは accessoryAddedイベントを受け取ります このイベントのaccessoryプロパティを 読み取ることで 新しく設定したサイコロを表す ASAccessoryオブジェクトを取得します 他のイベントには accessoryChangedなどがあります これは表示名など アクセサリのプロパティが 変更された場合に送信されます アクセサリのプロパティは で変更できます accessoryRemovedが送信されるのは ユーザーまたはアプリによって アクセサリがシステムから 削除された場合です
ASAccessoryクラスは 物理的なアクセサリを表します ここにはアクセサリの認可状態 表示名 検出記述子が含まれます また CBPeripheralのBluetooth識別子や Wi-Fiネットワークを ブロードキャストする場合のWi-Fi SSIDなど すべてのネットワークインターフェイスも 含まれます accessoryAddedイベントの ASAccessoryオブジェクトにより CoreBluetoothを使用して Bluetooth周辺機器に接続できます
いつものように CBCentralManagerを作成します Info.plistでAccessorySetupKitの サポートを宣言しているため 従来バージョンのiOSとは異なり ユーザーはBluetoothの 使用の許可を求められません
CBCentralManagerの状態が poweredOnになるのは アプリでアクセサリが ペアリングされている場合だけです ここではピンクのサイコロが AccessorySetupKitとペアリングされています ピンクのサイコロのBluetooth 周辺機器を取得するには bluetoothIdentifierを使用します もちろん いつでもセントラルマネージャの スキャンAPIを使用して 周辺機器をスキャンできます スキャン結果で返されるのは アプリと ペアリングされているアクセサリのみです 次に周辺機器と接続します 接続したら その周辺機器の GATTサービスを検索して 読み取りと更新通知の 受け取りができるようにします
アプリからBluetoothアクセサリに 初めて接続する場合は developer.apple.comにある CoreBluetoothのドキュメントをご覧ください それでは 新しく設定したピンクの サイコロに接続してみましょう
サンプルアプリから サイコロシミュレータに接続できます シミュレータアプリを起動して 動かしてみましょう
いいですね サイコロの結果はリアルタイムで サンプルアプリに同期されます AccessorySetupKitを使って アクセサリを設定し 既存のネットワークAPIを使って 接続する方法を説明しました しかし アプリが既に Bluetooth使用の認可を受けており AccessorySetupKitなしで 既存のアクセサリを管理できるとしたら? そのアクセス許可モデルから AccessorySetupKitの きめ細かいモデルにアプリを移行するには どうすればよいでしょうか
既存のアクセサリの Bluetooth周辺機器識別子 またはWi-Fi SSIDを使用して ASMigrationDisplayItemの インスタンスを作成できます これはASPickerDisplayItemの サブクラスとなります showPickerの呼び出しで これらの移行項目を引数として渡し 既存のアクセサリをアップグレードして AccessorySetupKitで管理されるようにし 新しいアクセサリの設定に 表示されるようにします showPickerの呼び出しに 移行項目のみが含まれていた場合 アプリの前面に情報ページが表示され 移行についてユーザーに通知されます 移行項目とともに 移行対象でないその他の表示項目も 渡すことにした場合 新しいアクセサリが 検出されて設定される場合のみ 移行が行われます
このような方法で 既存のアクセサリを移行して AccessorySetupKitで 管理されるようにします 今日のセッションのまとめに入る前に アクセサリの設定環境を 向上させるうえで本当に役立つ デザインに関する推奨事項を いくつか紹介します
アクセサリピッカーには 180x120ポイントの大きさの コンテナボックスがあり そこに製品画像が表示されます 倍率にかかわらず 画面上に鮮明に表示されるように 画像のピクセル解像度が 十分であることを確認しましょう
アセットの表示は ライトモードと ダークモードの両方でテストします どちらのモードでも適切に表示されるように 画像の背景は透明にする必要があります
画像の周囲に透明な境界線を付けます システムで画像全体のサイズを コンテナボックスに合わせる際 透明な境界線の幅が広いほど 画面上に表示されるアクセサリの サイズが小さくなります 透明な境界線を調整し パディングとして利用することで ピッカーのUIで画像が 最適なサイズで表示されるようにします
ユーザーがアクセサリを設定する際 アクセサリピッカーによってアプリのUIが 一部見えなくなることに留意してください 設定中 見えない可能性のあるUIを 更新しないようにします pickerDidPresentと pickerDidDismissイベントを検知して ピッカーの表示と消去を追跡できます
もう1つ重要なこととして showPicker APIはいつでも 呼び出すことができますが 想定外のピッカーが 表示されることのないように ピッカーの表示前に 新しいアクセサリの 追加に関する十分な背景情報を ユーザーに提示することをお勧めします また可能であれば showPickerの 呼び出しをボタンにバインドして 設定画面は必ず ユーザーの操作によって 表示されるようにします
最後に今日のセッションの重要ポイントを いくつか振り返りましょう AccessorySetupKitはBluetoothとWi-Fi対応 アクセサリを設定するための斬新な方法です 1回タップするだけで BluetoothとWi-Fiの両方で アプリからアクセサリにアクセスできます ユーザーがそのアプリに初めて触れる 重要なタイミングで 余計な負担が生じるのを回避できます
使用するには AccessorySetupKitの項目を アプリのInfo.plistに追加します ASAccessorySessionを作成して アクティブ化されるのを待ち タスクを開始します 検出するアクセサリごとに ASPickerDisplayItemを作成します アクセサリピッカーを表示して 設定のプロセスを開始し イベントに適切に対応します アプリで既にシステムアクセスを利用して 既存のアクセサリを管理している場合は ASMigrationDisplayItemを使用して アクセサリをAccessorySetupKitに移行します アセットのデザインに注意を払い できる限り最適な形で アクセサリがピッカーに 表示されるようにします
ご視聴ありがとうございました
-
-
6:02 - Register event handler
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)") } }
-
7:23 - Create picker display items
// 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 )
-
8:10 - Show picker
// Invoke accessory picker Button { session.showPicker(for: [pinkDisplayItem, blueDisplayItem]) { error in if let error { // Handle error } } } label: { Text("Add Dice") }
-
9:26 - Handle events
// 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)") } }
-
10:22 - Communicate with accessory
// Connect to accessory using CoreBluetooth let central = CBCentralManager(delegate: self, queue: nil) func centralManagerDidUpdateState(_ central: CBCentralManager) { switch central.state { case .poweredOn: // state will only be updated to poweredOn when you have paired accessories 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) }
-
11:58 - Migrate existing accessories
// 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 } }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。