every Tech Blog

株式会社エブリーのTech Blogです。

iOS ウィジェットのまとめ

iOS ウィジェットのまとめ

iOSのウィジェットは、iOSのアップデートに伴い配置場所と機能が拡充されてきました。ウィジェットを開発する上で適切な技術を選択するための情報として、その変遷と各OSバージョンにおいて利用可能な機能を整理しました。

レガシーなウィジェット TodayExtension (iOS 8〜iOS 17)

初期のウィジェットは、ホーム画面ではなく、通知センター(ホーム画面を右にスワイプして表示される画面)に配置されていました。制約が比較的少なく、アプリに依存せずウィジェット内で機能を完結させることもできました。

iOS 14でWidgetKit が導入された後も引き続きサポートされていましたが、iOS 18でサポートが終了しました。そのため、アプリにToday Extensionが含まれていても、iOS 18以降では利用できません。

ホーム画面ウィジェット(iOS 14〜)

iOS 14で WidgetKit が提供され、ホーム画面に配置するウィジェットを作れるようになりました。 ウィジェットのUIはSwiftUIで作成します。 WidgetKitはウィジェットの管理と表示更新の仕組みを提供します。

表示更新の仕組み

ウィジェットは、システムリソースの過剰消費やバッテリーの消耗を抑制し、デバイスのパフォーマンスを維持するため、いくつかの制約が設けられています。

ウィジェットに表示するデータの取得と表示内容の決定は、メインアプリケーションまたは専用のバックグラウンドプロセスで実行する必要があります。時刻に応じてウィジェットの表示を切り替える必要がある場合は、事前に更新日時と表示内容を計画したタイムラインを作成します。

タイムラインは、 TimelineProvider によって生成され、 TimelineEntry オブジェクトの配列と TimelineReloadPolicy で構成されます。各 TimelineEntry は、 WidgetKit がウィジェットの表示を更新する date を指定し、表示に必要な追加データを含めることができます。これにより、ウィジェットをいつ、どのようなデータで更新するかを事前に計画します。

タイムラインの更新頻度はOSによって管理されており、開発者が直接制御することはできません。アプリから reloadTimelines() を使用して更新を要求できますが、即時実行は保証されません。更新頻度は、ユーザーのアクティビティ、バッテリー残量、ネットワーク接続などの要因によって変動します。

ウィジェットは静的なスナップショットとして表示されるため、継続的な更新には適していません。定期的に変化する情報の表示に適しており、リアルタイム更新が求められる場合はライブアクティビティの利用が推奨されます。

本体アプリとの連携

ウィジェットと本体アプリの間でデータを共有するためには App Groups を利用します。App Groups を作成し、ウィジェットと本体アプリの両方で共通の App Groups を有効にすることによって、User Defaults, File Manager, Core Data, Swift Dataでデータを共有できます。

UserDefaults

UserDefaults は、ユーザー設定や小規模なデータセットの保存に適しています。 データは自動的にシリアライズされ、同期的にアクセスされます。そのため、UserDefaults はアプリケーションとそのウィジェット間で基本的な構成や状態情報を共有するのに便利です。 ただし、大規模なデータを扱うとパフォーマンス上の問題が生じる可能性があるため、そのような場合には CoreData や SwiftData の利用が推奨されます。また、機密性の高いデータには Keychain が適しています。

CoreDataとSwiftData

より複雑なデータモデルと大規模なデータセットを扱う場合、 CoreData または SwiftData を使用して永続データを共有できます。

SwiftDataは、CoreDataよりも簡潔なコードで記述でき、モデルのマイグレーションも容易かつ安全に行えるため、iOS 17以降をターゲットとするのであれば SwiftData を使うのが良さそうです。

ロック画面ウィジェット(iOS 16〜)

iOS 16では、ロック画面にウィジェットを配置できるようになり、これはホーム画面のウィジェットと同様の実装に基づいていますが、ロック画面特有の制約も存在します。

ロック画面のウィジェットは、基本的にモノクロ表示に限定されています。また、ウィジェットのサイズは accessoryInline (1行テキスト)、 accessoryCircular (円形)、accessoryRectangular (長方形)の3種類がありますがいずれもホーム画面ウィジェットよりも領域が狭いです。これらの表示上の制限に合わせて情報の取捨選択やレイアウトを工夫する必要があります。

さらに、プライバシーに関する考慮が必要です。ロック画面はロック中でも情報が表示されるため、個人情報や機密性の高い情報を表示する場合は、ユーザーが設定で表示/非表示を切り替えられるようにするなど、適切な対応が求められます。

ライブアクティビティ(iOS 16.1〜)

ウィジェットは静的あるいは定期的な情報更新に適しているのに対し、ライブアクティビティはリアルタイムかつ頻繁な情報更新に強みがあります。

ライブアクティビティは最大8時間のアクティブ表示が可能で、その後最長12時間ロック画面に残ります。この特性から、短中期的なイベントやタスクの追跡に最適です。一方、ウィジェットには表示時間の制約はありません。

両者はWidgetKitを基盤とし、UIはSwiftUIで構築されていますが、リアルタイム性やライフサイクル管理において異なる技術を採用しています。

ウィジェットはタイムラインプロバイダを通じて定期的にデータを更新します。対照的に、ライブアクティビティはActivityKitという専用フレームワークを使用し、アプリからリアルタイムに状態を更新します。バックグラウンドタスクの状態反映には、バックグラウンド動作中のアプリによる状態更新が必要です。

ライブアクティビティはiOSの複数の箇所に表示され、ロック画面ではバナー形式で詳細情報を提供します。iPhone 14 Pro以降ではDynamic Islandにも対応し、コンパクト、最小、拡張の3つの表示形式をサポートします。Dynamic Island非対応デバイスでは、更新時にロック画面上部に一時的なバナーが表示されます。

インタラクティブなウィジェット(iOS 17〜)

インタラクティブウィジェットの導入により、ユーザーはアプリを開くことなく、ホーム画面ウィジェットとロック画面ウィジェット上で直接簡単な操作を実行できるようになりました。

利用可能なインタラクティブなUI要素は、 Button と Toggle の2つに限定されています。

このインタラクティブウィジェットを実現する上で重要なのが、 App Intents フレームワークです。 App Intents を活用することで、アプリがフォアグラウンドで動作していない状態でも、システムが実行可能なアクションを定義できます。

ユーザーがウィジェット内のボタンやトグルを操作すると、システムは対応する App Intent を起動します。App Intent の perform() 関数が実行され、アプリのデータモデルの更新といった必要なアクションが実行されます。 perform() 関数の実行完了後、システムは自動的にウィジェットのタイムラインを更新し、変更内容をウィジェットに反映させます。重要な点として、ウィジェット自体は状態を持たず、App Intent実行後の変更されたデータモデルに基づいてタイムラインが更新されることによってウィジェット表示内容が変化します。

ユーザー操作後、 App Intent の実行とそれに続くタイムラインの再読み込みにより、ウィジェットのUI更新にはわずかな遅延が生じる可能性があります。

コントロールウィジェット(iOS 18〜)

iOS 18 で新たに導入されたコントロールウィジェットは、コントロールセンターやロック画面下部のウィジェット領域から、アプリケーションの機能を直接操作できるようにするものです。

従来のウィジェットがアプリ情報の視覚的な提供を主な目的とするのに対し、コントロールウィジェットは、シンプルで即座に実行できるタスクへのショートカットとしての役割に特化しています。

ボタンは瞬時の単一アクションに、トグルは明確なオン/オフを伴うアクションにそれぞれ用いられ、いずれもアクションの実行にはApp Intentsが活用されます。

コントロールウィジェットは、他のウィジェットと同様にWidgetKitフレームワークを基盤として構築されています。

おわりに

今回の記事ではiOSのウィジェットについて簡単にまとめました。参考になれば幸いです。