※この記事は2020/7/28時点のBeta3の情報を元に作成しています。
- 2020/7/25
IntentConfiguration
のinit
でplaceholderを引数に渡すことがdeprecatedになっていたので追記しました。 - 2020/7/28
isPlaceholder(deprecated)
redacted
placeholder
unredacted
について追記しました。 - 2020/8/21
TimelineProvider
のplaceholder(in:)
、Location Permission、 Timelineの間隔、メモリの最大容量について追記しました。 - 2020/8/27 Beta6で
TimelineProvider
のメソッド名や必須項目が変更になった件について追記しました。
iOS14から新しく登場した
WidgetKitを使ってWidgetを作成する機会があり
その際に調べたことや触ってみてわかったことをまとめました。
下記のWWDC2020のセッションを参考にしています。
Meet WidgetKit
https://developer.apple.com/videos/play/wwdc2020/10028/
Widgets Code-along, part 1: The adventure begins
https://developer.apple.com/videos/play/wwdc2020/10034/
Widgets Code-along, part 2: Alternate timelines
https://developer.apple.com/videos/play/wwdc2020/10035/
Widgets Code-along, part 3: Advancing timelines
https://developer.apple.com/videos/play/wwdc2020/10036/
Add configuration and intelligence to your widgets
https://developer.apple.com/videos/play/wwdc2020/10194/
Build SwiftUI views for widgets
https://developer.apple.com/videos/play/wwdc2020/10033/
Design great widgets
https://developer.apple.com/videos/play/wwdc2020/10103/
Widgetとは?
iOS13では
ホーム画面から左にスワイプすると出てくる
通知センターに設定できるViewで
TodayExtensionを利用して
Viewの表示や内容の更新したり
簡単なタスクを実行することができました。
それが
iOS14ではホーム画面にも表示ができるようになり
機能もさらに豊富になりました。
iPadやMacでも
同じように表示することができます。
iOS14で登場したAppライブラリという機能で
アプリのアイコンをライブラリフォルダに
収納することができるようになったことで
ホーム画面をより自由にカスタマイズできるようになり
Widgetを使うことで
より必要な情報を手軽に確認できるようになりました。
Widgetのゴール
WWDCのセッションの中で
下記の3点が
Widgetが目指すものとして掲げられています。
Glanceable
パッと見てすぐに欲しい情報が確認できる
というような意味です。
通常ユーザがホーム画面に止まるのは
ほんのわずかな時間です。
そのため
Widgetで何か操作を求めるなど
情報をパッと確認できること以外を行おうとするべきではない
と言っています。
Appleのアプリでは
下記のような情報が表示されるようになっています。
Relevant
ユーザの関心があるものを適切な時間に表示する
ということのようです。
例えば
- 朝出かける前には今日の天気を知りたい
- 日中の仕事中はタスクのTodoを忘れないようにリマインダーをチェックしたい
- 寝る前にはリラックスできる音楽が聞きたい
などをWidgetでは実現することができます。
また
iPhoneの画面で
全てのWidgetを表示するのはサイズに限界があり
それを解消するために
スマートスタック
という新しい機能が追加されました。
スマートスタック
Widgetのコレクションを
一つのWidgetサイズの中に納め
システムが適切な時間に適切な表示をするように
自動で表示内容を変更できる機能です。
※
自身でスワイプして表示を変えたり
自動回転をオフにすることもできます。
最終的には
システムで何を表示するかの判断はされますが
開発側で何を優先的に表示させたいのかの設定もできます。
※詳細は後ほど記載します。
Personalize
使用しているユーザに合わせてカスタマイズできる
iOS14のWidgetでは
ユーザがWidgetに表示できる内容をカスタマイズできます。
例えば
天気アプリのWidgetで
自分が住んでいる地域の情報が知りたいとします。
そこでWidgetをタップすると
地域を選択できるリストが表示されます。
このように
ユーザが本当に必要としている情報が提供できる機会を
設けることが大切になります。
WidgetKit
こういったWidgetを実現するために
WidgetKitという新しいフレームワークが登場しました。
いくつかWidgetKitのコンセプトが紹介されています。
SwiftUIでマルチプラットホームを簡単に実現する
iOS、iPadOS、macOSどれでも同じ様に表示できるように
現時点でマルチプラットホームを実現する一番簡単な方法として
SwiftUIで実装するようになっています。
さらに
SwiftUIは
DynamicTypeやDarkModeへもほぼ自動で対応してくれます。
準備ができたら表示する
ユーザは
平均で1日90回ホームスクリーンを訪れるそうですが
そのほとんどが一瞬です。
その際に
ローディングインジケータがずらりと並んでいたら
なんの有益な情報も提供できません。
そこでWidgetKitは
バックグラウンドでViewを生成して返すようにしています。
そして
Timelineという一つの時間軸の上で
適切なタイミングでViewを構築して表示します。
そしてこれをフレームワーク側で管理することで
この構築したViewを他の箇所でも再利用しています。
Widgetを追加する時
WidgetGalleryと呼ばれるモーダルの中でWidgetを選択します。
そこに表示されるViewは
- 事前に用意したView
または
- すでに構築が完了しているView
が表示されます。
すでに構築されたViewを利用することで
実際にホーム画面に置いた時に
Widgetがどう表示されるかを
ユーザは確認することができます。
情報の更新ができる
Widgetを更新するためには
- アプリからWidgetを更新する
- 定期的なWidgetの更新をTimelineに設定する
という方法があります。
例えば
カレンダーアプリのWidgetでは
予定のタイミングでWidgetの表示が更新されるように
Timelineに設定をしています。
しかし
途中で予定が変わりアプリのスケジュールを変更したタイミングで
Widgetの更新も行われ
Timelineの設定が更新されます。
WidgetKitの使い方
ここからはWidgetKitについて見ていきます。
WidgetKitには下記のようなコンセプトがあります。
- Kind
- Configuration
- SupportedFamilies
- Placeholder
Kind
WidgetKitでは一つのextensionの中で
複数のWidgetを構築することができるようになっています。
例えば
株価のアプリでは
- 複数の株価の概要を確認できるWidget
- 一つの株価の詳細を確認できるWidget
があります。
Configuration
WidgetKitには
- StaticConfiguration
- IntentConfiguration
があります。
StaticConfiguration
ユーザがカスタマイズする必要がないものなどに使用します。
例えば
Fitnessアプリの場合
すでにパーソナライズされた情報が表示され
ユーザが設定を変更する必要がないため
StaticConfigurationを使用しているようです。
IntentConfiguration
ユーザが設定を変更することができます。
Listの部分をタップすると選択可能な一覧が表示され
Widgetに表示される値の種類が変更できます。
これはSiriKit intent definitionファイルを定義することで
固定の選択肢を提供することができます。
さらに
iOS14の新機能
in-app Intent handling
を使って動的に選択肢を作成することもできます。
SupportedFamilies
WidgetKitでは
3種類のサイズのWidgetを作成できます。
- systemSmall
- systemMedium
- systemLarge
デフォルトでは全てのサイズをサポートしています。
Placeholder
実装する際に必須のViewの一つで
端末の設定の変更時に利用される(文字サイズ変更など)時に
呼ばれるとセッションでは言っていましたが
ほとんど使われることはなく
このタイミングで呼ばれるという保証はない
とも言っています。
ポイントとしては
このWidgetが何を表示するものなのかを表す
ことが大事だそうです。
そして
ユーザデータは含めずデフォルトの内容を含める
ことが推奨されていました。
実装例
ここからはコードを見ていきます。
※
開発を行うにあたって
Xcode12 Beta1では
シミュレータでWidgetが利用できません(Widgetのリストに表示されない)のでご注意ください。
Beta2では表示されるようになりました。
まずはWidgetを定義します。
上記で紹介した
KindやPlaceholder、
実際にデータを表示するViewを提供するクロージャを引数に
Configurationを作成しています。
Providerは具体的にViewを提供する方法を定義します。
具体的には後に登場するコードをご覧ください。
下記のような構成になっています。
Viewを構築するときのポイント
ここから
より詳細にViewを提供するコードを見ていきますが
その前にViewを構築していく際のポイントについて見てみます。
下記の3つのWidgetは
必要最低限な情報を表示しており
タップするとアプリを開いて詳細画面へ遷移します。
大事なのは
状態を持たないUI
を構築することです。
Widgetでは
スクロールや動画の再生などの操作はできません。
これは上記でも記載した
ユーザがホーム画面にいる時間の短さなどによる特徴だと考えられます。
その代わりに
Widgetをタップすることで
アプリにDeep Linkすることができます。
systemSmall
はWidget全体で一つのリンクになっており
タップするとアプリへ直接遷移します。
systemMedium
、systemLarge
では
個々のViewにwidgetURL
というメソッドを使うことで
別々のリンクを設定してアプリに遷移することができます。
そしてアプリ側ではonOpenURL
メソッドを使って
Deep Linkをハンドリングできます。
ドキュメントトップ
https://developer.apple.com/documentation/widgetkit
※
リンク先への遷移に失敗すると
アプリのトップページに遷移しました。
また
LazyVStack
など
LazyなViewと一緒に使用している場合に
画面に表示されていなければ
対象のリンク先へ遷移されません。
View
がレンダリングされていないので
当然と言われればそうなのですが
最初「あれ?」と思ったので記録として書き残しておきます。
Viewを提供するコード
それでは
コードを見ていきます。
Viewを提供する箇所は3つあります。
- Placeholder
- Snapshot
- Timeline
Placeholderについては
すでに見ましたので
下の2つについて見ていきます。
Snapshot
システムが
今すぐに1つのViewを必要としている時に
提供するViewです。
ただし
これはダミーデータではなく
実際のWidgetで利用するデータです。
なので
SnapshotとTimelineの最初のViewは
多くの場合で同じになります。
同時に
WidgetGalleyに表示されるViewになり
ユーザがWidgetを追加した時に
最初に表示されるViewにもなります。
Timeline
複数のViewと日付の組み合わせで
いつどのViewをWidgetに表示したいか
を設定します。
こうすると
フレームワークが
Viewをシリアライズ化してディスクに保存し
必要な時になったらレンダリングを行う
という仕組みになっているようです。
Timelineには
一般的には1日分の内容を設定するべきだそうですが
場合によってはより更新が必要なものもあります。
その場合
Reloads
と呼ばれるコンセプトに基づいて
表示の更新が実行されます。
※
ドキュメントにも詳細が記載されていますのでそちらをご参照ください。
https://developer.apple.com/documentation/widgetkit/keeping-a-widget-up-to-date
Reloads
フレームワークが
デバイスにあるそれぞれのWidgetを起動し
新しいTimelineを提供するように要求します。
Reloadsを行うことで
ユーザに最新の情報を提供していることを保証できます。
※
Reloadsに関しては
ドキュメントにも詳しい記載があるのでそちらもご参照ください
https://developer.apple.com/documentation/widgetkit/keeping-a-widget-up-to-date
具体的にはTimelineProvider
を利用します。
主に日付を持ったTimelineEntry
があり
https://developer.apple.com/documentation/widgetkit/timelineentry
Context
にはその時のデバイスの情報などが含まれています。
- systemSmall or systemMedium or systemLarge
- Widgetのサイズや位置
- Widgetが表示される際に設定されている全てのenvironmentの情報
- WidgetがWidgetGalleryに表示されるかどうか
例えば
Widgetを表示するのに
外部からリソースを取得することが必要な場合
WidgetGalleryに表示されるまでに時間がかかったり
エラーが発生すると表示されないことがあります。
(その場合真っ黒な画面になります。)
そこで
isPreview
メソッドを活用してtrueの場合には
staticなデータを返却するなどの対策を行うことができます。
snapshot
snapshot
メソッドでは
1つのTimelineEntry
を
timeline
timeline
メソッドでは
複数のTimelineEntry
にTimelinePolicy
を添付した
Timeline
を
返します。
下記が具体的な定義方法の例です。
TimelinePolicy
TimelinePolicy
には3種類あります。
atEnd
提供した最後のEntryが表示された際に
フレームワークにreloadを依頼します。
after(date: Date)
指定した日時に
フレームワークにreloadを依頼します。
never
reloadをしないようにフレームワークに依頼します。
下記はドキュメントのイメージで
どのようにreloadが発生するのかが示されています。
最初にProvider
から
3つのTimelineEntry
を持ち
atEnd
をRefresh Policyに設定したTimeline
を提供しています。
そうすると
最後のTimelineEntry
が表示されたタイミングで
フレームワークがreloadを呼ぶことで
再びProvider
から
新しいTimeline
を提供しています。
never
をRefresh Policyに設定しているため
表示はずっと変わらなくなります。
注意点
ただし注意しなければいけない点としては
この設定通りには動かない可能性があります。
ReloadsはTimelinePolicy
を基に
どのくらいWidgetが見られているかや
システムの状態を考慮して
最終的にフレームワーク側でreloadのタイミングを決めます。
また
システムの時間が急に大きく変わった場合などに
強制的にreloadする場合もあります。
※
Betaだからかもしれませんが
このタイミングはかなりバラつきがあり
どういうタイミングで発生するのかが
いまいちつかめませんでした。
(2020/8/21追記)
下記のForumの内容によると
最低でも15分程度の間隔は空ける必要があるようです。
https://developer.apple.com/forums/thread/653265
(2020/8/27追記)
Beta6でProtocolに変更がありました。
- メソッド名が
snapshot
->getSnapshot
- メソッド名が
timeline
->getTimeline
- Contextの引数ラベルが
with
->in
-
placeholder
メソッドが必須に
アプリからも更新できる
上記では
フレームワークにreloadのタイミングを委ねる方法でしたが
アプリからWidgetを明示的に更新する方法もあります。
例えば
アプリがバックグラウンド通知を受け取った時や
アプリ内でユーザがデータを更新した場合などが
考えられます。
WidgetCenter
を使用します。
アプリに紐づいている特定のWidgetのみを更新したり
全てのWidgetを更新することもできます。
また現在のConfigurationを知ることもできます。
注意点
ただし何でもかんでも更新するのではなく
Widgetに表示する内容に関連する更新が行われた際にのみ
更新するように考慮する必要があると言っていました。
バックグラウンドのURLSessionからデータを受け取る
Timelineを構築する際に
サーバからデータを取得する場合があると思います。
その際にバックグラウンドでAPIの呼び出しを行い
onBackgroundURLSessionEvents(matching:_:)
でリクエストの結果を受け取ることもできます。
※
ドキュメントやセッションでは言及されていますが
実際に試したところイベントを受け取ることができませんでした。
サンプルでも記載がないのでまだわかっておらず
引き続き調べています。
もしご存知の方いらっしゃいましたら
教えていただけましら幸いです🙇🏻♂️
注意点
ただし
こちらもリクエスト数なども考慮する必要があります。
Widget用に複数のリクエストを1つにまとめるなどの
対策が必要になるかもしれません。
アプリがバックグラウンドで動いている際のreloadのタイミングは
システムに委ねられます。
Reloadsを行う際には
プロセスやリクエストを効率的に行うこと。
Widgetは毎秒単位のずっと動いているようなものではありません。
Widgetの性質によって
どのくらいのReloadsが必要になるかを見積もり
考慮した設計をしましょう。
PersonalizationとIntelligence
Widgetをよりユーザに使いやすくするための
主に2つのコンセプトがあります。
- Intents
- Relevance
Intents
Intens.frameworkを利用して
ユーザにどのようにWidgetを表示するかの
選択肢を提供できます。
すでにSiriとShortcutsを一緒に利用する際に
活用されていた技術が
iOS14ではWidgetでも利用できるようになりました。
※
以下で簡単に実装方法を記載していますが
詳細に関してはドキュメントをご参照ください。
https://developer.apple.com/documentation/widgetkit/making-a-configurable-widget
Intent Definitionファイルの生成
File > New File and select SiriKit Intent Definition File
から作成できます。
ファイルを作成すると内部で
この内容にそったクラスが自動で生成されます。
CoreDataのxcdatamodeld
と似たような仕組みのようです。
コード
IntentConfiguration
と
IntentTimelineProvider
を活用します。
https://developer.apple.com/documentation/widgetkit/intentconfiguration
https://developer.apple.com/documentation/widgetkit/intenttimelineprovider
Intents Extensionを使って動的に選択肢を生成する
in-app Intent handling
というiOS14の新機能を使って
動的に選択肢を生成することもできます。
その場合
Intents Extensionをターゲットに追加し
IntentHandler
を実装する必要があります。
下記のような形で実装します。
class IntentHandler: INExtension, SelectCharacterIntentHandling {
func provideCharacterOptionsCollection(for intent: SelectCharacterIntent, with completion: @escaping (INObjectCollection<GameCharacter>?, Error?) -> Void) {
// Iterate the available characters, creating
// a GameCharacter for each one.
let characters: [GameCharacter] = CharacterDetail.availableCharacters.map { character in
let gameCharacter = GameCharacter(
identifier: character.name,
display: character.name
)
gameCharacter.name = character.name
return gameCharacter
}
// Create a collection with the array of characters.
let collection = INObjectCollection(items: characters)
// Call the completion handler, passing the collection.
completion(collection, nil)
}
}
そしてIntentTimelineProvider
の中で
結果を使用します。
struct CharacterDetailWidget: Widget {
var body: some WidgetConfiguration {
IntentConfiguration(
kind: "com.mygame.character-detail",
intent: SelectCharacterIntent.self,
provider: CharacterDetailProvider(),
placeholder: CharacterPlaceholderView()
) { entry in
CharacterDetailView(entry: entry)
}
.configurationDisplayName("Character Details")
.description("Displays a character's health and other details")
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
}
}
※
このinitはXcode12 Beta3でdeprecatedになりました。
placeholderを引数に渡さないようです。
struct CharacterDetailProvider: IntentTimelineProvider {
func timeline(for configuration: SelectCharacterIntent, with context: Context, completion: @escaping (Timeline<CharacterDetailEntry>) -> ()) {
// Access the customized properties of the intent.
let characterDetail = lookupCharacterDetail(for: configuration.character.name)
// Construct a timeline entry for the current date, and include the character details.
let entry = CharacterDetailEntry(date: Date(), detail: characterDetail)
// Create the timeline and call the completion handler. The .never reload
// policy indicates that the containing app will use WidgetCenter methods
// to reload the widget's timeline when the details change.
let timeline = Timeline(entries: [entry], policy: .never)
completion(timeline)
}
}
代わりにisPlaceholder
メソッドや
https://developer.apple.com/documentation/swiftui/view/isplaceholder(_:)
redacted
メソッドとplaceholder
プロパティを組み合わせて
Placeholder
を作成するようです。
https://developer.apple.com/documentation/swiftui/anyview/redacted(reason:)
https://developer.apple.com/documentation/widgetkit/timelineprovider/3656451-placeholder?changes=latest_beta
※ 2020/8/1追記
isPlaceholder
はdeprecatedになっておりredacted
を使用するようです。
Appleのサンプルコード内では下記のように利用していました。
RewardsCardEntryView(entry: .init(date: Date(), points: 4))
.previewContext(WidgetPreviewContext(family: .systemMedium))
.redacted(reason: .placeholder)
さらに
@Environment
でredactionReason
が取得できるので
この値が空ではないとき(=現状では.placeholder
が指定されているとき)に
placeholder表示に変更するということができます。
@Environment(\.redactionReasons) var redactionReasons
また逆にunredacted
を利用することで
一部のViewのみをPlaceholder表示にしないこともできます。
※ Beta3ですとImage
はplaceholderになりませんでした。
次のアップデートで改善されるのではないかと思っています。
※ (2020/8/21追記)
Beta5で新しくplaceholder(in:)
がTimelineProvider
に追加されました。
上記のplaceholder(in:)
はBeta3か4で追加されていたようです。
これを使用するとViewを自動でredacted
が適用されるようです。
https://developer.apple.com/documentation/widgetkit/timelineprovider/placeholder(in:)-6ypjs
Relevance
冒頭の方でも紹介しましたスマートスタックの中で
システムは合理的にユーザが関心が高いであろう
Widgetを表示するようにします。
その際の評価方法をアプリやWidgetを通じて
変更することができます。
主に2つの方法があります。
- アプリ内のユーザの操作からShortcutsにdonationする
- Widgetの
TimelineEntry
にTimelineEntryRelevance
を設定する
Shortcutsにdonation
ユーザの操作をINIntent
として
donationしておくことで
同じINIntent
だと判断された際に
スタックの中のWidgetが表示される可能性が高まります。
下記の例では
- 使用したカード
- 購入した商品カテゴリー
を表示するWidgetですが
月曜日と火曜日に
同じカードで同じ商品カテゴリーのものを購入したアクションを
donationしておきます。
そうすると
金曜日に同じような操作をした際に
その購入履歴のWidgetが表示されやすくなります。
TimelineEntryにTimelineEntryRelevanceを設定
各TimelineEntry
には
TimelineEntryRelevance
を使って
重みをつけることができます。
score
はfloat
で
これまでに提供した全てのEntryとの比較値として利用されます。
ドキュメントにも下記のような記載があります。
The score is a value
you choose that indicates the relevance of the widget,
relative to entries across timelines that the provider creates.
例えば
下記のように購入した金額をscore
に設定することで
購入金額の高いものが優先的に表示されるようになります。
duration
は
設定されたEntryが
Widgetに表示する時間になってから
どのくらいそのscore
が有効であるかを示す値です。
例えば
下記の例はバスケットボールの試合のスコアを表示するWidgetです。
試合の開始時にscore
加え
試合が終了するまでの3時間(duration = 3hrs
)を設定しています。
以降がnil(設定なし)なのは
Relevanceに影響を与えないことを示しています。
一つ前で0としているのは
次のRelevanceが来るまでは
このscore
(= 0)を継続して使用することを示しています。
良いWidgetを設計するために
ここからは良いWidgetを設計するためのポイントを
セッションの内容から見てみたいと思います。
Design great widgets(優れたWidgetの設計)のセッションの中で
大きく2つに分けて紹介されていました。
- Ideation(何を表示するのか)
- Creation(どう表示するのか)
※
Creationに関しては
HIG(Human Interface Guideline)と内容が似ていましたので
ドキュメントをご参照して頂けましたら幸いです。
Ideation
大きく分けて3つについて
述べられています。
- Principles
- Editing
- Multiples
Principles
大事なポイントとして以下の3点が挙げられています。
Personal
よりユーザに特化した情報を提供することで
アプリとユーザの感情的な繋がりを強くする。
Information
多くの情報の中から
一番重要な情報の概要を選んで提供する。
Contextual
ユーザがアプリで繰り返し操作して得ているような情報(必要としている情報)
を提供する。
必要な情報は時と場合によって異なるので
それに応じた情報が提供できるようにする。
例
カレンダーアプリは下記のようにスケジュールに応じて
表示方法を変えています。
一番重要な情報として
直近のスケジュールの内容と時刻と場所を表示します。
また
スケジュールの量や祝日に合わせて表示方法を変えたり
連絡先から知り合いの誕生日を表示することができます。
天気アプリでは
例えば雷雨が発生している場合は
より細かい分ごとの降水量を表示して
何時ごろに雨が止むのかが確認できるようになります。
Editing
iOS14の新機能で
ユーザがWidgetに設定できる内容を
カスタマイズできます。
これはWidgetにどのように情報を表示するのかに
関わってきます。
冒頭の方でも紹介しましたが
天気アプリでは表示する地域を選択できます。
さらに同じ種類の複数のWidgetを表示して
他の地域の天気を表示することもできます。
これが実現できることで
1つのWidgetに複雑な情報を詰め込む必要はなく
シンプルでわかりやすい表示を可能にします。
Multiples
1つのアプリの中で
複数の種類のWidgetを作成することも可能です。
例えば
株価アプリでは
ウォッチリストのサマリーを表示するWidgetと
一つの株価を細かく表示するWidgetが
用意されています。
どういった情報をユーザがすぐにチェックしたいかどうかを考え
複数のWidgetを用意するべきかどうかを検討します。
Widget作成に役立つView
最後にセッションの中で紹介されていた
Widget作成において役に立つViewを2つ紹介します。
Text init(_:style:)
SwiftUIのテキストに新しいイニシャライザが追加され
DateからTextを生成できるようになりました。
init(_ date: Date, style: Text.DateStyle)
これは指定した時間からの経過時間を自動で表示してくれます。
Widgetは常時動いているものではありませんが
このTextを活用することで
リアルタイムに起動しているように見せることができます。
※セッションの画像です。
またString Interpolationを活用することで
表示のローカライズも可能です。
ContainerRelativeShape
HIGにも記載されていますが
WidgetのCorner Radiusと
コンテンツのCorner Radiusは
一致させることが推奨されています。
しかし
この値はデバイスサイズに変わってくるため
手動で計算するのは大変難しいです。
そこで今回
ContainerRelativeShape
が追加されました。
これは親ViewのCorner Radiusに合わせるように
フレームワーク側で自動で計算してくれるようになります。
Beta5よりLocation Permissionが必要に
(2020/8/21追記)
WidgetでLocationを使用する場合に
Permissionをユーザに求めることが必要になりました。
そのため
Info.plistに下記のKeyが必要になります。
NSLocationUsageDescription
NSWidgetWantsLocation
NSWidgetWantsLocation
https://developer.apple.com/documentation/bundleresources/information_property_list/nswidgetwantslocation
メモリの最大容量
ドキュメントに記載はありませんが
こちらの記事によると30MBを超えるとクラッシュするようです。
まとめ
iOS14のWidgetについて見てきました。
これまでのアプリのアイコンが並んだホーム画面から
よりユーザが必要としている情報をすぐに確認できるようになるのは
便利そうだなと感じています。
一方で
必要ないものはユーザからどんどん遠ざかっていくのではないかとも感じており
Widgetを使うことでユーザに利便性を高めていくことは
大事になってくるのだろうと思いました。
まだまだ不明な点が多く
実際にReloadの(timeline
メソッドが呼ばれる)タイミングで
通知音を出して確認してみましたが
予定の時間に更新がされなかったり
予期せぬタイミングで更新されたりします。
※
ロック画面から復帰したら鳴ったり
他のアプリ削除したら鳴ったり
ウィジェットを追加していなくても鳴ったり...など
ただ使い続けていると
Timelineに設定した内容に関しては
だんだん時間通りに通知が来るようになってきたなとも感じています。
アプリの使用頻度も関わっているようなので
それが影響しているのかなと思っています。
データの更新とViewの更新のタイミングも
必ずしも一致しているわけではありませんでした。
また
スマートスタックを利用した時に
どのくらいの頻度で自分のWidgetが表示されるのか
Relevanceの有効性がどのくらいなのかなど
まだまだわからないことがあるので
これからも触ってみて色々調べていきたいなと思います😃
何か間違いなどございましたら
教えていただけますと助かります🙇🏻♂️