WWDC Quick Look 💓 By SwiftGGTeam
Bring your app's core features to users with App Intents

Bring your app's core features to users with App Intents

元の動画を見る

ハイライト

App Intents は Siri、Spotlight、Shortcuts、Widget、Control Center などすべてのシステム統合の統一プロトコル層——Intent、Entity、Query を 1 回定義すれば、複数のシステム入口を同時に駆動できます。


主要内容

App がどれだけ優れていても、ユーザーが開かなければ何も見えません。Christopher Nebel は冒頭で率直な比喩を使います。各 App は丁寧に作られた「箱」で、箱の中の体験は完璧ですが、箱同士を行き来すること自体が摩擦(friction)です。App の切り替えには時間と注意力が必要で、この小さな摩擦が繰り返されるとユーザーの操作フロー(flow)が途切れます。

App Intents が解決するのはこの問題です。システムが App 内の中核的なアクションとコンテンツオブジェクトを理解し、Spotlight 検索提案、Siri 会話、ホーム画面 Widget、Control Center コントロール、Action Button、Apple Pencil Pro のスクイーズなどに直接表示します。ユーザーは App を開かずに重要な操作を完了できます。セッション全体をハイキングルート App でデモ:最もシンプルな OpenPinnedTrailIntent から始め、パラメータ付き Intent、設定可能 Widget、Control Center ボタン、App Shortcut へ段階的に拡張。同一の Entity と Query が異なる機能間で再利用される様子を示します。

重要な洞察はコード再利用です。OpenTrail Intent 用に定義した TrailEntityTrailEntityQuery は、Widget の設定パラメータ、Control Center のボタン設定、Siri の自然言語インタラクションで直接使用可能。1 回書けば、どこでも効く。


詳細

Intent:アクションの定義(09:31

Intent は AppIntent プロトコルに準拠する型で、2 つを提供する必要があります:title(ローカライズされたタイトル。Shortcuts ではアクション名として表示)と perform() メソッド(実際の操作を実行)。

struct OpenPinnedTrailIntent: AppIntent {
    static var title: LocalizedStringResource = "Open Pinned Trail"

    static var openAppWhenRun = true

    func perform() throws -> some IntentResult {
// ピン留めされたルート詳細ページへ移動
        TrailNavigator.navigateToPinnedTrail()
        return .result()
    }
}

キーポイント:

  • title はローカライズ文字列。Shortcuts App ではそのままアクション名
  • openAppWhenRun = true で実行時に App をフォアグラウンドに開く
  • perform()IntentResult を返す。ここでは .result() のみ(ページ遷移だけで十分)
  • Intent 名はユーザーが理解できるアクション(OpenPinnedTrail)。内部実装名は使わない

Entity + Query:コンテンツと検索ロジック(12:13

Entity は App 内の「名詞」——中核的なコンテンツオブジェクト。AppEntity プロトコルに準拠し、displayRepresentation(表示用)、id(永続識別子)、query(クエリオブジェクト)を提供。

struct TrailEntity: AppEntity {
    static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Trail")
    static var defaultQuery = TrailEntityQuery()

    var id: UUID
    var name: String

    var displayRepresentation: DisplayRepresentation {
        DisplayRepresentation(title: "\(name)")
    }
}

Query は 2 つの質問に答えます:選択可能な Entity は?特定 ID に対応する Entity は?最もシンプルな方法は EnumerableEntityQuery に準拠し、allEntities() を提供:

struct TrailEntityQuery: EntityQuery, EnumerableEntityQuery {
    func allEntities() async throws -> [TrailEntity] {
// すべてのルートを返す。データ量をすべてメモリに読み込める場合に適している
        TrailStore.shared.allTrails.map { trail in
            TrailEntity(id: trail.id, name: trail.name)
        }
    }

    func entities(for identifiers: [UUID]) async throws -> [TrailEntity] {
// ID に基づいて検索し、Intent 実行時にパラメータを復元するために使う
        allEntities().filter { identifiers.contains($0.id) }
    }
}

キーポイント:

  • iOS 18 SDK でビルドすると、EnumerableEntityQuery から検索、述語クエリなどより複雑なクエリプロトコルを自動派生可能(14:18
  • データ量が大きくメモリに全部載せられない場合は EntityStringQuery など他のサブプロトコルに切り替え
  • Query の entities(for:) で Intent 実行時に保存された ID を完全な Entity オブジェクトに復元。Intent コードは裸の ID ではなく Entity を取得

パラメータ付き Intent:OpenIntent(11:04

Intent がユーザー選択のコンテンツオブジェクトを受け取る必要がある場合、OpenIntent プロトコルを使用:

struct OpenTrailIntent: OpenIntent {
    static var title: LocalizedStringResource = "Open Trail"

    @Parameter(title: "Trail")
    var target: TrailEntity

    func perform() throws -> some IntentResult {
        TrailNavigator.navigateToTrail(id: target.id)
        return .result()
    }
}

キーポイント:

  • OpenIntentopenAppWhenRun を暗黙的に含む。手動宣言不要
  • @Parameter マークのプロパティは Shortcuts のパラメータ選択 UI に自動表示。Query が候補を提供
  • パラメータ型は Entity 自体(TrailEntity)。Entity を記述するデータ(trail name や UUID)ではない

Parameter Summary:Shortcuts で読みやすい操作説明(15:00

static var parameterSummary: some ParameterSummary {
    Summary("Open \.$target")
}

キーポイント:

  • parameterSummary がないと Shortcuts ではパラメータがリスト下部に折りたたまれ読みにくい
  • 追加すると「Open Monterey Bay Coastal Trail」のような自然言語文として表示
  • ユーザーがパラメータを編集するとプレースホルダーがリアルタイムで置換され、操作意図が一目瞭然

Widget と Control Center:既存 Entity の再利用(16:59

Widget の設定 Intent は WidgetConfigurationIntent に準拠。以前定義した TrailEntity をパラメータ型として直接再利用。Control Center の設定可能コントロールも同様に ControlConfigurationIntent プロトコルを使用:

extension OpenTrailIntent: ControlConfigurationIntent {}
// 空の extension。OpenTrailIntent は必要なものをすでに備えている

キーポイント:

  • 1 つの Intent が複数の設定プロトコルに同時準拠可能。Widget と Control Center 用に別 Intent を書く必要なし
  • Control Center ボタンのタップアクションは設定済み Intent インスタンスを直接渡せる。perform() とパラメータ値を既に持っている

App Shortcut:Spotlight と Siri に自動表示(20:40

struct TrailAppShortcuts: AppShortcutsProvider {
    static var appShortcuts: [AppShortcut] {
        AppShortcut(
            intent: OpenPinnedTrailIntent(),
            phrases: [
                "Open my pinned trail in \(.applicationName)"
            ],
            shortTitle: "Open Pinned Trail",
            systemImageName: "pin.fill"
        )
    }
}

キーポイント:

  • App Shortcut がラップするのは Intent インスタンス(型ではない)。登録時にパラメータを事前入力可能
  • phrases には \.applicationName を必ず含める。Siri が音声指令をマッチするために必要
  • 手動登録コード不要——フレームワークが AppShortcutsProvider を自動検出。App インストール後すぐ使用可能
  • 既存 App Shortcut は今年 Apple Pencil Pro スクイーズを、昨年 Action Button を自動サポート(22:30

Dialog + Snippet を返して App を開かない(22:56

Siri が Intent を実行するとき、ページ操作ではなく情報表示だけなら、Dialog と SwiftUI ビューを含む結果を返して App 遷移を避けられる:

struct ShowPinnedTrailIntent: AppIntent {
    static var title: LocalizedStringResource = "Show Pinned Trail Conditions"

    func perform() async throws -> some IntentResult & ProvidesDialog & ShowsSnippetView {
        let trail = TrailStore.shared.pinnedTrail
        return .result(
            dialog: "\(trail.name) conditions: \(trail.conditions)",
            view: TrailConditionsView(trail: trail)
        )
    }
}

キーポイント:

  • ProvidesDialog で Siri がテキストを読み上げ、ShowsSnippetView で画面上に SwiftUI スニペットを表示
  • Dialog とビューテキストは異なってよい。読み上げ版と視覚版でそれぞれ重点を置ける
  • ビューは Widget と同じアーカイブ機構。Widget がサポートする SwiftUI 機能のみ使用可能
  • ユーザーは Snippet を見た後その場に留まり、App に飛ばされない

重要ポイント

  • やること:中核コンテンツモデルに AppEntity + EntityQuery を定義。理由:Entity はすべての App Intents 機能の基盤。1 回定義すれば Shortcuts パラメータ選択、Widget 設定、Control Center 設定、Siri の自然言語理解がすべて自動でサポートされ、以降の拡張コストはゼロ。始め方:App で最も中核的な 1〜2 データモデルを選び、AppEntity に準拠。displayRepresentationidEnumerableEntityQuery を実装。

  • やること:最高頻度の操作を App Shortcut に。理由:App Shortcut はインストール即生效。Spotlight 提案と Siri に自動表示。ユーザー設定不要で中核機能に到達——ROI 最高の統合方式。始め方:最もよく使う 1〜2 操作(「最近のドキュメントを開く」「お気に入りを表示」など)を見つけ、AppShortcutsProvider で App Shortcut にラップ。phrases と shortTitle を書く。

  • やること:同じ Intent で複数のシステム入口を駆動。理由:セッションの OpenTrailIntent が Shortcuts アクション、Widget 設定、Control Center ボタン、Siri 指令の底层実装として同時に機能。コードは 1 回だけ。1 つの Intent が複数プロトコル(OpenIntent + WidgetConfigurationIntent + ControlConfigurationIntent)に準拠すれば全シーンをカバー。始め方:既存 SiriKit Intent やカスタム URL Scheme 処理を App Intent に統一移行し、プロトコル拡張で Widget と Control Center を段階的に接続。


関連セッション

コメント

GitHub Issues · utterances