mcpField
R
relevancekit

relevancekit

github.com/dpearson2699開発1.2k3.1k 回インストール13 週間前に更新
リポジトリ

relevancekit について

relevancekitは、関連性の手がかりでSmart Stackへの表示時期を調整するApple Watchウィジェット開発者向けガイドです。時間、位置情報、フィットネス、睡眠、ハードウェアの条件と権限を扱います。

主な機能

  1. 01時間、位置情報、活動による関連性の設定
  2. 02関連性に基づくウィジェットの構築
  3. 03複数の手がかりの組み合わせと優先順位付け
  4. 04ウィジェットのグループ化と関連付け
  5. 05位置情報、フィットネス、睡眠の権限確認

活用シーン

  1. 01予定の前後にスケジュールウィジェットを表示
  2. 02通勤中や特定の場所で関連情報を表示
  3. 03運動、睡眠、ヘッドフォンの状態に応じたカード表示

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dpearson2699/swift-ios-skills --skill relevancekit

インストール後、Claude Code で/relevancekitを入力して読み込まれたか確認します。

同梱ファイルevals/evals.jsonreferences/relevancekit-patterns.md

詳細

RelevanceKit

デバイス上でコンテキストに応じた手がかりを提供し、Apple Watch の Smart Stack でウィジェットが表示されやすくします。RelevanceKit は、時刻、場所、フィットネスの状態、睡眠スケジュール、接続されたハードウェアに応じて、ウィジェットが「いつ」関連性を持つかをシステムに伝えます。Swift 6.3/watchOS 26+ を対象としています。

ベータ版に関する注意。 RelevanceKit の対応状況や動作について断定的な説明をする前に、Apple のドキュメントを確認し直してください。

関連ウィジェット、タイムラインプロバイダー、グループ化、プレビュー、権限のパターンについて詳しくは、references/relevancekit-patterns.md を参照してください。

内容

概要

watchOS は、Smart Stack 内のウィジェットの関連性を判断するために、次の 2 つの仕組みを使用します。

  1. タイムラインプロバイダーの関連性 — 既存の AppIntentTimelineProvider に relevance() を実装して、タイムライン エントリーに RelevantContext の手がかりを付加します。各プラットフォームで 利用できますが、データを使用するのは watchOS のみです。
  2. 関連ウィジェット — RelevanceConfiguration と RelevanceEntriesProvider を使用して、関連性の手がかりだけを基に動作する ウィジェットを構築します。システムは、関連する各エントリーに対して個別の Smart Stack カードを作成します。watchOS 26+ のみ。

ウィジェットに常に表示するデータがあり、関連性は補助的なものなら、タイムラインプロバイダーを選びます。条件が一致したときだけウィジェットを表示する場合や、複数のカードを同時に表示する場合(例:今後のカレンダーイベントを複数表示する場合)は、関連ウィジェットを選びます。

主な型
型モジュール役割
RelevantContextRelevanceKitコンテキストに応じた手がかり(日時、場所、フィットネス、睡眠、ハードウェア)
WidgetRelevanceWidgetKitウィジェットの種類に対応する関連性属性のコレクション
WidgetRelevanceAttributeWidgetKitウィジェット構成と RelevantContext を組み合わせます
WidgetRelevanceGroupWidgetKitSmart Stack でのグループ化動作を制御します
RelevanceConfigurationWidgetKit関連性の手がかりに基づくウィジェット構成(watchOS 26+)
RelevanceEntriesProviderWidgetKit関連性構成ウィジェットのエントリーを提供します(watchOS 26+)
RelevanceEntryWidgetKit関連ウィジェットのカードを 1 つ描画するために必要なデータ(watchOS 26+)

RelevanceConfiguration、RelevanceEntriesProvider、RelevanceEntry は WidgetKit API です。RelevanceKit の手がかりを公開する watchOS の関連ウィジェットの ワークフローに含まれる場合に限り、このスキルの対象に含めてください。

セットアップ

インポート
import RelevanceKit
import WidgetKit
プラットフォームの対応状況

RelevantContext は複数のプラットフォームで宣言されています(iOS 17+、watchOS 10+)が、 RelevanceKit の機能が有効になるのは watchOS のみです。ほかのプラットフォームで API を呼び出しても、効果はありません。タイムラインプロバイダーの relevance() は、共有プロバイダーコード向けに iOS 18+、macOS 15+、visionOS 26+、watchOS 11+ で利用できます。 RelevanceConfiguration、RelevanceEntriesProvider、RelevanceEntry は watchOS 26+ のみで利用できます。

権限

一部の関連性の手がかりには、権限またはターゲットの設定が必要です。

手がかり必要な権限
.location(inferred:)含有アプリが位置情報へのアクセスを要求し、ウィジェット拡張が NSWidgetWantsLocation を宣言していること
.location(_:) (CLRegion)含有アプリが位置情報へのアクセスを要求し、ウィジェット拡張が NSWidgetWantsLocation を宣言していること
.location(category:)含有アプリが位置情報へのアクセスを要求し、ウィジェット拡張が NSWidgetWantsLocation を宣言していること
.fitness(.workoutActive)HKWorkoutType への HealthKit アクセス
.fitness(.activityRingsIncomplete)appleExerciseTime、appleMoveTime、appleStandTime への HealthKit アクセス
.sleep(_:)HealthKit の sleepAnalysis 権限
.hardware(headphones:)なし
.date(...)なし

位置情報の利用目的を示す文字列は、ウィジェット拡張だけでなく、含有アプリの Info.plist に追加してください。ウィジェットのコードでは、位置情報の手がかりを利用する前に CLLocationManager.isAuthorizedForWidgetUpdates を確認してください。フィットネスおよび睡眠の手がかりを利用するには、HealthKit を有効にし、関連性を提供するアプリとウィジェット拡張のターゲットで、対象となる読み取りタイプを正確に要求してください。

関連性プロバイダー

オプション 1:関連性に対応したタイムラインプロバイダー

既存の AppIntentTimelineProvider に relevance() メソッドを追加します。この方法では、iOS と watchOS でコードを共有しながら、watchOS Smart Stack のインテリジェンスを追加できます。

struct MyProvider: AppIntentTimelineProvider {
    // ... snapshot, timeline, placeholder ...

    func relevance() async -> WidgetRelevance<MyWidgetIntent> {
        let attributes = events.map { event in
            let context = RelevantContext.date(
                from: event.startDate,
                to: event.endDate
            )
            return WidgetRelevanceAttribute(
                configuration: MyWidgetIntent(event: event),
                context: context
            )
        }
        return WidgetRelevance(attributes)
    }
}
オプション 2:RelevanceEntriesProvider(watchOS 26+)

条件に一致した場合にのみ表示されるウィジェットを作成します。システムは relevance() を呼び出してウィジェットがいつ必要になるかを判断し、次に一致した構成で entry() を呼び出して、描画データを取得します。

@available(watchOS 26.0, *)
struct MyRelevanceProvider: RelevanceEntriesProvider {
    func relevance() async -> WidgetRelevance<MyWidgetIntent> {
        let attributes = events.map { event in
            WidgetRelevanceAttribute(
                configuration: MyWidgetIntent(event: event),
                context: RelevantContext.date(event.date, kind: .scheduled)
            )
        }
        return WidgetRelevance(attributes)
    }

    func entry(
        configuration: MyWidgetIntent,
        context: Context
    ) async throws -> MyRelevanceEntry {
        if context.isPreview {
            return .preview
        }
        return MyRelevanceEntry(event: configuration.event)
    }

    func placeholder(context: Context) -> MyRelevanceEntry {
        .placeholder
    }
}

境界の振り分け

ウィジェット、位置情報、ワークアウト、Smart Stack が混在する機能では、RelevanceKit の範囲を RelevantContext、WidgetRelevanceAttribute、プロバイダーの relevance()、RelevantIntentManager、関連ウィジェットへの引き継ぎ、および関連性の手がかりに必要な権限に限定してください。タイムライン、再読み込みの予算、ファミリー、描画、APNs によるウィジェットプッシュ、Live Activities、ウィジェットの Controls は WidgetKit に、HKWorkoutSession、HKLiveWorkoutBuilder、HKWorkoutRoute、クエリ、アクティビティリング/睡眠データ、権限のユーザー体験は HealthKit に、MKLocalSearch、MKLocalSearchCompleter、MKDirections、ジオコーディング、権限、リージョン、ジオフェンシング、場所のデータは MapKit/CoreLocation に振り分けてください。

時間に基づく関連性

時間の手がかりは、特定の時点またはその前後にウィジェットが必要であることをシステムに伝えます。

単一の日付
RelevantContext.date(eventDate)
種類を指定した日付

DateKind は、時間に基づく関連性の性質について追加のヒントを提供します。

種類用途
.default一般的な時間に基づく関連性
.scheduled予定されたイベント(会議、フライト)
.informationalある時点の前後に関連する情報(天気予報)
RelevantContext.date(meetingStart, kind: .scheduled)
日付の範囲
// Using from/to
RelevantContext.date(from: startDate, to: endDate)

// Using DateInterval
RelevantContext.date(interval: dateInterval, kind: .scheduled)

// Using ClosedRange
RelevantContext.date(range: startDate...endDate, kind: .default)

位置情報に基づく関連性

推定された場所

システムは、ユーザーの日課から特定の場所を推定します。座標は必要ありません。

RelevantContext.location(inferred: .home)
RelevantContext.location(inferred: .work)
RelevantContext.location(inferred: .school)
RelevantContext.location(inferred: .commute)

権限の表にある位置情報の項目を適用し、手がかりを返す前に CLLocationManager.isAuthorizedForWidgetUpdates を確認してください。

特定のリージョン
import CoreLocation

let region = CLCircularRegion(
    center: CLLocationCoordinate2D(latitude: 37.3349, longitude: -122.0090),
    radius: 500,
    identifier: "apple-park"
)
RelevantContext.location(region)
POI カテゴリー(26.0+ SDK)

指定したカテゴリーのあらゆる場所の近くで関連性があることを示します。カテゴリーがサポートされていない場合は nil を返します。このファクトリーは Apple プラットフォームの 26.0+ SDK で利用できますが、RelevanceKit の手がかりが Smart Stack の動作に影響するのは、引き続き watchOS のみです。

import MapKit

if let context = RelevantContext.location(category: .beach) {
    // Widget is relevant whenever the person is near a beach
}

フィットネスと睡眠の関連性

フィットネス
// Relevant when activity rings are incomplete
RelevantContext.fitness(.activityRingsIncomplete)

// Relevant during an active workout
RelevantContext.fitness(.workoutActive)

権限に記載されているフィットネスの対応関係を正確に適用してください。

睡眠
// Relevant around bedtime
RelevantContext.sleep(.bedtime)

// Relevant around wakeup
RelevantContext.sleep(.wakeup)

権限に記載されている睡眠の対応関係を適用してください。

ハードウェアに基づく関連性

// Relevant when headphones are connected
RelevantContext.hardware(headphones: .connected)

特別な権限は必要ありません。

シグナルの組み合わせ

WidgetRelevance 配列に複数の WidgetRelevanceAttribute 値を返すと、いくつかの異なる条件下でウィジェットを関連性のあるものにできます。

func relevance() async -> WidgetRelevance<MyIntent> {
    var attributes: [WidgetRelevanceAttribute<MyIntent>] = []

    // Relevant during morning commute
    attributes.append(
        WidgetRelevanceAttribute(
            configuration: MyIntent(mode: .commute),
            context: .location(inferred: .commute)
        )
    )

    // Relevant at work
    attributes.append(
        WidgetRelevanceAttribute(
            configuration: MyIntent(mode: .work),
            context: .location(inferred: .work)
        )
    )

    // Relevant around a scheduled event
    for event in upcomingEvents {
        attributes.append(
            WidgetRelevanceAttribute(
                configuration: MyIntent(eventID: event.id),
                context: .date(event.date, kind: .scheduled)
            )
        )
    }

    return WidgetRelevance(attributes)
}

順序が重要です。 関連性属性は優先度順に返してください。システムは、指定された関連性の一部のみを使用する場合があります。

ウィジェットの統合

RelevanceConfiguration を使用した関連ウィジェット
@available(watchOS 26, *)
struct MyRelevantWidget: Widget {
    var body: some WidgetConfiguration {
        RelevanceConfiguration(
            kind: "com.example.relevant-events",
            provider: MyRelevanceProvider()
        ) { entry in
            EventWidgetView(entry: entry)
        }
        .configurationDisplayName("Events")
        .description("Shows upcoming events when relevant")
    }
}
タイムラインウィジェットとの関連付け

タイムラインウィジェットと関連ウィジェットの両方で同じデータを表示する場合は、 associatedKind を使用してカードの重複を防ぎます。関連ウィジェットが候補として表示されると、 システムはタイムラインウィジェットのカードを関連ウィジェットのカードに置き換えます。

RelevanceConfiguration(
    kind: "com.example.relevant-events",
    provider: MyRelevanceProvider()
) { entry in
    EventWidgetView(entry: entry)
}
.associatedKind("com.example.timeline-events")
グループ化

WidgetRelevanceGroup は、Smart Stack でシステムがウィジェットをどのようにグループ化するかを制御します。

// Opt out of default per-app grouping so each card appears independently
WidgetRelevanceAttribute(
    configuration: intent,
    group: .ungrouped
)

// Named group -- only one widget from the group appears at a time
WidgetRelevanceAttribute(
    configuration: intent,
    group: .named("weather-alerts")
)

// Default system grouping
WidgetRelevanceAttribute(
    configuration: intent,
    group: .automatic
)
RelevantIntent(タイムラインプロバイダーパス)

タイムラインプロバイダーを使用する場合は、タイムラインの更新間も システムが関連性データを保持できるように、RelevantIntentManager も更新します。

import AppIntents

func updateRelevantIntents() async {
    let intents = events.map { event in
        RelevantIntent(
            MyWidgetIntent(event: event),
            widgetKind: "com.example.events",
            relevance: RelevantContext.date(from: event.start, to: event.end)
        )
    }
    try? await RelevantIntentManager.shared.updateRelevantIntents(intents)
}

タイムラインの更新時だけでなく、関連性データが変化するたびにこれを呼び出します。

関連ウィジェットのプレビュー

プレビューのレシピにある エントリー、関連性設定、完全なプロバイダーのレシピを使用します。ウォッチで WidgetKit Developer Mode を有効にし、権限を許可した場合と拒否した場合をテストして、 実機の Apple Watch で仕上げてください。テストのヒントも参照してください。

よくある間違い

  • iOS と同じ動作を期待して RelevanceKit API を使用する。 API はすべての プラットフォームでコンパイルされますが、効果があるのは watchOS のみです。
  • Smart Stack カードが重複する。 同じデータに対してタイムラインウィジェットと 関連ウィジェットの両方を提供する場合は、重複を防ぐために .associatedKind(_:) を使用します。
  • updateRelevantIntents を呼び出さない。 タイムラインプロバイダーを使用する場合、 timeline() 内だけでこれを呼び出すと、更新の間にシステムが古い関連性データを保持してしまいます。 データが変化するたびに更新してください。
  • location(category:) が nil を返す場合を考慮しない。 このファクトリーはオプショナルを返します。 すべての MKPointOfInterestCategory 値がサポートされているわけではありません。

レビューチェックリスト

  • ルーティング:RelevanceKit の効果があるのは watchOS のみであり、WidgetKit、 HealthKit、MapKit、CoreLocation の実装は兄弟スコープ内にとどまっています。
  • シグナル:コンテキストがデータモデルと一致し、属性が優先順位順に並び、 すべての手がかりで Permissions テーブルに記載された設定が正確に使われています。
  • プロバイダー:エントリー、プレースホルダー、関連性、プレビューの各パスがあり、 位置カテゴリのオプショナルとウィジェット更新の認可が処理されています。
  • 調整:.associatedKind(_:) によってカードの重複が防がれ、 タイムラインプロバイダーのデータが変化するたびに updateRelevantIntents が実行されます。
  • テスト:Developer Mode が有効になっており、プレビューで表示サイズと、 権限を許可した状態および拒否した状態が網羅されています。

参考資料

コメント