View in English

  • メニューを開く メニューを閉じる
  • Apple Developer
検索
検索を終了
  • Apple Developer
  • ニュース
  • 見つける
  • デザイン
  • 開発
  • 配信
  • サポート
  • アカウント
次の内容に検索結果を絞り込む

クイックリンク

5 クイックリンク

ビデオ

メニューを開く メニューを閉じる
  • コレクション
  • トピック
  • すべてのビデオ
  • 利用方法

WWDC25に戻る

ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。

  • 概要
  • Summary
  • トランスクリプト
  • コード
  • ウィジェットの新機能

    WidgetKitは、ウィジェット、ライブアクティビティ、コントロールのアップデートによってアプリを向上させます。ウィジェットをvisionOSに取り込んだり、CarPlayを使って運転中にウィジェットを操作したり、アクセント付きレンダリングモードでウィジェットの外観を向上させる方法を学びましょう。また、watchOSのスマートスタックに関連ウィジェットを表示する方法や、プッシュ通知を使用してウィジェットを最新の状態に維持する方法も説明します。

    関連する章

    • 0:00 - Introduction
    • 1:03 - Widgets in new places
    • 15:31 - Relevance widgets
    • 18:12 - Push widget updates

    リソース

    • Increasing the visibility of widgets in Smart Stacks
    • Optimizing your widget for accented rendering mode and Liquid Glass
    • RelevanceKit
    • Updating widgets with WidgetKit push notifications
    • Updating your widgets for visionOS
      • HDビデオ
      • SDビデオ

    関連ビデオ

    WWDC25

    • CarPlay向けアプリの強化
    • visionOS向けウィジェットのデザイン
    • watchOS 26の新機能

    WWDC24

    • システム全体にアプリのコントロールを拡張
    • Apple Watch向けのライブアクティビティのデザイン

    WWDC23

    • ウィジェットの新しい場所への展開方法
    • プッシュ通知コンソールについて

    WWDC20

    • プッシュ通知のプライマー
  • このビデオを検索

    こんにちは Tanner Oakesです System Experienceチームで エンジニアをしています ウィジェットは タイムリーな情報や アクションをシステム随所に表示して アプリをバックグラウンドでも有効に 機能させる優れた手段です WidgetKitは拡張を続けており ウィジェットの機能をさらに高め 新たな活躍の場を生み出しています 友人のLucaは カフェイン摂取量を 記録するアプリを担当しています 私もアプリの更新を手伝いました 今回は ウィジェットの新たな機能を 存分に活用するコツを 皆さんにご紹介します このビデオでは Appleのプラットフォーム全体で動作する ウィジェットやライブアクティビティや コントロールについてご紹介します watchOSのスマートスタックで 関連性の高いウィジェットのコンテンツを 表示する 新しい方法も説明します 最後に プッシュ通知機能を利用して ウィジェットを複数のデバイスで 最新の状態に保つ方法もお伝えします ウィジェットやライブアクティビティや コントロールは大きく変化しました まずは ウィジェットが 初めて登場した場所で どれだけ見た目が変化したかを 紹介しましょう iOS 26では ホーム画面の アイコンやウィジェットを 透明なガラスのような見た目にしたり 色付けを選択してカスタマイズし たとえばこんなブルーで表示したり という設定も可能になりました こうした外観は デスクトップ上の ウィジェットや macOS Tahoeの通知センターでも 設定できます こうした新しい表示の仕組みは iOSとmacOSで共通しています まず ウィジェットのコンテンツを アクセントレンダリングモードで生成して コンテンツ全体を白く着色します 次に ウィジェットの背景を削除して テーマ別ガラスや 色付けカラーエフェクトに置き換えます カフェイントラッカーウィジェットは アクセントモードにしただけで 見た目がずっと良くなりました ウィジェットの見栄えを良くするため 微調整が必要な場合もあります 手持ちのアプリに 自分がよく飲むドリンクを表示する ウィジェットを追加しました ちなみに私は抹茶ラテです ウィジェットには ドリンクを描いた 大きな画像が表示され その下にはタイトルで テキストの背後はグラデーションにして 画像に重ねたとき 読みやすくなるようにしています。 アクセントレンダリングを適用すると ウィジェットのコンテンツはすべて 白く着色されます このラテカップのように コンテンツが 不透明な場合は 白一色になります グラデーションのように 一部が透明なコンテンツは 不透明な部分も残しながら 白く色付けされます 私のイメージとはかけ離れています 画像が分かりにくいし 文字も読み取れません アクセントレンダリングの効果を上げる ウィジェット更新方法を紹介します ウィジェットのビューはこんな感じです ドリンクの画像を含むZStackと グラデーションと テキストビューです widgetRenderingMode環境変数を ウィジェットビューに追加します ウィジェットをフルカラーで レンダリングする場合に限るという 条件を付けて 大きい画像と 線形グラデーションを表示します 次に VStackに画像を追加して テキストの上に戻し 画像表示にあたり ウィジェットがアクセントモードの場合 という条件を付けます いい感じのレイアウトになりました ここからは 画像の見た目を 良くする作業です widgetAccentedRenderingMode モディファイアを画像に追加して 低彩度に設定します widgetAccentedRenderingModeは ウィジェットのImagesに適用できる SwiftUIモディファイアです アクセントモードでの 画像の見せ方は I pass inという引数で 正確にコントロールできます widgetAccentedRenderingModeは 5つのモードに対応しています それぞれのモードが画像の表示に どう影響するか紹介します iOSとmacOSのアクセントモードを Watchのアクセントモードと比較します

    widgetAccentedRenderingModeで nilを渡すということは モディファイアを まったく適用しないのと同義です 画像にはメインコンテンツの色が 適用されます iOSとwatchOS 両方のウィジェットで 画像が完全に白になりました .accentedを渡すと 画像がアクセントカラーになります。 iOSとmacOSでは メインカラーと アクセントカラーは両方とも白なので 画像も白くなります watchOSでは アクセントカラーが 文字盤のカラーと同じになるので ウィジェットの画像は青くなります .desaturatedを渡すと 画像の彩度が低下します エフェクトの結果は iOSとwatchOS 両方の表示スタイルで同じに見えます .accentedDesaturatedを渡すと 指定した 2つのエフェクトが両方とも適用されます つまり 画像の彩度が低下し 選択したテーマのアクセントカラーが 適用されます iOSでは 画像がやや白っぽくなります watchOSでは 低彩度にした画像が テーマのアクセントカラーである ブルーで着色されます .fullColorを渡すと アクセントレンダリングモードでの 画像修正はゼロになります 文字盤との馴染みという都合上 watchOSで使われることはありません ほとんどのウィジェットは ホーム画面の他の要素と馴染むよう .desaturatedまたは .accentedDesaturatedが使われます アルバムのアートワークや本の表紙など メディアコンテンツを表す画像には .fullColorを使用します ここからは ウィジェットを まったくの新次元へとシフトさせます visionOS 26では visionOSアプリにも ウィジェットを設定できるようになりました 互換性のある ウィジェット付きの iPhoneアプリやiPadアプリをお持ちなら visionOSでもそのまま利用できます iOSやmacOSのシステムファミリサイズ 全般に対応します 他のプラットフォームと同様に visionOSのウィジェットも 操作可能で アニメーション表示ができます ウィジェットの動作と WidgetKitによる 新しいオプションを紹介します visionOSでは ウィジェットを 部屋に追加して 壁に固定できます デフォルトでは 壁に直接掛けたような 凸面状になります ウィジェットは 壁面より凹ませて 壁に直接埋め込んだように 見せることもできます スタイルがウィジェットに 馴染まない場合は ウィジェット設定で supportedMountingStylesモディファイアを使い 提供させたいオプションを 指定します このモディファイアは visionOSとiOS両方の ウィジェットで使用できます デフォルトでは ウィジェットはすべて ガラステクスチャで描画されます visionOSアプリでは ウィジェットに 紙のテクスチャを指定して ポスターのような見た目にできます 左側は よく飲むドリンクのウィジェットを ガラスで構成したもので 右側は 同じウィジェットですが 実験のため 紙のテクスチャを指定したものです ウィジェット設定で widgetTextureモディファイアを使い ウィジェットのレンダリングを 紙のテクスチャで行うか ガラスボードを使うか指定します ポスター調のウィジェットを完成させるため visionOSでは新たにsystemExtraLargePortrait ウィジェットファミリーが登場しました これは systemExtraLargeという 横幅拡張用ウィジェットファミリーの 垂直方向版です

    supportedFamiliesモディファイアを使用して これをウィジェット設定に追加します visionOSでは ウィジェットの カラーテーマもカスタマイズできます デフォルトでは フルカラー プレゼンテーションで表示されます 緑のテーマを選択すると アクセントレンダリングモードで コンテンツが表示されます ウィジェットのフレームとコンテンツは 選択した色で着色されます バックグラウンドは削除されて 選択したカラーテーマに合わせた 単色に置き換えられます このスタイルでは 先ほど説明した iOSおよびmacOSと同じ レンダリングアプローチを適用します 先ほどと同じ技術を使って 指定したカラーテーマで ウィジェットを ベストの見た目に仕上げます widgetAccentedRenderingMode モディファイアを使って 画像の見た目をカスタマイズします 環境変数widgetRenderingModeを使って 条件付きで より大きな変更を適用します

    visionOSでは ウィジェットを 環境内に取り込んで 壁などに配置することができます 空間内を移動しても ウィジェットは 固定した場所から動きません 部屋の向こう側の壁という遠い場所に ウィジェットがある場合 遠くにあるウィジェットもまた 実際に存在する物体のように 小さくて見づらくなります 実際の物体とは異なり visionOSのウィジェットは LevelOfDetail APIによって 距離に応じて表示の仕方を変えます カフェイン摂取量トラッカーに このAPIを追加する方法を紹介します

    こちらは1日のカフェイン摂取量と 直近に飲んだドリンクと 他のドリンクを簡単に追加できる 便利なボタンが表示されている 既存のウィジェットです ウィジェットが遠い場所にある状態でも 総カフェイン摂取量は大きく表示して 読みやすくしたいと思います ボタンも隠したいところです 遠くからでは操作できませんからね さて カフェイン摂取量ウィジェットで TotalCaffeineViewのサイズを変更して 下側にあるLogDrinkViewの 表示/非表示も 条件付きの切り替えに更新してみます まず 環境プロパティLevelOfDetailを ビューに追加します LevelOfDetailは2つの値の一方になります デフォルトではウィジェットにおける 通常の詳細レベルが選択されています visionOSでは ウィジェット表示は ほどよい距離にある状態で デフォルトの詳細レベルになります ウィジェットとの距離が 物理的にある程度大きくなると 表示レベルは簡略化に切り替わり ウィジェットが遠くからでも ぱっと読み取れる よりシンプルな形で表示されます 条件を追加して LevelOfDetailがデフォルトの場合だけ LogDrinkViewを表示させます 次に カフェイン摂取量の更新です

    総カフェインの表示では タイトルと フォーマットされた総カフェイン摂取量を 表示させています まず 環境変数LevelOfDetailを ビューに追加します 表示を大きくするため 総カフェイン摂取量のフォントを 条件付きで変更して 詳細レベルに応じて タイトルと 大きなタイトルを切り替えます

    これで ウィジェットからの距離が ある程度まで広がると ウィジェットの表示が よりシンプルで 一目で読み取りやすいバージョンに 切り替わるようになりました ウィジェット内のタイムライン変更と同じく 詳細レベルの変更も アニメーション化されます 空間スタイルのカスタマイズや 詳細レベルについてのアドバイスや 新しい環境へのウィジェット移行時に 考慮するべきポイントについては 「Design Widgets for visionOS」で 詳しく紹介しています。 ここでギアをチェンジします ウィジェットとライブアクティビティは 今まさに CarPlayと公道を駆けています CarPlay Ultraでは ウィジェットは ダッシュボード左側の スタックに表示されます iOS 26以降 この機能は すべてのCarPlay搭載車で 利用可能になります ウィジェットの設定は CarPlayの設定アプリで実行できます 車載ディスプレイで使用するため CarPlayでは 一目でわかる情報 大きな文字 判読性が重要になります そのためCarPlayは ウィジェットの背景を削除し fullColorの systemSmallファミリーを使用して StandByスタイルでレンダリングします ウィジェットの操作は タッチスクリーンで実行できるほか CarPlayシミュレータを デベロッパサイトから入手して ウィジェットをテストすることも可能です StandBy表示にウィジェットを マッチさせる方法の詳細は WWDC 23の「Bring widgets to new places」で紹介しています ライブアクティビティは CarPlayのホーム画面にも表示できます デフォルトでは ライブアクティビティの Dynamic Islandには「leading」ビューと 「trailing」ビューが表示されています これは コーヒー注文トラッカーの ライブアクティビティを CarPlayに表示した状態です 確かに悪くはありませんが ほんの少しコードを足せば もっと良い出来になります これが ライブアクティビティのコードです 現状では 「Leading」ビューと 「Trailing」ビューが表示されています このライブアクティビティの表示を CarPlay用にカスタマイズするため supplementalActivityFamilies モディファイアを追加して Activity Configurationへの引数として 「.small」で渡します LeadingビューとTrailingビューを 使用する代わりに CarPlayには iPhoneのロック画面と同じ ActivityViewを表示させます これでうまく表示される ライブアクティビティもあるでしょうが 今回は情報が多すぎて コンテンツの一部が見切れています 幸い ここからさらに カスタマイズを加えられます

    こちらはActivityViewです activityFamily環境変数を ビューに追加します 条件を指定して ビューのボディに 表示するコンテンツを切り替えたり レイアウトを調整して 上質の使用体験を提供したりできます activityFamilyが「small」の場合は 小さめのレイアウトに最適化した ショップオーダービューを表示します それ以外の場合は デフォルトのオーダービューを表示します 追加のコードを少々加えたら CarPlayのライブアクティビティが 見栄えよくなりました 注文が上がるまでの残り時間も ひと目で確認できます supplementalActivityFamilyの追加により ペアリング済みApple Watchでの ライブアクティビティの表示も かなり改善されます iPhoneアプリが自動で実行するため watchOS専用アプリは必要ありません watchOSのスマートスタックで ライブアクティビティの見た目を ブラッシュアップする方法については 「Design Live Activities for Apple Watch」 をご覧ください CarPlayでウィジェットの効果を さらに高める方法を知りたいなら 「Turbocharge your app for CarPlay」も 要チェックです ライブアクティビティが活躍する場は CarPlayだけではありません ペアリング済みiPhoneからの情報は macOS Tahoeにも表示されます iPhoneのDynamic Islandと同様に 注文トラッカーのライブアクティビティも LeadingビューとTrailingビューの2つを メニューバーに表示させます ライブアクティビティを選択すると iPhoneのロック画面が表示されます ロック画面の表示をクリックすると 関連するアプリが iPhoneミラーリングを使用して起動します macOSでのライブアクティビティは iOS 18以降搭載のiPhoneで利用できます コード変更は不要で macOSのiPhoneウィジェットと同様に 連携操作とディープリンクに対応します では macOSとwatchOSのコントロールの 新たな世界を紹介します macOSの場合は macOS SDKと Catalyst いずれのビルドかを問わず Macで動作中のアプリから コントロールを実行できます Appleシリコン搭載のMacで動作する iOSアプリからでもコントロールできます コントロールは コントロールセンターで追加できます iOSで利用可能な 3種類の表示サイズ(小、中、大)を macOS上でも選択できます メニューバーに直接 コントロールを配置することもできます コーヒートラッカーのコントロールを macOSに追加したので メニューバーからコーヒーログを 簡単に更新できます watchOS 26では コントロールを3か所に表示できます サイドボタンからアクセスできる コントロールセンターで設定ができます Apple Watch Ultraの アクションボタンを押しても コントロールを実行できます それに加えて スマートスタックでも 設定を実行できます 他のウィジェットにならんで コントロールのマークやタイトルや 現在の値が表示されます コントロールは ペアリング済みデバイスの watchOSアプリまたはiPhoneアプリから 実行できます コントロールのビルド方法に関する 広範なガイドは WWDC24の 「Extend your app’s controls across the system」で確認できます 次は watchOS 26スマートスタックの relevanceウィジェットを紹介します watchOSのカフェイン摂取量アプリに お気に入りのコーヒーショップが 半額になる ハッピーアワーの時間帯を 確認できるようにする ウィジェットを追加しました ウィジェットで改善したいポイントが 2つあります 第一に 複数のコーヒーショップの ハッピーアワーを追跡していると ハッピーアワーが重なることがあります つまり スマートスタックの表示も いきおい詰め込みがちになります 第二に ハッピーアワーの時間帯は ほぼ一定する傾向にあります つまり 他の時間帯には ウィジェットの出番がありません ハッピーアワーウィジェットを 関連性の高いタイミングにのみ スマートスタックに表示して 開催中のハッピーアワーの情報を より詳しくしたいところです watchOS 26のrelevanceウィジェットなら それも不可能ではありません ハッピーアワーをウィジェットとして 設定する方法を紹介します relevanceウィジェットを定義するには ウィジェット型を作成して StaticConfigurationや AppIntent構成に代えて RelevanceConfigurationを使います 他の構成と同様に 種類文字列や プロバイダオブジェクトや カスタムエントリをSwiftUIビューに 変換するクロージャで構成されています プロバイダ型は RelevanceEntriesProviderです プレースホルダとrelevanceメソッドは TimelineEntriesProviderと同様です プレースホルダには コンテンツの準備中に表示させる シンプルなエントリを返します relevance用に まずは 自分で定義した一連の構成オブジェクトを 取得します

    ハッピーアワーウィジェットの場合 構成と関連性があるのは ハッピーアワーの開始時間と 終了時間です ハッピーアワー各回の 日付間隔を使って このコンテキストで該当する 属性を定義します そうしたら エントリメソッドを実装します タイムラインウィジェットとは違い RelevanceEntriesProviderは 単一のエントリだけを 構成に提供します 構成には このエントリに必要な ショップデータや ハッピーアワーの時間範囲という すべてのデータを記入してあり ウィジェットをすぐに作成できます 他のデータやアセットが必要なら メソッドをasyncとマークしてあるので ここで取得できます relevanceウィジェットの設定が完了し 関連性ある場合だけ ハッピーアワーが スマートスタックに表示されます 複数の構成で 関連性が 同時発生した場合は ウィジェットの複数のインスタンスを スマートスタックで確認できます relevanceウィジェットは watchOS 26のパワフルな新機能です ウィジェットのコンテンツと 関連性を直接関連付けることができます relevanceウィジェットは単体で使っても また タイムラインベースの 既存のウィジェットと併用しても 素晴らしい効果を発揮します Relevanceウィジェットの詳細については 「What’s new in watchOS 26」 をご覧ください 今回 ウィジェットを表示できる場所や プラットフォームがさらに増えました どこに表示する場合でも ウィジェットを 常に最新の状態に維持する必要があります 先日 サーバを追加したので カェイン摂取量データを すべてのデバイスで同期できます ウィジェットを更新するための 方法をご紹介します 最初は ウィジェットの 定期的なリロードです この図で 左側のApp Bundleには アプリとWidget Extensionが含まれています 右側のボックスはWidgetKitを表しています iPhoneのホーム画面や Apple Watchの文字盤などで ウィジェットを設定すると WidgetKitはWidget Extensionに タイムラインを要求します Widget Extensionは ウィジェットタイムラインを返します この応答には TimelineReloadPolicyが含まれています WidgetKitはこれに基づいて ウィジェットを 次にリロードするタイミングを決定します TimelineReloadPolicyを使用する方法は 定期的な更新を必要とする ウィジェットに適しています 例えば カフェの営業時間を 表示するウィジェット、 天気予報ウィジェット、 株価ウィジェットなどです パフォーマンスとバッテリー駆動時間を 管理するため タイムラインの定期的なリロードには バジェットが適用されます

    アプリでWidgetCenter APIを 使用する方法もあります ウィジェットに反映する必要がある データ変更がアプリ内で発生した場合 WidgetCenterのreloadAllTimelines またはreloadTimelines(ofKind:)メソッドが 呼びだされます これにより ウィジェットのコンテンツが古くなり リロードする必要があることを WidgetKitに伝えます 通知を受けたWidgetKitは Widget Extensionにタイムラインを要求して ウィジェットを更新します この方法は ウィジェットコンテンツが主に アプリ内で変更される場合に適しています 例えば カフェイン摂取量の更新、 メモの変更、 リマインダーのチェックなどがあります このAPIが呼び出された時点で アプリが実行されるため このリクエストには バジェットが適用されません では サーバ上または別のデバイスで データ変更が発生するとどうなるでしょうか この場合 ウィジェットの プッシュ更新が発生します データ変更を追跡しているサーバが プッシュ通知をAPNsに送信します APNsは アプリのウィジェットを リロードするようWidgetKitに指示します 他の更新と同じように WidgetKitは 最新のタイムラインを ウィジェットに要求します ウィジェットのプッシュ更新は データがそのデバイス以外で 変更される場合に適しています TimelineReloadPolicyと同様 パフォーマンスとバッテリー駆動時間を 管理するため ウィジェットのプッシュ通知更新にも バジェットが適用されます この機能を使用すると それぞれの状況に適した方法で ウィジェットをリロードできます これらは相互に排他的ではありません ウィジェットによっては 複数の方法を使用すると便利です ウィジェットのプッシュ更新を使用すると iPadのアプリ、Vision Proのウィジェット、 macOSのメニューバーコントロールなど カフェイン摂取量を どこで更新するかに関わらず すべてのデバイスで 最新データを確認できます この機能をウィジェットに 追加する方法をご紹介しましょう WidgetPushHandlerを作成して ウィジェット構成に追加します Push Notificationエンタイトルメントを Widget Extensionに追加して ウィジェット更新プッシュリクエストを 作成します まず WidgetPushHandlerプロトコルに 準拠した構造体を作成します このタイプは プッシュトークンの変更または 設定済みのウィジェットの変更を 通知するためのものです pushTokenDidChangeメソッドを使用して プッシュトークンとウィジェットの情報を サーバに送信します 次に ウィジェットの設定を 更新する必要があります ここでは カフェイン摂取量ウィジェットの 設定を使用します pushHandlerモディファイアを ウィジェットに追加して プッシュ通知のサポートを登録します このモディファイアでは 前に実装した ウィジェットpushHandlerのタイプを渡します

    最後に Xcodeで Widget Extensionの タブに移動します ここでPush Notification エンタイトルメントを追加して APNsと通信できるようにします これで ウィジェットの プッシュ更新を設定できました 次に ウィジェット更新のプッシュ通知を 送信する方法を説明します プッシュ通知を使用して ウィジェットを更新するには HTTPS POSTリクエストを Apple Pushサーバに送信します WidgetPushHandlerで リクエストパスの 最後の部分として提供された ウィジェットプッシュトークンを使用します ヘッダーでは APNsプッシュタイプとして 「widgets」を使用し アプリのバンドルIDを使用して apns-topicヘッダーを設定します 末尾に「.push-type.widgets」を付けます リクエストの本文では apsディクショナリで content- changedキーをtrueに設定します プッシュ通知の詳細については 「Push Notifications Primer」をご覧ください 「Meet Push Notifications Console」では プッシュ通知リクエストを簡単に テストする方法をご確認いただけます ウィジェットを最新の状態に維持するには プッシュ更新が役立ちますが 他の通知に常に 優先するものではありません 必要に応じて実行してください 緊急または重要な 更新を表示する場合は ユーザー通知を使用します 飲み物の注文、試合のスコア、 フライト情報など 限られた期間中 更新が定期的に発生する場合は ライブアクティビティを使用します ウィジェットを最新の状態に維持する時は ウィジェットのプッシュ更新を使用します ウィジェットのプッシュ更新は ウィジェット 対応の全プラットフォームで利用できます ウィジェットのプッシュ通知を送信すると 対象デバイスのすべてのプッシュ対応 ウィジェットが更新されます ウィジェットのリロードは バジェットを消費します サーバでの更新を制限するなど 更新プッシュは最小限に抑えてください 開発時やテスト中は 設定でWidgetKitデベロッパモードを 使用すると アプリのプッシュとリロードの バジェットを無視できます 本日は 新しい ウィジェット向けプラットフォームについて 詳しくご説明しました ここで紹介したビデオもぜひご覧ください また iOSとmacOSでは ウィジェットの外観が新しくなります 最後に 外部ソースまたは他のデバイスから ウィジェットのデータを更新する場合は プッシュ通知を追加して 最新の状態に保つことも検討しましょう 本日はウィジェットの様々な新機能や 表示場所をご紹介しました 皆さんのウィジェットでぜひご活用ください ご視聴ありがとうございました

    • 2:44 - Observe .widgetRenderingMode

      struct MostFrequentBeverageWidgetView: View {
          @Environment(\.widgetRenderingMode) var renderingMode
          
          var entry: Entry
          
          var body: some View {
              ZStack {
                  if renderingMode == .fullColor {
                      Image(entry.beverageImage)
                          .resizable()
                          .aspectRatio(contentMode: .fill)
                  
                      LinearGradient(gradient: Gradient(colors: [.clear, .clear, .black.opacity(0.8)]), startPoint: .top, endPoint: .bottom)
                  }
                  
                  VStack {
                      if renderingMode == .accented {
                          Image(entry.beverageImage)
                              .resizable()
                              .widgetAccentedRenderingMode(.desaturated)
                              .aspectRatio(contentMode: .fill)
                      }
                      
                      BeverageTextView()
                  }
              }
          }
      }
    • 6:08 - visionOS Widget Configuration

      struct CaffeineTrackerWidget: Widget {
          var body: some WidgetConfiguration {
              StaticConfiguration(
                  kind: "BaristaWidget",
                  provider: Provider()
              ) { entry in
                  CaffeineTrackerWidgetView(entry: entry)
              }
              .configurationDisplayName("Caffeine Tracker")
              .description("A widget tracking your caffeine intake during the day.")
              .supportedMountingStyles([.elevated])
              .widgetTexture(.paper)
              .supportedFamilies([.systemExtraLargePortrait])
          }
      }
    • 8:56 - LevelOfDetail - CaffeineTrackerWidgetView

      struct CaffeineTrackerWidgetView : View {
          @Environment(\.levelOfDetail) var levelOfDetail
          
          var entry: CaffeineLogEntry
      
          var body: some View {
              VStack(alignment: .leading) {
                  TotalCaffeineView(entry: entry)
      
                  if let log = entry.log {
                      LastDrinkView(log: log)
                  }
      
                  if levelOfDetail == .default {
                      LogDrinkView()
                  }
              }
          }
      }
    • 9:46 - LevelOfDetail - TotalCaffeineView

      struct TotalCaffeineView: View {
          @Environment(\.levelOfDetail) var levelOfDetail
          
          let entry: CaffeineLogEntry
      
          var body: some View {
              VStack {
                  Text("Total Caffeine")
                      .font(.caption)
      
                  Text(totalCaffeine.formatted())
                      .font(caffeineFont)
              }
          }
          
          var caffeineFont: Font {
              if levelOfDetail == .simplified {
                  .largeTitle
              } else {
                  .title
              }
          }
          
          var totalCaffeine: Measurement<UnitMass> {
              entry.totalCaffeine
          }
      }
    • 11:49 - Add .supplementalActivityFamilies

      struct ShopOrderLiveActivity: Widget {
          var body: some WidgetConfiguration {
              ActivityConfiguration(for: Attributes.self) { context in
                  ActivityView(context: context)
              } dynamicIsland: { context in
                  DynamicIsland {
                      DynamicIslandExpandedRegion(.leading) {
                          ExpandedView(context: context)
                      }
                  } compactLeading: {
                      LeadingView(context: context)
                  } compactTrailing: {
                      TrailingView(context: context)
                  } minimal: {
                      MinimalView(context: context)
                  }
              }
              .supplementalActivityFamilies([.small])
          }
      }
    • 12:27 - Add .activityFamily

      struct ActivityView: View {
          @Environment(\.activityFamily) var activityFamily
          var context: ActivityViewContext<Attributes>
          
          var body: some View {
              switch activityFamily {
              case .small:
                  ShopOrderSmallView(context: context)
              default:
                  ShopOrderView(context: context)
              }
          }
      }
    • 16:20 - Define relevance widget with RelevanceConfiguration

      struct HappyHourRelevanceWidget: Widget {
          var body: some WidgetConfiguration {
              RelevanceConfiguration(
                  kind: "HappyHour",
                  provider: Provider()
              ) { entry in
                  WidgetView(entry: entry)
              }
          }
      }
    • 16:41 - Implement RelevanceEntriesProvider

      struct Provider: RelevanceEntriesProvider {
          func placeholder(context: Context) -> Entry {
              Entry()
          }
          
          func relevance() async -> WidgetRelevance<Configuration> {
              let configs = await fetchConfigs()
              var attributes: [WidgetRelevanceAttribute<Configuration>] = []
              
              for config in configs {
                  attributes.append(WidgetRelevanceAttribute(
                      configuration: config,
                      context: .date(interval: config.interval, kind: .default)))
              }
              
              return WidgetRelevance(attributes)
          }
          
          func entry(configuration: Configuration,
                     context: RelevanceEntriesProviderContext) async throws -> Entry {
              Entry(shop: configuration.shop, timeRange: configuration.timeRange)
          }
      }
    • 21:13 - Handle push token and widget configuration changes

      struct CaffeineTrackerPushHandler: WidgetPushHandler {
          func pushTokenDidChange(_ pushInfo: WidgetPushInfo, widgets: [WidgetInfo]) {
              // Send push token and subscription info to server
          }
      }
    • 21:30 - Add pushHandler to WidgetConfiguration

      struct CaffeineTrackerWidget: Widget {
          var body: some WidgetConfiguration {
              StaticConfiguration(
                  kind: Constants.widgetKind,
                  provider: Provider()
              ) { entry in
                  CaffeineTrackerWidgetView(entry: entry)
              }
              .configurationDisplayName("Caffeine Tracker")
              .pushHandler(CaffeineTrackerPushHandler.self)
          }
      }
    • 22:29 - Push Notification Request Body

      {
          "aps": {
              "content-changed": true
          }
      }
    • 0:00 - Introduction
    • Learn about updates to WidgetKit including new ways to incorporate your app with the system, show relevant content in the Smart Stack, and keep your app up to date.

    • 1:03 - Widgets in new places
    • Widgets have new styling options and are available in new places. Check out tips to make your widgets look great with accented rendering mode. Widgets are available in more places, including visionOS 26 and CarPlay. Widgets on visionOS 26 can be added to rooms and pinned to surfaces. These widgets can be customized to support different mounting styles, textures, and level of detail based on proximity. CarPlay and macOS 26 now support Live Activities. Controls are available on macOS Tahoe and watchOS 26.

    • 15:31 - Relevance widgets
    • Relevant widgets show up in the Smart Stack on watchOS 26 when they’re most relevant based on people’s routines, location, and more. These widgets show up in the Smart Stack only when they’re relevant, and multiple instances can show up at the same time, like for overlapping calendar events or happy hours. Build relevant widgets by specifying when the widget is most relevant, like at a particular time or type of location.

    • 18:12 - Push widget updates
    • Widgets across all WidgetKit platforms can now be updated by push updates through APNS. There are multiple tools to keep widgets up to date, and the best tool for each use case is determined by how the data for your widget is updated. Timelines are good for regularly updating data. Changes driven by interaction in an app should reloadAllTimelines. For synchronization between devices, or external data changes, like from a server, use widget push updates. Push updates for widgets help keep widgets more up to date, but aren’t a direct replacement for other notification experiences. Consider whether a User Notification, Live Activity, or widget is best for each use case.

Developer Footer

  • ビデオ
  • WWDC25
  • ウィジェットの新機能
  • メニューを開く メニューを閉じる
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    メニューを開く メニューを閉じる
    • アクセシビリティ
    • アクセサリ
    • App Extension
    • App Store
    • オーディオとビデオ(英語)
    • 拡張現実
    • デザイン
    • 配信
    • 教育
    • フォント(英語)
    • ゲーム
    • ヘルスケアとフィットネス
    • アプリ内課金
    • ローカリゼーション
    • マップと位置情報
    • 機械学習
    • オープンソース(英語)
    • セキュリティ
    • SafariとWeb(英語)
    メニューを開く メニューを閉じる
    • 英語ドキュメント(完全版)
    • 日本語ドキュメント(一部トピック)
    • チュートリアル
    • ダウンロード(英語)
    • フォーラム(英語)
    • ビデオ
    Open Menu Close Menu
    • サポートドキュメント
    • お問い合わせ
    • バグ報告
    • システム状況(英語)
    メニューを開く メニューを閉じる
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles(英語)
    • フィードバックアシスタント
    メニューを開く メニューを閉じる
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(英語)
    • News Partner Program(英語)
    • Video Partner Program(英語)
    • セキュリティ報奨金プログラム(英語)
    • Security Research Device Program(英語)
    Open Menu Close Menu
    • Appleに相談
    • Apple Developer Center
    • App Store Awards(英語)
    • Apple Design Awards
    • Apple Developer Academy(英語)
    • WWDC
    Apple Developerアプリを入手する
    Copyright © 2025 Apple Inc. All rights reserved.
    利用規約 プライバシーポリシー 契約とガイドライン