こんにちは!
梅雨で雨の日が続いていますが皆さんいかがお過ごしですか?
さて、今回は iOS14 から新しく導入される WidgetKit についてまとめていこうと思います!
WidgetKit
Smart Stacks
ウィジェットの集合体で、自動的に回転して一番上に正しいウィジェットを表示してくれる。ユーザーがスワイプして切り替えることも可能。
自身でスワイプして表示を変えたり、自動回転をオフにすることもできる。
WidgetKit API
ウィジェットで関連性の高い状態になるタイミングや、他のものになるかもしれないタイミングをシステムに知らせる事ができる。
Widget のサイズについて
小・中・大 の3つのサイズがある。ただし、すべてのサイズをサポートしなくてもよい。ただ、できるだけ多くのサイズに対応させた方がよい。
WidgetKit のUI
すべて Swift UI で作られている。SwiftUIはDynamic TypeやDark Modeのような機能をほぼ自動的にサポートすることができる。
情報の更新が可能
Widgetを更新するためには、
- アプリから更新命令
- 定期的な更新スケジュール設定
という2つの方法がある。
アプリから更新した場合は、新しい更新スケジュール設定をすることになる。
WidgetKitについて詳しく
WidgetKitの4つのコンセプト
- Kind
- Configuration
- SupportedFamilies
- Placeholder
Kind
WidgetKitでは1つのextensionで複数のWidgetを構築可能。
例として、株価アプリの場合
- 複数の株価をサマリで確認できるWidget
- 1つの株価の詳細を確認できるWidget
といった具合。
Configuration
Widgetについての設定は2種類存在する。
- StaticConfigurations
- IntentConfigurations
フィットネスアプリはユーザーが個別で設定させる項目がないのでStaticConfigurations、天気アプリではユーザーが見たい情報をある程度設定できる様にするためにIntentConfigurationsを設定する。
SupportedFamilies
WidgetKitでは3種類のサイズでWidgetを作ることができる。
- systemSmall
- systemMedium
- systemLarge
デフォルトではすべてのサイズをサポートしている。
Placeholder
どんなKindのWidgetも必ずこのPlaceholderが必要になる。
Placeholder UIはデフォルトのコンテンツが入ったUI。
ここにはユーザーデータを含めてはいけない。
そのWidgetがどんなUIかを分からせるために存在する。
いつ必要とされるかの保証はされないが、環境設定が変わった時に呼ばれる。
例えばダイナミックタイプが変わった時(文字サイズの変更)。
コードを見てみる
Widgetを構築するポイント
状態を持たないUIを構築することが重要。SwiftUIはそれにとても適している。
音楽の再生、ボタンでの操作などは組めない。
できるのはWidgetをタップしてDeeplinkを開くこと。
systemSmall Widget は全体が1つのタップターゲットになっている。
systemMedium, systemLargeは2つ以上のタップターゲットを仕込める。
Deeplinkのリンク自体はwidgetURL APIを使用する。
3つのViewのUI体験
3つのUI体験について考える必要がある。
Placeholder UIについては上で述べたので割愛。
- Placeholder UI
- Snapshot
- Timeline
SnapshotとTimelines
システムが迅速に表示するための1つのEntry。
可能な限り素早くViewを返すことが望まれている。
実際のユーザーデータを使う。
ほとんどの場合、タイムラインの最初のエントリーやSnapshotは同じになる。
TimelineはView+Dateで構成される。
どの時間で何を表示すれば良いかを表すデータとなる。
Timelineの返却値はDark ModeとLight Modeをサポートする必要がある。
WidgetKit ExtensionがEntryを返す時、Timeline情報を取り出し、ビュー階層をシリアライズしてディスクに保存する。
これはその時々で独立したエントリーを描画するということを意味する。
これによりシステムが数あるWidgetを同時にいくつもあるタイムラインと同時に起動させられる。
Reloads
通常は1日のコンテンツを表示するためのビューを返せば良いが、Widgetを更新しなければならないタイミングも存在する。
この更新のことをReloadsと呼ぶ。
Reloadはシステムが Extensionに対して、新しいタイムラインを問い合わせることをいう。
Timeline Provier Protocolは以下。(2020/07/26時点の情報)
TimelineEntry
... 主に日付情報で構成されている。
Context
... 環境情報を提供する。システムがEntryを要求するコンテキストのこと。
func snapshot()
... システムが単一のEntryを呼ぶためのメソッド。
func timeline()
... システムが連続のEntryを呼ぶためのメソッド。
timelineを生成する時に、ReloadPolicyを設定している。
Reload Policy
システムに次のタイムラインを要求させるタイミングを定めたもの。
- atEnd
- after(date: Date)
- never
システムによるリロードは次のタイミングで実行される。
- ReloadPolicy
- 頻繁に追加のリロードが走る(システムにより適当なタイミングで実行?)
環境設定が変わった時
に関してユーザーはBackground Notificationを使い、Widget Center経由のWidgetKit APIを使用してExtensionを起動させられる。
本アプリ自体で情報変更があったタイミングでもリロードさせることができる。
WidgetCenter
- reloadTimelines(ofKind:)
- reloadAllTimelines
- getCurrentConfigurations(completion:)
また、より多くの情報を得るためにサーバへ問い合わせする場合には、 onBackgroundURLSessionEvents を使って拡張機能に配信することができる。
Personalizations
2つの大きなコンセプトが存在する。
Intent
... Widgetに指定するユーザー設定
Relavance
... スタックの中で開発者に情報を与えるもの
Intent framework
Intentはユーザーへの質問セットのパラメータを持つ。
例として、天気アプリではユーザーにどの場所の予報を提供するかを問う。
Intents frameworkは既にSiri Shortcutで使用されており、iOS14でもWidget設定として用いられている。
Intelligence
SmartStackで多くのウィジェットを回転させることができ、より関連度の高いウィジェットを表示することができる。アプリや、ウィジェットはこの決定に関わる部分に働きかけることができる。
そのためには2種類の方法がある。
- Shortcuts donation
- Timeline Relevece API
Shortcuts donation
アプリで特定のアクションを起こすと、ショートカットを提供することができる。
Widgetが同じINIntentでバックアップされている場合、ユーザーが同一アクションを実行した時にウィジェットがスタックで出現することがある。
Timeline Relevance API
Widget Extensionから Timeline Relevance APIを使ってTimeline Entryの関連度を注釈する機能がある。
時間と Entryをもとにscoreとdurationを返す。
duration
... そのEntryが関連度が持続する時間
score
... これまでに提供された相対値(Float)
システムは他のアプリも含めこの相対値を判断し、スタック内で回転する正しいウィジェットを決定する。