Highlight
FinanceKit は iOS 18 で導入された新フレームワークで、Apple Wallet の金融データにアクセスする標準化 API を提供します。Apple Card、Apple Savings、Apple Cash のデータをローカルストアに集約し、すべてのデータ処理は端末上で完結、ネットワーク接続は不要です。
主要内容
家計管理アプリ最大の課題はデータが取得できないこと。各銀行の API 形式が統一されず、接入手順も様々で、多くはオープンインターフェースすらありません。ユーザーは手動で取引を入力し、体験が悪く、データも誤りやすい。
FinanceKit がこの状況を変えます。Apple Wallet から直接金融データを読み取り—Apple Card、Apple Savings、Apple Cash の口座、残高、取引記録をすべて 1 つのローカルストアに集約。ネットワーク不要、すべて端末上で処理。複数金融機関との連携は不要—FinanceKit 1 つのフレームワークだけで済みます。
データアクセスには 3 方式があり、権限は弱い順です。最も軽量なのは Transaction Picker—システム UI コンポーネントでユーザーが手動で共有する取引を選択。認可は一時的。次はクエリ API で、ユーザーの明示的認可が必要。特定条件の金融データを一括取得。最後は長期接続クエリ API で、Swift Async Sequences ベース。金融データの変更を継続監視し、History Token で断点再開—アプリ再起動後も前回位置から同期を継続。
詳細
データ可用性チェック
FinanceKit API を呼ぶ前に必ず isDataAvailable をチェック。false のまま呼び続けるとフレームワークがアプリを強制終了—推奨ではなく必須(05:38)。
import FinanceKit
let available = FinanceStore.isDataAvailable(
.financialData
)
guard available else {
// No meaningful action can be performed
return
}
キーポイント:
FinanceStore.isDataAvailable(.financialData)は静的メソッド。インスタンス不要falseのとき他の FinanceKit API を絶対に呼ばない。さもないとアプリ終了- 同じ iOS バージョン内では変化しない。キャッシュ可能
Transaction Picker
ユーザーに数件の取引を選ばせるだけなら(経費精算など)、Transaction Picker が最もシンプル(08:08)。
import SwiftUI
import FinanceKit
import FinanceKitUI
struct TransactionSelector: View {
@State private var selectedItems: [FinanceKit.Transaction] = []
var body: some View {
if FinanceStore.isDataAvailable(.financialData) {
TransactionPicker(selection: $selectedItems) {
Text("Show Transaction Picker")
}
}
}
キーポイント:
FinanceKitUIの追加 import が必要selectionはTransaction配列にバインド。ユーザー選択で直接反映- クロージャにトリガーボタンの ViewBuilder
- 認可は一時的(ephemeral)。Picker は選択を記憶しない
認可とクエリ API
クエリ API はユーザーの明示的認可が必要。Info.plist に NSFinancialDataUsageDescription を追加し、requestAuthorization() を呼ぶ(12:16)。
import FinanceKit
let store = FinanceStore.shared
guard store.isDataAvailable(for: .financialData) else {
return
}
let authStatus = await store.requestAuthorization()
guard authStatus == .authorized else {
return
}
キーポイント:
requestAuthorization()でシステムダイアログが表示。ユーザーが共有する口座を選択- 認可後も設定でいつでも変更・取り消し可能
- App Store 配布には追加の distribution entitlement が必要
口座クエリ
認可後、AccountQuery で口座をクエリ(15:24)。
let store = FinanceStore.shared
let sortDescriptor = SortDescriptor(\Account.displayName)
let predicate = #Predicate<Account> { account in
account.institutionName == "Apple"
}
let query = AccountQuery(
sortDescriptors: [sortDescriptor],
predicate: predicate
)
let accounts : [Account] = try await store.accounts(query: query)
キーポイント:
- Swift の
#Predicateマクロでフィルタ条件を構築 SortDescriptorでソート制御。少なくとも 1 つ指定を推奨- 各データ型に対応する Query クラスがある
残高クエリ
残高クエリは返却数を制限可能。トレンドグラフ描画に適する(18:12)。
func getBalances(account: Account) async throws -> [AccountBalance] {
let sortDescriptor = SortDescriptor(\AccountBalance.asOfDate, order: .reverse)
let predicate = #Predicate<AccountBalance> { balance in
balance.available != nil &&
balance.accountId == account.id
}
let query = AccountBalanceQuery(
sortDescriptors: [sortDescriptor],
predicate: predicate,
limit: 7
)
return try await store.accountBalances(query: query).reversed()
}
キーポイント:
- 日付降順で最新 7 件を取得し、
reversed()で時系列順に復元 asOfDateは残高の計算時刻。データの鮮度判断に使用- 金額は常に正数。方向は
creditDebitIndicatorで区別
長期接続クエリと断点再開
transactionHistory は Async Sequence を返し、変更を継続的にプッシュ(20:27)。
import FinanceKit
let store = FinanceStore.shared
let account: Account = ...
let transactionSequence = store.transactionHistory(
forAccountID: account.id
)
for try await change in transactionSequence {
processChanges(change.inserted, change.updated, change.deleted)
}
since パラメータに前回保存した History Token を渡せば、チェックポイントから再開(21:04)。
import FinanceKit
let store = FinanceStore.shared
let account: Account = ...
let currentToken = loadToken()
let transactionSequence = store.transactionHistory(
forAccountID: account.id,
since: currentToken
)
for try await change in transactionSequence {
processChanges(change.inserted, change.updated, change.deleted)
persist(token: change.newToken)
}
キーポイント:
- 各 change に
inserted、updated、deletedの 3 配列 change.newTokenは Codable で、シリアライズしてディスクに保存可能since: tokenを渡すとその token 以降の増分変更のみ返却- リアルタイム監視が不要なら
isMonitoring: falseを追加。既存変更処理後 Sequence は自動終了
重要ポイント
-
やること:Transaction Picker で「手動取引インポート」機能を実装。価値:Info.plist 説明、認可ダイアログ、entitlement 申請が不要。最低コストで統合。始め方:
FinanceKitUIを import し、ビューにTransactionPickerを配置、@State配列にバインド。 -
やること:History Token で増分同期を実装。価値:起動のたびに全取引を全量取得するとデータ量が多い場合に遅く無駄。Token で増分のみ処理し、パフォーマンスが大幅向上。始め方:change 処理後に
change.newTokenをディスクに永続化。次回起動時にtransactionHistory(forAccountID:since:)に渡す。 -
やること:口座タイプに応じて金額方向を正しく解釈。価値:金額は常に正数。debit/credit の意味は口座タイプ依存—資産口座(Apple Cash)の debit は残高減少、負債口座(Apple Card)の debit は利用可能枠減少。混同するとユーザーに誤った収支統計を表示。始め方:取引リスト表示時に口座が資産か負債かを判断し、
creditDebitIndicatorと組み合わせて収入/支出を決定。 -
やること:データ制限状態の変化を監視。価値:データ可用性(
isDataAvailable)は定数だが、データ制限(restriction)はアプリ実行中に変化する可能性—MDM ポリシー調整など。フレームワークはエラーを投げるがアプリは終了しない。自行処理が必要。始め方:catch 分岐で制限エラーを処理し、現在金融データにアクセスできない旨をユーザーに通知。
関連セッション
- What’s new in Wallet and Apple Pay — Wallet と Apple Pay の最新強化機能
- What’s new in privacy — 新しい権限フローとプライバシー保護メカニズム
- Bring your app’s core features to users with App Intents — App Intents フレームワークの核心概念
- Track model changes with SwiftData history — History API でデータ変更を追跡。FinanceKit の History Token メカニズムと類似
コメント
GitHub Issues · utterances