ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
WidgetKitについて
WidgetKitのご紹介: Appで最も役立つ情報をホーム画面に直接表示する最善の方法です。優れたウィジェットとはどのようなものかを紹介し、WidgetKitの機能や特徴について確認します。ウィジェットの作り方や、WidgetKitがSwiftUIを活用してどのようにステートレスな体験を提供しているかを学ぶことができます。既存のプロアクティブテクノロジーと併用することで、ウィジェットが確実に関連事項を表示する方法をご紹介します。また、コンテンツの内容が常に最新となるようなTimelineを作成します。ウィジェットの作成の詳細については、"Build SwiftUI views for widgets"と"The widgets code-along"をご覧ください。
リソース
- Building Widgets Using WidgetKit and SwiftUI
- Creating a widget extension
- Human Interface Guidelines: Widgets
- Keeping a widget up to date
- Learn more about creating widgets
- WidgetKit
関連ビデオ
WWDC22
WWDC21
WWDC20
-
ダウンロード
“ようこそ WWDC2020へ”
WWDCへようこそ “WidgetKitについて” こんにちは 私はナヒール iOS System Experienceチームの マネージャーです 同僚のニールも後で登場します 今日は皆さんに WidgetKitをご紹介します iOS 14ではホーム画面が 劇的にリニューアル よりダイナミックで個性化され ウィジェットを重視しています 新しいウィジェットは大胆で ひと目で分かるデザインです iPhoneのホーム画面だけでなく
新しいToday Viewも iPadのホーム画面に適応 MacOS Big Surの 新しい通知センターに適しています
APIを掘り下げる前に ウィジェットで体験できることを ご紹介します チームで考えた 最高のウィジェットの3つのポイントは ひと目で分かり 関連性があり 個々にカスタマイズできること
“ひと目で分かる”とは どういうことか? 新しいウィジェットには さまざまなサイズがあります 最小サイズで使うのは ホーム画面アイコン4つ分ほどのスペースです そこを有意義に使いたいですね ホーム画面にいるのは ほんの少しで すぐ別の画面に移りますよね ちらっとのぞく程度だった ウィジェットを最大限に活用しましょう
小サイズを例として見てみましょう ボタンを押したり 複雑なユーザ―インターフェイスを 解明する必要はありません 重要なのはコンテンツです ウィジェットは ミニAppではありません “ホーム画面に小さなボタンが並ぶ ミニApp”でなく より突出したコンテンツと 考えてください イメージしにくい場合は― デザインチームのセッションを ご覧ください 魅力的なウィジェットを作る 秘策を教えてくれます
見やすさは その1つにすぎません 関連性を持たせることも重要です 例えば朝 支度している時 私が気にするのは天気です その後 日中は “リマインダー”でやるべきことをチェック 1日の終わりは“ミュージック” 近所迷惑なほど 大音量では聴きませんよ スペースがカギとなる Mobile Platformsでは 適切なウィジェットを 必要な時にすぐ使えるようにしたい
そこでSmart Stackの登場です ウィジェットを自動的に回転させ 適切なウィジェットを前面に表示します スワイプできますし 楽しいですよ Stackでの表示には on-device intelligenceを使います これに使えるのが Siri Shortcuts donations ここ数年で我々が開発したシステムです また特定のWidgetKit APIのおかげで ウィジェットが より関連性を持つ タイミングをシステムが認識できます これはウィジェットに限った話ではありません このトピックに特化したセッションが あるので確認してみてください 3つ目は個々にカスタマイズ可能なこと 例えば“天気”ウィジェット 私はカナダ人なのでセ氏表示です ご覧のとおり 小 中 大の3つのサイズがあります 全サイズに対応させる必要はなく App次第ですが 多くのサイズに対応するのを お勧めします さらにカスタマイズしましょう タップして編集モードに入り フリップで迅速に構成できます 構成オプションはショートカット同様に Intentでビルドされています 都市の選択も その一例で 大いに可能性のある 効果的なシステムです WidgetKitがすばらしいのは このConfiguration UI全体を Intentから完全に自動で生成できることです 要点をまとめると 最高のウィジェットは ひと目で分かり 関連性があり 個々にカスタマイズできる
これらを踏まえて開発したのが WidgetKitです まず我々が目指したのは ウィジェットをマルチプラットフォーム化し 簡単にすることで ディベロッパが学んだことをiOSやiPadOS macOSに適用できるようにすること そのため ウィジェットのインターフェイスと WidgetKitはSwiftUIでビルドされています またSwiftUIは Dynamic Typeやダークモードのような機能を ほぼ自動的にサポートしやすくします 次に ホーム画面にウィジェットを置くのは 大きな意味があります ホーム画面を見るのは 1日当たり平均で90回以上 毎回 見る時間はごくわずか
そのためローディングスピナーばかり 表示されるのは避けたいもの watchOSを開発した時も ひと目で分かり 瞬時に表示することを目指しました 今回 そのプロセスを参考にしたのです
WidgetKit extensionは Background extensionで タイムラインで一連の View Hierarchyを返します SwiftUIの宣言型の資質を使って タイムラインの これらの表示をまとめ― ホーム画面に送り タイムラインに従って適当な時に表示できます これは読み込んで表示させるという ランチャーのプロセスを回避し 瞬時に見やすい表示を実現します
事前に表示を準備できれば それらをシステムの他の領域に 再利用できます 例えばWidget galleryから ウィジェットを追加することで ホーム画面でウィジェットがどう見えるか プレビューが可能です タイムラインはメインAppから リフレッシュできます 例えばAppの変更時は ウィジェットも更新されます もしくはextensionから スケジュール更新も要求できます
例えば“カレンダー”のウィジェットは その日の予定を把握しています extensionは この情報を元に表示を変え 次に出席すべき会議は何時からか 事前に教えてくれるのです ニールと私がコーヒーをスキップして ステーキ店に行くことにした場合 “カレンダー”で予定を更新します
“カレンダー”はAPIを使って タイムラインをリロード するとextensionが起動し 最新情報と共に 新しいタイムラインに返すのです WidgetKitの仕組みが分かったところで 次はニールが ウィジェットの作り方を説明します よろしく ありがとう ナヒール 私はニール・デサイ WidgetKit エンジニアリングマネージャーです 最高のウィジェットの作り方を お話しします これには4つの重要なポイントがあります ウィジェットを定義する方法 ひと目で分かる体験の実現方法 ウィジェットのエンジンである 表示 タイムライン リロード そして ウィジェットのカスタマイズと インテリジェンスについて ウィジェットはシンプルですが 非常に効果的です 使えるツールについてお話ししましょう まずはウィジェットを定義する方法です これには いくつかのコンセプトがあります 種類 構成 supportedFamilies プレースホルダです
さまざまなウィジェットを実現するために 我々が求めたのは 1つのextensionで 多種のウィジェットに対応するメカニズムです
例えば“株価”の1つのextensionが提供する “株価”の概要ウィジェット 2~3銘柄の情報が ひと目で分かる最高のウィジェットです また同じextensionが “株価”の詳細ウィジェットも起動し ホーム画面やmacOSの通知センターで 1銘柄を表示できるようにします これらに使うのがSwiftUIや マルチプラットフォームextensionです WidgetKit extensionはSwiftUIやAppKit Catalystベースの macOS Appに対応します また ウィジェットの種類は 対応する構成も表します 1つはStaticConfiguration もう1つはIntentConfigurationです
フィットネスのウィジェットでは ユーザ―に構成を行わせる必要はなく その日のアクティビティを表示するだけ 私自身のデータはよくないです もっと体を動かさないと… 本題から それましたね このウィジェットは StaticConfigurationを使います “リマインダー”では 特定のリストをカスタマイズできます こちらのウィジェットは IntentConfigurationを使います “supportedFamilies” また特定の種類は 1つ以上のsupportedFamiliesを有効にできます ウィジェットはデフォルトで すべてのfamilyに対応しています “天気”ウィジェットも同様 どのfamilyタイプでも 気温を華氏で見られます ナヒールはセ氏表示でしたね これらのfamilyは iOSやmacOSの表示にぴったりです ウィジェットの定義に関する 最後のコンセプトはプレースホルダUI どのウィジェットでもデフォルトの ユーザ―インターフェイスです その役割は ただ ウィジェットの種類を表すことであり ユーザ―のデータは含みません このインターフェイスは小出しに引き出され それがいつ行われるかは不明です デバイスの環境が変わる時のみ 新しいプレースホルダUIを求めます 例えばデバイスのDynamic Type設定が 変わる時
プレースホルダUIは ウィジェットの種類を表します ウィジェットに最適なインターフェイスを 吟味するといいでしょう コードですね これら4つのコンセプトが ウィジェットの定義を実現します ここでウィジェットのプロトコルに適合した サンプルのウィジェットを定義し 種類を指定します いくつかのアイテムで構成された ウィジェットの構成を返し PlaceholderViewで providerを指定します
このようにしてウィジェットの エンジンを設定するのです
次は ひと目で分かる体験の実現について お話しします 例を挙げると“天気”や “Nike Run Club”“ カレンダー”などです 有用な情報を表示し Appを起動させるように誘導します 方法の1つは StatelessUIを作ることであり SwiftUIが これに最適です ホーム画面や通知センター上の インタラクションとは違います これらのウィジェットで スクロールはできませんし スイッチや その他のシステム制御 映像や動画にも対応していません ひと目で分かるインターフェイスにより ユーザ―は― 気軽にウィジェットをタップし Appに入ります これはsystemSmallでの“ミュージック” 直近で再生したアルバムにタップし 直接 Appに入ることができます systemSmallでは ウィジェットそのものにタップし ユーザ―を直接 Appへ導きます
“ミュージック”のウィジェットは systemMediumにも対応しています 膨大な種類のアルバムが表示され 各アルバムがリンクとなり 直接Appへ導きます ウィジェット全体はwidgetURL APIを使って URLリンクと関連づけられます systemMediumかsystemLargeで サブリンクを作りたければ 新しいLink APIとSwift APIを使えます
以上がウィジェットの定義と ひと目で分かる体験の実現方法です 次はウィジェットのビュー タイムライン リロードについて 考慮すべきは3タイプの ユーザーインターフェイスです 先述のプレースホルダに スナップショットとタイムラインです スナップショットでは 単体の入力を素早く表示するので extensionには表示を迅速に返すことが 求められます そうすればウィジェットが iOSの魅力的なWidget galleryで見られます これはデザイン時のスクリーンショットや 画像でなく iOS iPadOS macOSで 実際に体験できるウィジェットです
大抵はタイムラインの最初の入力と スナップショットが 同じ入力として返されます つまりWidget galleryで見る内容は ユーザーがデバイスに追加した際のもの そのスレッドに従い スナップショットが単体の入力であれば 適当な時に表示される一連の多重ビューは タイムラインにすぎません タイムラインは 返されたビューと日付の組み合わせであり これにより特定のビューをいつ出すか 指示できます
そしてタイムラインを返すことで ウィジェットの体験が実現するのです タイムラインは ダークとライトモード両方で返すべきです WidgetKit extensionが入力を返す時 その情報を取ってView Hierarchyを diskへシリアライズします “WidgetKit ExtensionからWidgetへ” つまり個々の入力をジャストインタイムで レンダリングするのです するとシステムが多くのウィジェットを 多くのタイムラインと共に起動します これは本当にクールなテクノロジーです タイムラインは通常 数日分のコンテンツのために返されるべきもの しかしウィジェットは時に より最新の情報を返す必要があります これをリロードのコンセプトを 通して行います
リロードではシステムがextensionを呼び出し 各ウィジェットの新しいタイムラインを要求 そしてコンテンツが 最新であることを確認します コードは新しいトピックを学ぶための 最も簡単な方法と思います 見てみましょう これは“TimelineProvider”プロトコルです 主に日付で構成されている“TimelineEntry” 環境情報を提供し システムが入力を要求する“Context”
スナップショット機能では システムが単体の入力を要求 タイムライン機能では システムが一連の入力を要求します
ではTimelineProviderプロトコルに どうやって準拠するか? providerを作成し スナップショットで単体の入力を作成し 返します タイムラインでは 一連の入力を返し リロードポリシーを添付 リロードポリシーは各タイムラインに組み込まれ 次のタイムラインを要求する時を システムに教えます
リロードを要求できるのは タイムラインの最後か 特定の日付の後です タイムラインをリロードしないよう 指定することも可能です 例えばウィジェットがタイムラインを返す前に ユーザーのデータを求める場合 システムがリロードポリシーを考慮し ウィジェットのリロードに 最適なタイミングを判断します よく見られるウィジェットは リロードが多く まれに見られるウィジェットは その逆です またシステムはデバイス環境の変更時に リロードを強制します 時刻変更が起きた時などがその一例です
システムはリロードに最適な時間を 決めますが イベントによっては あなたがシステムに指示する必要があります 例えばAppが受け取る バックグラウンド通知や ユーザーがAppに 変更を加えた時です バックグラウンド通知を受ける時 WidgetCenter経由でWidgetKit APIを使い タイムラインをリロードすれば extensionを呼び出します フォアグラウンドAppに ユーザーが変更を加える場合も タイムラインをリロードできます
フォアグランドAppの リロードの際は 反映すべき変更がAppで起きた時のみに ウィジェットをリロードしましょう タイムラインのリロードには AppプロセスのWidgetCenter APIか extensionが使えます 種類ごと またはすべてのタイムラインを リロードする方法があり CurrentConfigurationsの リストを引き出せます また 追加の情報をサーバに 問い合わせる時もあります タスクを始めるために Background URL Sessionを使えば onBackgroundURLSessionEventsのモディファイアを 経由してペイロードがextensionに送られます ネットワーキングの使用についても 認識すべきです リクエストをサーバへバッチ処理し 必要な分だけ ネットワーキングを使いましょう
Appのprocessor widgetが バックグラウンドで動いている時 リロードはシステムに割り当てられています ウィジェットが必要な分だけ 処理やネットワーキングを行いましょう ウィジェットではホーム画面での― ライブ体験の実現を 目指しているのではありません
ウィジェットを最新に保つには さまざまなリロード方法があります あなたのウィジェットに合った 体験を考え― タイムラインの多様なリロード方法を 効率よく使いましょう 最後にウィジェットを カスタマイズする方法と Stackでインテリジェンスを伝える方法を お話しします
カスタマイズとインテリジェンスには 2つのコンセプトがあります ウィジェットを設定するメカニズムとして 使われるIntentと Stackでインテリジェンスを 開発者に伝えさせるレレバンスです IntentはIntents frameworkによって動き ユーザーへの質問である パラメータ一式を含みます 例えば“天気”の構成に関する質問では 予報を返すべき場所を問います Intentの枠組みは Siriやショートカットとの統合や iOS 14ではウィジェットの構成を 起動するのに使われています
例を見てみましょう “株価”の単一のシンボルウィジェットは どの銘柄を表示するか尋ねます ユーザーがウィジェットを設定する時 Intentは答えるために “株価”のAppで示されている 同様の株価リストを返します これはAppに必要なツールを与え ユーザーに最高の構成を提供するものです
それが不十分な時もあります メインAppで存在しない株価を 表示したい時は? Intentのおかげで このようなタイプの体験は Intents dynamic options capabilityを 使って実現できます ユーザーはconfiguration UIで検索し システムはStocks Intents Extensionを起動 それが一連の答えを銘柄記号で返します 新しいiOS 14ではIntentが App内Intent handlingに対応しているため Appが質問に答えます
App内Intent handlingについての詳細は “What's New in SiriKit and Shortcuts”トークをご覧ください 先ほど定義したウィジェットを変更して Intentに対応するには? StaticConfigurationの代わりに IntentConfigurationを指定し 関連するIntentを指定します
同様に先ほどのTimelineProviderが IntentTimelineProviderに適合した providerに発展しています Intentオブジェクトをパスされ Intentのパラメータに基づき― 特定のタイムラインを生成できます
ウィジェットの利点の1つは Stackに複数存在することです システムが最も関連性の高い ウィジェットをローテートし あなたのAppとウィジェットが インテリジェンスをフィードできます 主な方法は2つです Appはユーザーが操作を行う時 ショートカットを寄与できます ウィジェットに同じINIntentがある場合 その操作を行う時に ウィジェットがローテートされるのです さらに詳しく知りたければ “Enable Widget Personalization and Intelligence”トークをご覧ください またウィジェットのextensionは TimelineEntryRelevance API経由で タイムライン入力を関連する値と共に 注釈できます 適当な時に入力が最適だとあなたが思う時 scoreとdurationを返し システムに特定のウィジェットを ローテートするよう伝えられます Scoreはあなたが与えた入力すべてに関連する 浮動値であり Durationは特定の入力が関連する時の 時間間隔です
強調したいのは 関連する値が あなたが与えた入力すべてに関連していること システムが関連する値と 他のすべてのウィジェット値を元に Stackで適切なウィジェットを ローテートさせます
ウィジェットはシンプルですが ものすごく効果的です ミニAppではないため ユーザーがひと目で分かる体験を 考えましょう タイムラインやリロードのコンセプト インテリジェンスを駆使し iOS iPadOS and macOSで 最高の体験を実現してください あなたにとって最高のWWDCになりますように あなたの開発が楽しみです
-
-
11:01 - StaticConfiguration Widget definition
@main public struct SampleWidget: Widget { private let kind: String = "SampleWidget" public var body: some WidgetConfiguration { StaticConfiguration(kind: kind, provider: Provider(), placeholder: PlaceholderView()) { entry in SampleWidgetEntryView(entry: entry) } .configurationDisplayName("My Widget") .description("This is an example widget.") } }
-
15:51 - TimelineProvider example
public struct Provider: TimelineProvider { public func snapshot(with context: Context, completion: @escaping (SimpleEntry) -> ()) { let entry = SimpleEntry(date: Date()) completion(entry) } public func timeline(with context: Context, completion: @escaping (Timeline<Entry>) -> ()) { let entry = SimpleEntry(date: Date()) let timeline = Timeline(entries: [entry, entry], policy: .atEnd) completion(timeline) } }
-
20:45 - IntentConfiguration Widget definition
@main public struct SampleWidget: Widget { private let kind: String = "SampleWidget" public var body: some WidgetConfiguration { IntentConfiguration(kind: kind, intent: ConfigurationIntent.self provider: Provider(), placeholder: PlaceholderView()) { entry in SampleWidgetEntryView(entry: entry) } .configurationDisplayName("My Widget") .description("This is an example widget.") } }
-
20:54 - IntentTimelineProvider example
public struct Provider: IntentTimelineProvider { public func timeline(for configuration: ConfigurationIntent, with context: Context, completion: @escaping (Timeline<Entry>) -> ()) { let entry = SimpleEntry(date: Date(), configuration: configuration) // generate a timeline based on the values of the Intent completion(timeline) } }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。