iOS WidgetでAppIntentを使ってプルダウン選択肢を表示する方法

iOS開発

はじめに

この記事の概要

iOS 17以降で利用できるAppIntentを活用し、Widgetに編集用のプルダウン選択肢を表示する方法を解説します。選択肢にはユーザー設定(UserDefaults)から取得したデータを使用し、動的に反映させる方法を具体的なコード例とともに紹介します。

AppIntentで選択肢付きWidgetを作成する手順

Widgetの作成とIntent対応設定

Widget Extensionで「AppIntent」を選択

Widgetを作成する際に、「Include Configuration Intent(AppIntent)」にチェックを入れることで、初期構成ファイル ConfigurationAppIntent が自動生成されます。

@ParameterにoptionsProviderを使ってプルダウンを実現

DynamicOptionsProviderの活用

コード例:プルダウンを表示するAppIntentの設定

AppIntentで選択肢を表示するには、@ParameteroptionsProviderを指定し、選択肢を返すクラス(DynamicOptionsProvider準拠)を実装します。

@Parameter(
    title: "Favorite Team",
    optionsProvider: TeamNamesOptionsProvider()
)
var favoriteTeam: String?

TeamNamesOptionsProviderは以下のように定義します。

private struct TeamNamesOptionsProvider: DynamicOptionsProvider {
    func results() async throws -> [String] {
        return Teams.createTeamLongNMList()
    }
}

Shared UserDefaultsから選択肢データを取得する方法

AppとWidget間でのデータ共有

SharedDefaultsを使ったJSONデータの読み込み

final class Teams {
    private static let sharedDefaults: UserDefaults = UserDefaults(suiteName: "group.scoreboardMobile.Widget")!

    static func createTeamLongNMList() -> [String] {
        let jsonString = sharedDefaults.string(forKey: "selected_teams") ?? "アプリで選択してください"
        let jsonData = jsonString.data(using: .utf8)!
        let decoder = JSONDecoder()

        do {
            let teams = try decoder.decode([Team].self, from: jsonData)
            return teams.map { $0.teamLongNM }
        } catch {
            print("Failed to decode JSON: \(error)")
            return []
        }
    }
}

注意点:DynamicOptionsProviderはStaticで呼ぶ

Staticでないと値を取得できない理由

optionsProviderがDynamicOptionsProviderのインスタンスを直接受け取る仕様のため、内部で参照するメソッドやプロパティもすべてstaticである必要があります。UserDefaultsからのデータ取得もstatic経由で行うことで、Widgetから正しく選択肢を表示できます。

読者
読者

なんでstaticじゃないと動かないんですか?

ごりら
ごりら

仕様上の制限で、インスタンスメソッドだとWidgetから呼び出す際に適切に初期化されない可能性があるんだ。特にUserDefaultsアクセスはstaticが安全なんだよ。

まとめ

この記事の振り返り

  • WidgetでAppIntentを使えば、編集UIにプルダウンを追加できる
  • @ParameteroptionsProviderを活用し、動的な選択肢表示が可能
  • Shared UserDefaultsを使えば、アプリで設定した値をWidgetに反映できる
  • DynamicOptionsProviderの内部処理はstaticで構築するのが安全

コメント

タイトルとURLをコピーしました