financekit
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFinanceKit
FinanceKit
Access financial data from Apple Wallet including Apple Card, Apple Cash, and Apple Card Savings. FinanceKit provides on-device, offline access to accounts, balances, and transactions with user-controlled authorization. Targets Swift 6.3 / iOS 26+. Query APIs are available from iOS 17.4; background delivery requires iOS 26.
访问来自Apple Wallet的财务数据,包括Apple Card、Apple Cash和Apple Card Savings。FinanceKit提供设备端离线访问账户、余额和交易的能力,权限由用户控制。适配Swift 6.3 / iOS 26及以上版本。查询API从iOS 17.4开始可用;后台推送功能需要iOS 26及以上版本。
Contents
目录
Setup and Entitlements
设置与权限
Requirements
要求
- Managed entitlement -- request from Apple via the FinanceKit entitlement request form. This is a managed capability; Apple reviews each application.
com.apple.developer.financekit - Organization-level Apple Developer account (individual accounts are not eligible).
- Account Holder role required to request the entitlement.
- 托管权限——通过FinanceKit权限申请表向苹果申请权限。这是一项托管能力,苹果会对每个申请进行审核。
com.apple.developer.financekit - 组织级Apple Developer账户(个人账户不符合申请条件)。
- 需要具备账户持有人角色才能申请该权限。
Project Configuration
项目配置
- Add the FinanceKit entitlement through Xcode managed capabilities after Apple approves the request.
- Add to Info.plist -- this string is shown to the user during the authorization prompt.
NSFinancialDataUsageDescription
xml
<key>NSFinancialDataUsageDescription</key>
<string>This app uses your financial data to track spending and provide budgeting insights.</string>- 苹果批准申请后,通过Xcode托管能力添加FinanceKit权限。
- 在Info.plist中添加——该字符串会在授权弹窗中展示给用户。
NSFinancialDataUsageDescription
xml
<key>NSFinancialDataUsageDescription</key>
<string>This app uses your financial data to track spending and provide budgeting insights.</string>Data Availability
数据可用性
Check whether the device supports FinanceKit before making any API calls. This value is constant across launches and iOS versions.
swift
import FinanceKit
guard FinanceStore.isDataAvailable(.financialData) else {
// FinanceKit not available -- do not call any other financial data APIs.
// The framework terminates the app if called when unavailable.
return
}For Wallet orders:
swift
guard FinanceStore.isDataAvailable(.orders) else { return }Data availability returning does not guarantee data exists on the device. Data access can also become temporarily restricted (e.g., Wallet unavailable, MDM restrictions). Restricted access throws rather than terminating.
trueFinanceError.dataRestricted调用任何API之前先检查设备是否支持FinanceKit。该值在应用启动和iOS版本间保持恒定。
swift
import FinanceKit
guard FinanceStore.isDataAvailable(.financialData) else {
// FinanceKit不可用——请勿调用任何其他财务数据API。
// 若不可用时调用框架,应用会被终止。
return
}针对Wallet订单:
swift
guard FinanceStore.isDataAvailable(.orders) else { return }数据可用性返回不代表设备上一定存在数据。数据访问也可能临时受限(例如Wallet不可用、MDM限制)。访问受限会抛出错误,不会终止应用。
trueFinanceError.dataRestrictedAuthorization
授权
Request authorization to access user-selected financial accounts. The system presents an account picker where the user chooses which accounts to share and the earliest transaction date to expose.
swift
let store = FinanceStore.shared
let status = try await store.requestAuthorization()
switch status {
case .authorized: break // Proceed with queries
case .denied: break // User declined
case .notDetermined: break // No meaningful choice made
@unknown default: break
}请求访问用户选定的财务账户的权限。系统会展示账户选择器,用户可以选择要共享的账户以及可公开的最早交易日期。
swift
let store = FinanceStore.shared
let status = try await store.requestAuthorization()
switch status {
case .authorized: break // 可继续执行查询
case .denied: break // 用户拒绝了授权
case .notDetermined: break // 用户未做出有效选择
@unknown default: break
}Checking Current Status
检查当前授权状态
Query current authorization without prompting:
swift
let currentStatus = try await store.authorizationStatus()Once the user grants or denies access, returns the cached decision without showing the prompt again. Users can change access in Settings > Privacy & Security > Financial Data.
requestAuthorization()无需弹窗即可查询当前授权状态:
swift
let currentStatus = try await store.authorizationStatus()用户授予或拒绝访问后,会返回缓存的决策,不会再次展示弹窗。用户可以在设置 > 隐私与安全性 > 财务数据中修改访问权限。
requestAuthorization()Querying Accounts
查询账户
Accounts are modeled as an enum with two cases: (e.g., Apple Cash, Savings) and (e.g., Apple Card credit). Both share common properties (, , , ) while liability accounts add credit-specific fields.
.asset.liabilityiddisplayNameinstitutionNamecurrencyCodeswift
func fetchAccounts() async throws -> [Account] {
let query = AccountQuery(
sortDescriptors: [SortDescriptor(\Account.displayName)],
predicate: nil,
limit: nil,
offset: nil
)
return try await store.accounts(query: query)
}账户被建模为枚举,包含两个case:(例如Apple Cash、储蓄账户)和(例如Apple Card信用卡)。两者都共享通用属性(、、、),而负债账户额外新增了信贷相关字段。
.asset.liabilityiddisplayNameinstitutionNamecurrencyCodeswift
func fetchAccounts() async throws -> [Account] {
let query = AccountQuery(
sortDescriptors: [SortDescriptor(\Account.displayName)],
predicate: nil,
limit: nil,
offset: nil
)
return try await store.accounts(query: query)
}Working with Account Types
处理账户类型
swift
switch account {
case .asset(let asset):
print("Asset account, currency: \(asset.currencyCode)")
case .liability(let liability):
if let limit = liability.creditInformation.creditLimit {
print("Credit limit: \(limit.amount) \(limit.currencyCode)")
}
}swift
switch account {
case .asset(let asset):
print("资产账户,货币:\(asset.currencyCode)")
case .liability(let liability):
if let limit = liability.creditInformation.creditLimit {
print("信用额度:\(limit.amount) \(limit.currencyCode)")
}
}Account Balances
账户余额
Balances represent the amount in an account at a point in time. A is one of three cases: (includes pending), (posted only), or .
CurrentBalance.available.booked.availableAndBookedswift
func fetchBalances(for accountID: UUID) async throws -> [AccountBalance] {
let predicate = #Predicate<AccountBalance> { balance in
balance.accountID == accountID
}
let query = AccountBalanceQuery(
sortDescriptors: [SortDescriptor(\AccountBalance.id)],
predicate: predicate,
limit: nil,
offset: nil
)
return try await store.accountBalances(query: query)
}余额代表某一时间点账户内的金额。是三个case之一:(包含待处理交易)、(仅已入账交易)或。
CurrentBalance.available.booked.availableAndBookedswift
func fetchBalances(for accountID: UUID) async throws -> [AccountBalance] {
let predicate = #Predicate<AccountBalance> { balance in
balance.accountID == accountID
}
let query = AccountBalanceQuery(
sortDescriptors: [SortDescriptor(\AccountBalance.id)],
predicate: predicate,
limit: nil,
offset: nil
)
return try await store.accountBalances(query: query)
}Reading Balance Amounts
读取余额数值
Amounts are always positive decimals. Use to determine the sign:
creditDebitIndicatorswift
func formatBalance(_ balance: Balance) -> String {
let sign = balance.creditDebitIndicator == .debit ? "-" : ""
return "\(sign)\(balance.amount.amount) \(balance.amount.currencyCode)"
}
// Extract from CurrentBalance enum:
switch balance.currentBalance {
case .available(let bal): formatBalance(bal)
case .booked(let bal): formatBalance(bal)
case .availableAndBooked(let available, _): formatBalance(available)
@unknown default: "Unknown"
}金额始终为正十进制数。使用确定符号:
creditDebitIndicatorswift
func formatBalance(_ balance: Balance) -> String {
let sign = balance.creditDebitIndicator == .debit ? "-" : ""
return "\(sign)\(balance.amount.amount) \(balance.amount.currencyCode)"
}
// 从CurrentBalance枚举中提取:
switch balance.currentBalance {
case .available(let bal): formatBalance(bal)
case .booked(let bal): formatBalance(bal)
case .availableAndBooked(let available, _): formatBalance(available)
@unknown default: "Unknown"
}Querying Transactions
查询交易记录
Use with Swift predicates, sort descriptors, limit, and offset.
TransactionQueryswift
let predicate = #Predicate<Transaction> { $0.accountID == accountID }
let query = TransactionQuery(
sortDescriptors: [SortDescriptor(\Transaction.transactionDate, order: .reverse)],
predicate: predicate,
limit: 50,
offset: nil
)
let transactions = try await store.transactions(query: query)使用带Swift谓词、排序描述符、limit和offset的。
TransactionQueryswift
let predicate = #Predicate<Transaction> { $0.accountID == accountID }
let query = TransactionQuery(
sortDescriptors: [SortDescriptor(\Transaction.transactionDate, order: .reverse)],
predicate: predicate,
limit: 50,
offset: nil
)
let transactions = try await store.transactions(query: query)Reading Transaction Data
读取交易数据
swift
let amount = transaction.transactionAmount
let direction = transaction.creditDebitIndicator == .debit ? "spent" : "received"
print("\(transaction.transactionDescription): \(direction) \(amount.amount) \(amount.currencyCode)")
// merchantName, merchantCategoryCode, foreignCurrencyAmount are optionalswift
let amount = transaction.transactionAmount
let direction = transaction.creditDebitIndicator == .debit ? "支出" : "收入"
print("\(transaction.transactionDescription): \(direction) \(amount.amount) \(amount.currencyCode)")
// merchantName、merchantCategoryCode、foreignCurrencyAmount为可选值Built-In Predicate Helpers
内置谓词助手
FinanceKit provides factory methods for common filters:
swift
// Filter by transaction status
let bookedOnly = TransactionQuery.predicate(forStatuses: [.booked])
// Filter by transaction type
let purchases = TransactionQuery.predicate(forTransactionTypes: [.pointOfSale, .directDebit])
// Filter by merchant category
let groceries = TransactionQuery.predicate(forMerchantCategoryCodes: [
MerchantCategoryCode(rawValue: 5411) // Grocery stores
])FinanceKit为常见筛选场景提供了工厂方法:
swift
// 按交易状态筛选
let bookedOnly = TransactionQuery.predicate(forStatuses: [.booked])
// 按交易类型筛选
let purchases = TransactionQuery.predicate(forTransactionTypes: [.pointOfSale, .directDebit])
// 按商户类别筛选
let groceries = TransactionQuery.predicate(forMerchantCategoryCodes: [
MerchantCategoryCode(rawValue: 5411) // 杂货店
])Transaction Properties Reference
交易属性参考
| Property | Type | Notes |
|---|---|---|
| | Unique per device |
| | Links to parent account |
| | When the transaction occurred |
| | When booked; nil if pending |
| | Always positive |
| | |
| | Display-friendly description |
| | Raw institution description |
| | Merchant name if available |
| | ISO 18245 code |
| | |
| | |
| | Foreign currency if applicable |
| | Exchange rate if applicable |
| 属性 | 类型 | 说明 |
|---|---|---|
| | 设备内唯一 |
| | 关联所属账户 |
| | 交易发生时间 |
| | 入账时间;待处理交易为nil |
| | 始终为正 |
| | |
| | 适合展示的描述 |
| | 机构原始描述 |
| | 商户名称(若可用) |
| | ISO 18245编码 |
| | |
| | |
| | 外币金额(若适用) |
| | 汇率(若适用) |
Long-Running Queries and History
长时查询与历史记录
Use -based history APIs for live updates or resumable sync. These return (inserted, updated, deleted items) plus a for resumption.
AsyncSequenceFinanceStore.ChangesHistoryTokenswift
func monitorTransactions(for accountID: UUID) async throws {
let history = store.transactionHistory(
forAccountID: accountID,
since: loadSavedToken(),
isMonitoring: true // true = keep streaming; false = terminate after catch-up
)
for try await changes in history {
// changes.inserted, changes.updated, changes.deleted
saveToken(changes.newToken)
}
}使用基于的历史记录API实现实时更新或可恢复同步。这些API返回(插入、更新、删除的项目)以及用于恢复查询的。
AsyncSequenceFinanceStore.ChangesHistoryTokenswift
func monitorTransactions(for accountID: UUID) async throws {
let history = store.transactionHistory(
forAccountID: accountID,
since: loadSavedToken(),
isMonitoring: true // true = 持续推送;false = 追上历史数据后终止
)
for try await changes in history {
// changes.inserted、changes.updated、changes.deleted
saveToken(changes.newToken)
}
}History Token Persistence
历史记录Token持久化
HistoryTokenCodableswift
func saveToken(_ token: FinanceStore.HistoryToken) {
if let data = try? JSONEncoder().encode(token) {
UserDefaults.standard.set(data, forKey: "financeHistoryToken")
}
}
func loadSavedToken() -> FinanceStore.HistoryToken? {
guard let data = UserDefaults.standard.data(forKey: "financeHistoryToken") else { return nil }
return try? JSONDecoder().decode(FinanceStore.HistoryToken.self, from: data)
}If a saved token points to compacted history, the framework throws . Discard the token and start fresh.
FinanceError.historyTokenInvalidHistoryTokenCodableswift
func saveToken(_ token: FinanceStore.HistoryToken) {
if let data = try? JSONEncoder().encode(token) {
UserDefaults.standard.set(data, forKey: "financeHistoryToken")
}
}
func loadSavedToken() -> FinanceStore.HistoryToken? {
guard let data = UserDefaults.standard.data(forKey: "financeHistoryToken") else { return nil }
return try? JSONDecoder().decode(FinanceStore.HistoryToken.self, from: data)
}如果保存的Token指向已压缩的历史记录,框架会抛出错误。请丢弃该Token并重新开始查询。
FinanceError.historyTokenInvalidAccount and Balance History
账户与余额历史记录
swift
let accountChanges = store.accountHistory(since: nil, isMonitoring: true)
let balanceChanges = store.accountBalanceHistory(forAccountID: accountID, since: nil, isMonitoring: true)swift
let accountChanges = store.accountHistory(since: nil, isMonitoring: true)
let balanceChanges = store.accountBalanceHistory(forAccountID: accountID, since: nil, isMonitoring: true)Transaction Picker
交易选择器
For apps that need selective, ephemeral access without full authorization, use from FinanceKitUI. Access is not persisted -- transactions are passed directly for immediate use.
TransactionPickerswift
import FinanceKitUI
struct ExpenseImportView: View {
@State private var selectedTransactions: [Transaction] = []
var body: some View {
if FinanceStore.isDataAvailable(.financialData) {
TransactionPicker(selection: $selectedTransactions) {
Label("Import Transactions", systemImage: "creditcard")
}
}
}
}对于需要选择性、临时访问且无需完整授权的应用,可以使用FinanceKitUI提供的。访问权限不会持久化——交易将直接传递给应用供即时使用。
TransactionPickerswift
import FinanceKitUI
struct ExpenseImportView: View {
@State private var selectedTransactions: [Transaction] = []
var body: some View {
if FinanceStore.isDataAvailable(.financialData) {
TransactionPicker(selection: $selectedTransactions) {
Label("导入交易记录", systemImage: "creditcard")
}
}
}
}Wallet Orders
Wallet订单
FinanceKit supports saving and querying Wallet orders (e.g., purchase receipts, shipping tracking).
FinanceKit支持保存和查询Wallet订单(例如购买收据、物流跟踪)。
Saving an Order
保存订单
swift
let result = try await store.saveOrder(signedArchive: archiveData)
switch result {
case .added: break // Saved
case .cancelled: break // User cancelled
case .newerExisting: break // Newer version already in Wallet
@unknown default: break
}swift
let result = try await store.saveOrder(signedArchive: archiveData)
switch result {
case .added: break // 已保存
case .cancelled: break // 用户取消
case .newerExisting: break // Wallet中已有更新版本
@unknown default: break
}Checking for an Existing Order
检查是否存在已有订单
swift
let orderID = FullyQualifiedOrderIdentifier(
orderTypeIdentifier: "com.merchant.order",
orderIdentifier: "ORDER-123"
)
let result = try await store.containsOrder(matching: orderID, updatedDate: lastKnownDate)
// result: .exists, .newerExists, .olderExists, or .notFoundswift
let orderID = FullyQualifiedOrderIdentifier(
orderTypeIdentifier: "com.merchant.order",
orderIdentifier: "ORDER-123"
)
let result = try await store.containsOrder(matching: orderID, updatedDate: lastKnownDate)
// result: .exists、.newerExists、.olderExists 或 .notFoundAdd Order to Wallet Button (FinanceKitUI)
添加订单到Wallet按钮(FinanceKitUI)
swift
import FinanceKitUI
AddOrderToWalletButton(signedArchive: orderData) { result in
// result: .success(SaveOrderResult) or .failure(Error)
}swift
import FinanceKitUI
AddOrderToWalletButton(signedArchive: orderData) { result in
// result: .success(SaveOrderResult) 或 .failure(Error)
}Background Delivery
后台推送
iOS 26+ supports background delivery extensions that notify your app of financial data changes outside its lifecycle. Requires App Groups to share data between the app and extension.
iOS 26及以上版本支持后台推送扩展,可在应用生命周期外通知应用财务数据变更。需要使用App Groups在应用和扩展间共享数据。
Enabling Background Delivery
启用后台推送
swift
try await store.enableBackgroundDelivery(
for: [.transactions, .accountBalances],
frequency: .daily
)Available frequencies: , , .
.hourly.daily.weeklyDisable selectively or entirely:
swift
try await store.disableBackgroundDelivery(for: [.transactions])
try await store.disableAllBackgroundDelivery()swift
try await store.enableBackgroundDelivery(
for: [.transactions, .accountBalances],
frequency: .daily
)可用频率:(每小时)、(每天)、(每周)。
.hourly.daily.weekly禁用选择性或完全禁用后台推送:
swift
try await store.disableBackgroundDelivery(for: [.transactions])
try await store.disableAllBackgroundDelivery()Background Delivery Extension
后台推送扩展
Create a background delivery extension target in Xcode (Background Delivery Extension template). Both the app and extension must belong to the same App Group.
swift
import FinanceKit
struct MyFinanceExtension: BackgroundDeliveryExtension {
var body: some BackgroundDeliveryExtensionProviding { FinanceDataHandler() }
}
struct FinanceDataHandler: BackgroundDeliveryExtensionProviding {
func didReceiveData(for dataTypes: [FinanceStore.BackgroundDataType]) async {
for dataType in dataTypes {
switch dataType {
case .transactions: await processNewTransactions()
case .accountBalances: await updateBalanceCache()
case .accounts: await refreshAccountList()
@unknown default: break
}
}
}
func willTerminate() async { /* Clean up */ }
}在Xcode中创建后台推送扩展目标(后台推送扩展模板)。应用和扩展必须属于同一个App Group。
swift
import FinanceKit
struct MyFinanceExtension: BackgroundDeliveryExtension {
var body: some BackgroundDeliveryExtensionProviding { FinanceDataHandler() }
}
struct FinanceDataHandler: BackgroundDeliveryExtensionProviding {
func didReceiveData(for dataTypes: [FinanceStore.BackgroundDataType]) async {
for dataType in dataTypes {
switch dataType {
case .transactions: await processNewTransactions()
case .accountBalances: await updateBalanceCache()
case .accounts: await refreshAccountList()
@unknown default: break
}
}
}
func willTerminate() async { /* 清理资源 */ }
}Common Mistakes
常见错误
1. Calling APIs when data is unavailable
1. 数据不可用时调用API
DON'T -- skip availability check:
swift
let store = FinanceStore.shared
let status = try await store.requestAuthorization() // Terminates if unavailableDO -- guard availability first:
swift
guard FinanceStore.isDataAvailable(.financialData) else {
showUnavailableMessage()
return
}
let status = try await FinanceStore.shared.requestAuthorization()错误做法——跳过可用性检查:
swift
let store = FinanceStore.shared
let status = try await store.requestAuthorization() // 不可用时会终止应用正确做法——先判断可用性:
swift
guard FinanceStore.isDataAvailable(.financialData) else {
showUnavailableMessage()
return
}
let status = try await FinanceStore.shared.requestAuthorization()2. Ignoring the credit/debit indicator
2. 忽略借贷指示器
DON'T -- treat amounts as signed values:
swift
let spent = transaction.transactionAmount.amount // Always positiveDO -- apply the indicator:
swift
let amount = transaction.transactionAmount.amount
let signed = transaction.creditDebitIndicator == .debit ? -amount : amount错误做法——将金额视为有符号值:
swift
let spent = transaction.transactionAmount.amount // 始终为正正确做法——应用指示器判断符号:
swift
let amount = transaction.transactionAmount.amount
let signed = transaction.creditDebitIndicator == .debit ? -amount : amount3. Not handling data restriction errors
3. 未处理数据受限错误
DON'T -- assume authorized access persists:
swift
let transactions = try await store.transactions(query: query) // Fails if Wallet restrictedDO -- catch :
FinanceErrorswift
do {
let transactions = try await store.transactions(query: query)
} catch let error as FinanceError {
if case .dataRestricted = error { showDataRestrictedMessage() }
}错误做法——假设授权访问会一直有效:
swift
let transactions = try await store.transactions(query: query) // Wallet受限时会失败正确做法——捕获:
FinanceErrorswift
do {
let transactions = try await store.transactions(query: query)
} catch let error as FinanceError {
if case .dataRestricted = error { showDataRestrictedMessage() }
}4. Requesting full snapshots instead of resumable queries
4. 请求全量快照而非可恢复查询
DON'T -- fetch everything on every launch:
swift
let allTransactions = try await store.transactions(query: TransactionQuery(
sortDescriptors: [SortDescriptor(\Transaction.transactionDate)],
predicate: nil, limit: nil, offset: nil
))DO -- use history tokens for incremental sync:
swift
let history = store.transactionHistory(
forAccountID: accountID,
since: loadSavedToken(),
isMonitoring: false
)
for try await changes in history {
processChanges(changes)
saveToken(changes.newToken)
}错误做法——每次启动都拉取所有数据:
swift
let allTransactions = try await store.transactions(query: TransactionQuery(
sortDescriptors: [SortDescriptor(\Transaction.transactionDate)],
predicate: nil, limit: nil, offset: nil
))正确做法——使用历史记录Token进行增量同步:
swift
let history = store.transactionHistory(
forAccountID: accountID,
since: loadSavedToken(),
isMonitoring: false
)
for try await changes in history {
processChanges(changes)
saveToken(changes.newToken)
}5. Not persisting history tokens
5. 未持久化历史记录Token
DON'T -- discard the token:
swift
for try await changes in history {
processChanges(changes)
// Token lost -- next launch reprocesses everything
}DO -- save every token:
swift
for try await changes in history {
processChanges(changes)
saveToken(changes.newToken)
}错误做法——丢弃Token:
swift
for try await changes in history {
processChanges(changes)
// Token丢失——下次启动会重新处理所有数据
}正确做法——保存每次返回的Token:
swift
for try await changes in history {
processChanges(changes)
saveToken(changes.newToken)
}6. Misinterpreting credit/debit on liability accounts
6. 误解负债账户的借贷标记
Both asset and liability accounts use for outgoing money. But means different things: on an asset account it means money received; on a liability account it means a payment or refund that increases available credit. See references/financekit-patterns.md for a full interpretation table.
.debit.credit资产和负债账户都使用表示流出资金。但的含义不同:在资产账户中表示资金入账;在负债账户中表示还款或退款,会增加可用信用额度。完整的解释表请查看references/financekit-patterns.md。
.debit.creditReview Checklist
审核清单
- checked before any API call
FinanceStore.isDataAvailable(.financialData) - entitlement requested and approved by Apple
com.apple.developer.financekit - set in Info.plist with a clear, specific message
NSFinancialDataUsageDescription - Organization-level Apple Developer account used
- Authorization status handled for all cases (,
.authorized,.denied).notDetermined - caught and handled gracefully
FinanceError.dataRestricted - applied correctly to amounts (not treated as signed)
CreditDebitIndicator - History tokens persisted for resumable queries
- handled by discarding token and restarting
FinanceError.historyTokenInvalid - Long-running queries use when live updates are not needed
isMonitoring: false - Transaction picker used when full authorization is unnecessary
- Only data the app genuinely needs is queried
- Deleted data from history changes is removed from local storage
- Background delivery extension in same App Group as the main app (iOS 26+)
- Financial data deleted when user revokes access
- 调用任何API前已检查
FinanceStore.isDataAvailable(.financialData) - 已申请并获得苹果批准的权限
com.apple.developer.financekit - Info.plist中已设置,且信息清晰具体
NSFinancialDataUsageDescription - 使用的是组织级Apple Developer账户
- 已处理所有授权状态情况(、
.authorized、.denied).notDetermined - 已捕获并妥善处理错误
FinanceError.dataRestricted - 已正确对金额应用(未直接视为有符号值)
CreditDebitIndicator - 已持久化历史记录Token用于可恢复查询
- 已处理错误,方式为丢弃Token并重启查询
FinanceError.historyTokenInvalid - 不需要实时更新时,长时查询设置了
isMonitoring: false - 不需要完整授权时使用了交易选择器
- 仅查询应用真实需要的数据
- 历史记录变更中的已删除数据已从本地存储中移除
- 后台推送扩展与主应用属于同一个App Group(iOS 26及以上)
- 用户撤销访问时已删除相关财务数据
References
参考资料
- Extended patterns (predicates, sorting, pagination, currency formatting, background updates): references/financekit-patterns.md
- FinanceKit framework
- FinanceKitUI framework
- FinanceStore
- Transaction
- Account
- AccountBalance
- FinanceKit entitlement
- Implementing a background delivery extension
- Meet FinanceKit (WWDC24)
- 扩展模式(谓词、排序、分页、货币格式化、后台更新):references/financekit-patterns.md
- FinanceKit框架
- FinanceKitUI框架
- FinanceStore
- Transaction
- Account
- AccountBalance
- FinanceKit权限
- 实现后台推送扩展
- 认识FinanceKit (WWDC24)