概要
0:01:00購入の復元は、サブスクリプションやアプリ内課金を販売するすべての iOS アプリにとって基本的な機能です。 Apple の App Store Review Guidelines では、アプリ内課金を提供するすべてのアプリに、ユーザーが購入を復元できる手段を用意することが義務づけられています。 これがないと、審査でアプリがリジェクトされることがあります。
ユーザーが復元を必要とする代表的な場面は次のとおりです。
- アプリを削除したあとに再インストールしたとき
- 新しい iPhone や iPad をセットアップするとき
- 同じ Apple ID でサインインした 2 台目の端末にアプリをダウンロードしたとき
- ローカルの購入状態が失われたアプリのアップデート後
前提条件
- RevenueCat iOS SDK がインストールされている(Swift Package Manager または CocoaPods 経由)
- App のエントリーポイントで API キーを使って SDK を構成済み
- RevenueCat のダッシュボードにエンタイトルメントが少なくとも 1 つ構成されている
restorePurchases() API
0:01:30
RevenueCat の restorePurchases() メソッドは、次の処理を順に実行します。
- 端末から現在の App Store レシートを取得する
- Apple での検証のため、レシートを RevenueCat のサーバーに送信する
- 有効なサブスクリプションや購入を現在の顧客レコードに同期する
- すべての有効なエンタイトルメントを含む、更新された
CustomerInfoオブジェクトを返す
Swift の最新の async/await 構文を使った基本的な使い方は次のとおりです。
// Basic restore using async/await
do {
let customerInfo = try await Purchases.shared.restorePurchases()
if customerInfo.entitlements["premium"]?.isActive == true {
// User has premium access
print("Purchases restored successfully")
} else {
print("No active purchases found to restore")
}
} catch {
print("Error restoring purchases: \(error.localizedDescription)")
}
返される CustomerInfo オブジェクトは、復元後のユーザーの現在のサブスクリプション状態を反映します。
エンタイトルメントは、プロダクト ID ではなく、必ず識別子(たとえば "premium")で確認してください。
こうすると、機能のゲート処理を特定のプロダクトから切り離しておけます。
SwiftUI での実装
0:02:30
次に示すのは、単体で動作する本番向けの RestorePurchasesButton という SwiftUI ビューです。
ローディング状態を扱い、結果をアラートで表示し、二重タップを防ぐために非同期処理の間はボタン自身を無効化します。
import SwiftUI
import RevenueCat
struct RestorePurchasesButton: View {
@State private var isRestoring = false
@State private var showAlert = false
@State private var alertMessage = ""
var body: some View {
Button(action: restorePurchases) {
if isRestoring {
ProgressView()
.progressViewStyle(.circular)
} else {
Text("Restore Purchases")
}
}
.disabled(isRestoring)
.alert("Restore Purchases", isPresented: $showAlert) {
Button("OK") { }
} message: {
Text(alertMessage)
}
}
private func restorePurchases() {
isRestoring = true
Task {
do {
let customerInfo = try await Purchases.shared.restorePurchases()
if customerInfo.entitlements.active.isEmpty {
alertMessage = "No active purchases found. If you believe this is an error, please contact support."
} else {
alertMessage = "Your purchases have been successfully restored!"
}
} catch {
alertMessage = "Failed to restore purchases: \(error.localizedDescription)"
}
isRestoring = false
showAlert = true
}
}
}
このボタンをペイウォールや設定画面に置きます。
struct PaywallView: View {
var body: some View {
VStack(spacing: 16) {
// ... your pricing options ...
RestorePurchasesButton()
.font(.footnote)
.foregroundColor(.secondary)
}
}
}
UIKit での実装
0:02:00まだ SwiftUI に移行していないアプリ向けに、クロージャベースのコールバック API を使った UIKit の実装は次のとおりです。
@IBAction func restorePurchasesTapped(_ sender: UIButton) {
sender.isEnabled = false
Purchases.shared.restorePurchases { customerInfo, error in
sender.isEnabled = true
if let error = error {
self.showAlert(title: "Error", message: error.localizedDescription)
return
}
if customerInfo?.entitlements["premium"]?.isActive == true {
self.showAlert(title: "Success", message: "Purchases restored successfully!")
self.updateUIForPremium()
} else {
self.showAlert(
title: "Not Found",
message: "No active purchases found. Contact support if you believe this is an error."
)
}
}
}
private func showAlert(title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true)
}
組み込みの復元ボタン
0:01:30
RevenueCat の ペイウォール (RevenueCatUI の PaywallView または
PaywallViewController) を使っている場合、「購入を復元」ボタンは自動的に含まれます。
自分で追加する必要はありません。
この組み込みボタンは、RevenueCat のすべてのペイウォールテンプレートの下部に表示され、上記の手動実装とまったく同じように動作します。
完全にカスタムなペイウォール UI を構築している場合は、上記の
RestorePurchasesButton コンポーネントを使ってください。
import RevenueCatUI
// RevenueCat's PaywallView includes a restore button automatically
struct AppPaywall: View {
var body: some View {
// The restore purchases button is built in, no extra code needed
PaywallView()
}
}
重要な注意点
0:01:30restorePurchases() を呼び出すと、RevenueCat は新しい匿名 ID を作成することがあります。
アプリ独自の認証システムがある場合は、復元を呼び出す前に
Purchases.shared.logIn(appUserID:) でユーザーをログインさせ、購入が正しいアカウントに
ひも付くようにしてください。
restorePurchases() は、ユーザーが明示的に復元ボタンをタップしたときにのみ呼び出してください。
アプリ起動のたびに自動で呼び出すのは不要で、App Store へのネットワークリクエストが発生し、
アプリの起動を遅くする可能性があります。
関連ガイド
- iOS アプリ内課金の完全チュートリアル: RevenueCat の iOS 連携をエンドツーエンドで解説
- Android (Kotlin) で購入を復元する: このガイドの Android 版
- iOS でサブスクリプション状態を確認する: CustomerInfo を使った機能ゲートの方法
- トラブルシューティング: RevenueCat のよくある問題と解決策