【iOS】ActivityKitでLive Activityを表示する

ActivityKitはLive Activityを開発するためのフレームワークです。Live Activityとは、Appの最新情報をロック画面やDynamic Islandに表示するための機能で、Appを起動していなくても最新の情報をユーザに提供することができます。

本記事ではDynamic Islandとロック画面にLive Activityを表示し、表示内容の更新、表示を停止するための実装方法について書きます。
Live Activityの表示形状タイプ
Live Activityの表示形状タイプはいくつかの種類があります。アクティブなLive Activityの数や、画面の表示状態によってiOSが表示形状タイプを自動的に切り替えます。
Compact

アクティブなLive Activityが一つだけの時、Live ActivityはCompactタイプで表示されます。Compactタイプは2つのView領域で構成されています。1つはTrueDepthカメラの前端のLeading side、もう1つは末尾側のTrailing sideです。
Minimal

アクティブなLive Activityが二つ以上の時、Live ActivityはMinimalタイプで表示されます。先に実行されたLive Activityがattached領域に、後に実行されたLive Activityがdetached領域に表示されます。
Expanded

Live Activityをロングタップした時、Live ActivityはExpandedタイプで表示されます。Expandedタイプは複数のView領域で構成されており、Compactタイプと比べてより多くの情報を表示することができます。
ロック画面

ロック画面時は画面下部にLive Activityが表示されます。
Live Activityの実装
Live Activityを実装するには、既に追加されたWidget Extension内のソースファイルにコードを追加するか、新規でWidget Extensionをプロジェクトに追加する必要があります。Live ActivityのユーザインターフェースはWidgetKitとSwiftUIを使用して構築します。
Widget Extensionの追加
AppにLive Activityを追加するために、Widget Extensionをプロジェクトに追加します。File -> New -> Targetの順に選択すると以下のようなターゲット一覧ダイアログが表示されます。

この中からWidget Extensionを選択すると、Widget Extensionに関する情報を入力するダイアログが表示されます。Product Nameに任意の名前を指定、Include Live Activityにチェックをつけます。

Live Activityの有効化
ホストApp側のInfo.plistファイルにSupports Live Activitiesキー(NSSupportsLiveActivities )を追加し、対応する値にYES を設定します。

Live Activityに表示する情報の定義
Live Activityに表示する情報はActivityAttributes に準拠した構造体で定義します。静的な情報は構造体のプロパティで定義し、動的な情報は構造体内で定義したCodable , Hashable プロトコルに準拠するContentState 構造体のプロパティで定義します。
Live Activityの定義
Live ActivityはWidget プロトコルに準拠した構造体で定義し、body プロパティにActivityConfiguration オブジェクトを返すコードを記述します。for 引数には前項で作成したActivityAttributes に準拠した構造体名を指定します。第二引数にはActivityViewContext< Attribute > オブジェクトを引数とする、ロック画面に表示するLive Activity Viewを返すクロージャを指定します。ActivityViewContext< Attribute > にはLive Activityに表示するための情報が格納されており、クロージャ内でLive Activity Viewを生成する時に使用することができます。最後のdynamicIsland 引数には、ActivityViewContext< Attribute > を引数とするDynamicIsland 型のオブジェクトを返すクロージャを指定します。
DynamicIsland
DynamicIsland 型のオブジェクトにDynamicIslandで表示するViewを定義します。
Compact

compactLeading 引数にはLeading side領域に表示したいViewを返すクロージャを 、compactTrailing 引数にはTrailing side領域に表示したいViewを返すクロージャを指定します。
Expanded

Leading、Trailing、Center、Bottom各領域に表示するViewを返すクロージャを引数に設定した、DynamicIslandExpandedRegion 型のオブジェクトを生成し、DynamicIsland クラスの引数に指定します。

以上でLive Activityの実装は完了です。
Live Activityはホーム画面/ロック画面ウィジェットと違い、タイムラインは存在しません。Live Activityを開始するには、ホストAppでLive Activity開始のリクエスト処理を行う必要があります。
Live Activityの開始
iOS 16.1以前
Live Activityを開始するために、Live Activityに表示する情報を生成します。
DeliveryAttributes オブジェクトに静的な情報を、DeliveryAttributes.ContentState に動的な情報を引数に指定してオブジェクトを生成します。生成したそれぞれのオブジェクトをActivity クラスのrequest メソッドの引数に指定して実行するとLive Activityが開始します。
iOS 16.2以降
iOS 16.2以降からは、request メソッドの引数contentState: がcontent: に変更されました。content: にはActivityContent<Activity<Attributes>.ContentState> オブジェクトを指定します。上記のサンプルコードでは省略形で記述していますが、省略なしで記述した場合、以下のようなコードになります。
ActivityContent<Activity<Attributes>.ContentState> のinit の引数state: にはContentState オブジェクトを、staleDate: には表示しているLive ActivityのActivityState をstale に変更する日付をDate? オブジェクトで指定します。ActivityState をstale に変更する必要がない時は、nil を指定します。

Live Activityの更新
iOS 16.1以前
DeliveryAttributes.ContentStateを生成し、Activity クラスのupdate メソッドの引数に指定して実行するとLive Activityに表示する情報を更新することができます。
iOS 16.2以降
iOS 16.2以降からは、update メソッドの引数using: がcontent: に変更されました。content: にはActivityContent<Activity<Attributes>.ContentState> オブジェクトを指定します。

Live Activityの停止
iOS 16.1以前
DeliveryAttributes.ContentState を生成し、Activity クラスのend メソッドの引数に指定して実行するとLive Activityを停止することができます。
iOS 16.2以降
iOS 16.2以降からは、end メソッドの引数using: がcontent: に変更されました。content: にはActivityContent<Activity<Attributes>.ContentState> オブジェクトを指定します。

ホストApp側のサンプルソースは以下になりますので、必要に応じてご参照ください。
iOS 16.1以前
iOS 16.2以降
参考情報
Dynamic Islandサイズ仕様
| 表示形状タイプ | 機種 | Dynamic Islandの幅 (pt) |
|---|---|---|
| Compact or minimal | iPhone 14 Pro Max | 250 |
| iPhone 14 Pro | 230 | |
| Expanded | iPhone 14 Pro Max | 408 |
| iPhone 14 Pro | 371 |
Live Activityサイズ仕様
| 画面解像度 (ポートレート) | Compact leading | Compact trailing | Minimal | Expanded | ロック画面 |
|---|---|---|---|---|---|
| 430x932 | 62.33x36.67 | 62.33x36.67 | 36.67–45x36.67 | 408x84–160 | 408x84–160 |
| 393x852 | 52.33x36.67 | 52.33x36.67 | 36.67–45x36.67 | 371x84–160 | 371x84–160 |
参考資料
ActivityKit
Human Interface Guidelines > Live Activities.
Discussion