🎛️

【iOS 18】コントロールウィジェットの導入 (基礎編)

2024/06/16に公開

コントロールはアプリの機能を、コントロールセンター、ロック画面、アクションボタンに配置することができる機能です。iOS 18からはサードパーティ製アプリも、独自に開発したコントロールをコントロールセンターやロック画面、アクションボタンに配置することができるようになりました。

これから、「Extend your app’s controls across the system」セッションで公開されている内容を、二つの記事に分けて解説します。
https://developer.apple.com/jp/videos/play/wwdc2024/10157/
本記事のシリーズをお読みいただくことで、実際にアプリで動作確認を行いながら、「Extend your app’s controls across the system」セッションで解説されている内容を把握していただくことができます。

本記事では、以下の内容に絞って解説します。

  • アプリにコントロールウィジェットを追加する方法
  • 主要なプロトコルおよび構造体

WidgetKit

WidgetKitは、iOS 14から使用可能なフレームワークです。WidgetKitフレームワークには、ホームスクリーン / コントロール /ロックスクリーンウィジェットといったウィジェットを開発するするためのAPIが定義されています。

Widget Extensionの追加

Widget Extensionは、ウィジェットを作成するためのテンプレートファイルです。
以下の手順に従って、Widget ExtensionをアプリのXcodeプロジェクトにを追加します。

  1. コントロールウィジェットを追加したいアプリのXcodeプロジェクトを開き、[File] > [New] > [Target]の順に選択します。

  2. 「Widget Extension」のテンプレート、[Next]を選択します。

  3. Product Name項目にターゲット名を入力し、「Include Control」にチェックをつけて[Finish]を選択します。

手順3でProduct Name項目に入力した名称のフォルダがナビゲーター領域に表示されていれば、Widget Extensionの追加は完了です。

この時点でビルドを行うと、アプリがiPhoneにインストールされます。コントロールセンターに遷移し、[コントロールを追加]を選択すると、コントロールギャラリーが表示されます。コントロールギャラリーの中から作成したコントロールを選択することで、コントロールをコントロールセンターに追加することができます。

また、コントロールセンターに加えてロック画面にコントロールを配置することもできます。

ファイル構成

Widget Extensionを追加すると、以下の3つのswiftファイルが自動的に追加されます。

各ファイルの概要

  • TestBundle.swift
    アプリで表示したいホーム / ロック画面ウィジェット、ライブアクティビティ、コントロールウィジェットを定義しています。

  • TestControl.swift
    コントロールウィジェットの外観や実行したい処理といった、コントロールウィジェットの実態を定義しています。

  • Test.swift
    ホーム / ロック画面ウィジェットを定義しています。

「TestBundle.swift」、「Test.swift」の内容は、ホーム画面ウィジェットの作成方法を解説している以下の記事をご参照ください。
https://zenn.dev/naoya_maeda/articles/e5c5af8ec567c9

本記事では、「TestControl.swift」の内容に絞って解説します。

ControlWidget

コントロールウィジェットの構成はControlWidget プロトコルに準拠した構造体で定義します。body にコントロールウィジェットの構成を表現する構造体を定義し、その構造体の中でコントロールウィジェットの外観と実行するアクションを定義します。ユーザーがコントロールをロングタップした時に実行するアクションはインテントで定義します。

StaticControlConfiguration

ユーザーがコントロールの構成を変更することができない、静的なコントロールウィジェットを作成するにはStaticControlConfiguration を使用します。StaticControlConfigurationinit<Provider>(kind: String, provider: Provider, content: (Provider.Value) -> Content) で初期化を行います。
kind にはコントロールウィジェットを識別するための文字列、provider にはコントロールウィジェットに値を渡すためのControlValueProvider プロトコル、またはAppIntentControlValueProvider プロトコルに準拠したオブジェクト、content にはコントロールウィジェットを表すControlWidgetToggle 、またはControlWidgetButton オブジェクトを指定します。

ControlValueProvider プロトコル

ControlValueProvider プロトコルは、コントロールウィジェットに値を渡すプロバイダーとしての役割を定義したプロトコルで、previewValuecurrentValue() を定義します。ユーザーがコントロールをコントロールセンターに追加する時、一時的にコントロールウィジェットの外観を、コントロールギャラリーに表示する必要があります。この時、WidgetKitはpreviewValue をシステムに提供し、システムは提供されたpreviewValue を使用してコントロールウィジェットの外観を表示します。その後、非同期で取得した値はcurrentValue() を経由してシステムに提供し、システムはcurrentValue() 経由で取得した値を使用してコントロールウィジェットの外観を更新します。

コントロールウィジェットのタイプ

コントロールウィジェットのタイプは、トグルを表現するControlWidgetToggle と、ボタンを表現するControlWidgetButton が用意されています。

ControlWidgetToggle

ControlWidgetToggle はトグルを表現する構造体です。
上記のコードでは、トグル名は"Start Timer"、トグルの状態を提供するプロバイダには、Provider() 、トグルに変更が入った時に実行するアクションにはStartTimerIntent() インテント、コントロールウィジェットの外観にLabel() を指定しています。

ControlWidgetButton

ControlWidgetButton はボタンを表現する構造体です。
上記のコードでは、ボタンをタップした時に実行するアクションにはStartTimerIntent() インテント、コントロールウィジェットの外観にImage() を指定しています。

SetValueIntent プロトコル

コントロールウィジェットがロングタップされた時に実行するインテントは、SetValueIntent プロトコルに準拠させます。value にコントロールウィジェットに渡したい値を指定し、perform でコントロールがロングタップされた時に実行したい処理を記述します。

本記事では、アプリにコントロールウィジェットを追加する方法と、主要なプロトコルおよび構造体について解説しました。
次回の記事では、ユーザーがコントロールの構成を変更することができるコントロールウィジェットの作成や、コントロールウィジェットの状態をアップデートする方法といった、もう少し深掘りした内容について解説します。
https://zenn.dev/naoya_maeda/articles/f1ab08b3d466f2

参考資料

・Extend your app’s controls across the system
https://developer.apple.com/jp/videos/play/wwdc2024/10157/

Discussion