TL;DR
StoreKit の Consumable Product が Ask to Buy で購入された場合に検知するには、Transaction.updates の中で Transaction.unfinishedを監視するようにする。
Transaction.updates {
guard
case .verified(let transaction) = verificationResult,
transaction.revocationDate == nil
else { return }
for await verificationResult in Transaction.unfinished {
switch transaction.productType {
case .consumable:
// アプリ内の情報を更新する
default:
break
}
await transaction.finish()
}
}
背景
以前 StoreKit 2 でのアプリ内課金の基本 という記事を書いたのですが、 Transaction.currentEntitlements
について
これで consumable の購入個数を更新できるかと思ったが、transaction が finish() していない consumable があっても currentEntitlements で取得できなかった。
という問題がありました。記事の中ではワークアラウンドコードを仕込んだのですが、それだと Ask to Buy 機能を使った時に consumable product を購入できたことが検知できませんでした。
この問題について Apple Developer Forums で問い合わせていたのですが、回答が得られたので記事として残しておきます。
解決策
当初は Transaction.currentEntitlements
でトランザクションが終了していない consumable product を取得しようとしていました(当時ドキュメントがそうなっていたので)
現在のTransaction.currentEntitlements
のドキュメント を見ると、以下の情報が取得できると書いてあります。
- それぞれの non-consumable product のトランザクション
- 購読中かグレースピリオドの auto-renewable subscription の最新のトランザクション
- 終了後も含めた non-renewing subscription の最新のトランザクション
そして、consumable product に関して以下の記載もありました。
To get transactions for unfinished consumables, use the unfinished or all sequences in Transaction.
なので、consumable product の終了していないトランザクションを取得するには、Transaction.unfinished
か Transaction.all
を使えば良さそうです。
-
Transaction.unfinished
はfinish()
が呼ばれていないトランザクションを取得できます。 -
Transaction.all
は今までのトランザクションの履歴を取得でき、finish()
が呼ばれていない consumable product のトランザクションも含みます。しかし、以下のトランザクションは含まないようです:- 終了した consumable product, non-renewing subscription
- 再購入された non-consumable product, auto-renewing subscription, non-renewing subscription
- 購入の復元
今回は、フォーラムの回答でも提案されていたので、Transaction.unfinished
を使うことにしました。
Transaction.updates {
guard
case .verified(let transaction) = verificationResult,
transaction.revocationDate == nil
else { return }
for await verificationResult in Transaction.unfinished {
switch transaction.productType {
case .consumable:
// アプリ内の情報を更新する
default:
break
}
await transaction.finish()
}
}
Xcode で Ask to Buy を試すと、購入の承認後に無事アプリ内で購入処理のハンドリングができました