iOSアプリ内課金とペイウォールの概要

0:02:00

RevenueCatのiOS SDKコードラボへようこそ!

このコードラボでは、以下のことを行います:

RevenueCat SDKをXcodeプロジェクトに統合 SwiftUIアプリケーションにアプリ内課金を実装 課金ユーザーと非課金ユーザーを区別する方法を学習 RevenueCatのサーバーサイド設定に基づいたSwiftUIでのペイウォール画面を構築

このコードラボを終える頃には、iOSアプリにアプリ内課金を正常に実装し、RevenueCatのiOS SDKとSwiftUIを使用して動的なペイウォールを表示できるようになります。

overview

RevenueCat SDKのインポート

0:05:00

まず最初に、アプリ内課金を実装する前に、RevenueCat SDKをプロジェクトにインポートする必要があります。最も簡単な方法はSwift Package Managerを使用することです。

Xcodeで、Podfileに以下を追加します:

text
pod 'RevenueCat'
pod 'RevenueCatUI'

Xcodeがパッケージを取得します。RevenueCatをアプリのメインターゲットに追加することを確認してください。

事前構築されたペイウォールの実装も予定している場合は、同時にRevenueCatUIライブラリを追加できます。

Getting Your API Key

Before you can initialize the SDK, you'll need your RevenueCat API key. Here's where to find it:

  1. Go to the RevenueCat dashboard
  2. Navigate to your project
  3. Click on API keys in the left sidebar
  4. Copy your Apple App Store API key (it should start with appl_)
Finding your API key in the RevenueCat dashboard
Important: Keep your API keys secure and never commit them to public repositories. Consider using environment variables or a secure configuration management system for production apps.

Initialize the SDK

次に、以下のコードを使用してアプリのinit()メソッドまたはAppDelegateでPurchases SDKを初期化します:

swift
import SwiftUI
import RevenueCat

@main
struct MyApp: App {
    init() {
        // SDKからのすべてのメッセージをログ出力
        Purchases.logLevel = .debug

        // APIキーでSDKを設定
        Purchases.configure(withAPIKey: <public_apple_api_key>, appUserID: <app_user_id>)
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

ユーザー識別: 特定のappUserIDを提供していないため、RevenueCatはユーザーの匿名IDを自動的に生成・管理します。復元機能を適切に使用したい場合は、バックエンドから提供される一意の識別子を設定してください。 トランザクションの完了: デフォルトでは、SDKはApp Storeとのトランザクションの完了を自動的に処理するため、手動で行う必要はありません。

素晴らしい!これで実装の50%が完了しました。

Entitlementの検証

0:03:00

次に、ユーザーのEntitlementの検証に移りましょう。

Entitlementはユーザーが購入後にロック解除するアクセスレベルや機能を表します。これは、広告バナーを表示するかどうか、またはプレミアムアクセスを付与するかどうかを決定するのに役立ちます。

Swiftのモダンなasync/await構文を使用して、ユーザーがアクティブなEntitlementを持っているかどうかを簡単に確認できます:

swift
import SwiftUI
import RevenueCat

struct ContentView: View {
    @State private var isSubscribed: Bool = false

    let ENTITLEMENT_ID = "premium" // RevenueCatダッシュボードからのEntitlement識別子

    var body: some View {
        VStack {
            if isSubscribed {
                PremiumContent()
            } else {
                Text("これは無料コンテンツです。")
                // ここでバナーやペイウォールを表示できます
            }
        }
        .task {
            // ビューが表示されたときにEntitlementを確認
            await checkEntitlement()
        }
    }

    private func checkEntitlement() async {
        do {
            let customerInfo = try await Purchases.shared.customerInfo()
            // Entitlementがアクティブかどうかを確認
            if customerInfo.entitlements[ENTITLEMENT_ID]?.isActive == true {
                self.isSubscribed = true
            } else {
                self.isSubscribed = false
            }
        } catch {
            print("顧客情報の取得エラー: \(error)")
        }
    }
}

ユーザーが特定のEntitlementを持っているかどうかを確認したら、どのように進めるかを決定できます。このSwiftUIの例では、@State変数(isSubscribed)を更新し、ビューが自動的に再レンダリングされ、プレミアムコンテンツまたは無料版のいずれかを表示します。

アプリ内課金の実装

0:04:00

次に、プレミアム体験を提供するためのアプリ内課金を実装しましょう。開始するには、まずRevenueCatで設定した商品を取得する必要があります。このデータは、ユーザーに購入オプションを提示するために使用されます。

Purchases.shared.products(productIdentifiers:)を呼び出すことで利用可能な商品を取得できます:

swift
import RevenueCat

class PurchaseViewModel: ObservableObject {
    func purchase(product: StoreProduct) async {
        do {
            let result = try await Purchases.shared.purchase(product: product)

            // ユーザーがプレミアムの権限を持っているか確認
            if result.customerInfo.entitlements["premium"]?.isActive == true {
                // プレミアムコンテンツをロック解除
                print("購入成功!")
            }
        } catch {
            print("購入エラー: \(error)")
        }
    }

    func fetchProducts() async -> [StoreProduct] {
        do {
            // 識別子を使用して商品を取得
            let products = try await Purchases.shared.products(["premium_monthly", "premium_yearly"])
            return products
        } catch {
            print("商品取得エラー: \(error)")
            return []
        }
    }
}

StoreProductオブジェクトを取得したら、Purchases.shared.purchase(product:)を呼び出すことでアプリ内課金フローを開始できます。これにより自動的にネイティブのApp Store購入シートがトリガーされ、ユーザーはアプリ内でトランザクションを安全に完了できます。

このように、わずか数行のコードで完全に機能するアプリ内課金フローを統合できました—レシート、StoreKit API、または購入検証を手動で処理する複雑さに対処する必要はありません。

ペイウォールの実装

0:07:00

次は、SwiftUIを使用してiOSプロジェクトにペイウォールを実装する時間です。

ビジネスロジック

まず、RevenueCatダッシュボードから現在のOfferingを取得する必要があります。Offeringは、ペイウォールでユーザーに提示される利用可能なパッケージ(月額、年額など)を定義します。これはPurchases.shared.offerings()を使用して簡単に行えます:

swift
import Foundation
import RevenueCat
import SwiftUI

@MainActor // @Publishedプロパティへの変更がメインスレッドで行われることを保証
class PaywallViewModel: ObservableObject {

    // ペイウォールに表示する現在のOfferingを保持
    @Published var offering: Offering?

    // UIでインジケーターを表示するための読み込み状態を追跡
    @Published var isLoading: Bool = false

    init() {
        // ViewModelが作成されるとすぐにOfferingを取得可能
        Task {
            await fetchOffering()
        }
    }

    /**
     * RevenueCatから現在のOfferingを取得し、@Publishedプロパティを更新
     */
    func fetchOffering() async {
        self.isLoading = true

        do {
            let offerings = try await Purchases.shared.offerings()
            // ダッシュボードでこの配置用に設定した「current」のOfferingを取得
            self.offering = offerings.current
        } catch {
            print("Offering取得エラー: \(error.localizedDescription)")
            // UIでもエラー状態を処理したい場合があります
        }

        self.isLoading = false
    }
}

RevenueCat iOS SDKにはSwiftのasync/awaitのネイティブサポートがあり、モダンなSwiftUIアプリケーションにシームレスにフィットします。@Publishedofferingを公開することで、SwiftUIビューが変更をリアクティブに監視できます。

SwiftUIでのペイウォールUI

この時点で、すべての準備が整っています。RevenueCatUIパッケージを追加した場合は、SwiftUIを使用してペイウォールUIを簡単に構築できます。

RevenueCatのUIライブラリは、組み込みのSwiftUIビューPaywallViewを提供しており、ペイウォール画面を素早く表示できます。このコンポーネントは標準的なSwiftUIモディファイアを使用して完全にカスタマイズ可能です。

SwiftUIのsheetモディファイアを使用してペイウォールを実装・表示するのがいかに簡単かを示す例を以下に示します:

swift
import SwiftUI
import RevenueCat
import RevenueCatUI

struct ContentView: View {
    @State private var showPaywall = false

    var body: some View {
        Button("ペイウォールを表示") {
            showPaywall = true
        }
        .sheet(isPresented: $showPaywall) {
            // シートにペイウォールを表示
            PaywallView()
        }
    }
}

PaywallViewは自動的に現在のOfferingを取得し、RevenueCatダッシュボードで設定したテンプレートを使用して表示します。既に取得している場合は、Offeringオブジェクトを直接渡すこともできます:

swift
import SwiftUI
import RevenueCat
import RevenueCatUI

struct ContentView: View {
    // ペイウォールシートの表示をトリガー
    @State private var showPaywall = false

    // ペイウォール用のViewModelのインスタンスを作成
    // @StateObjectはビューと同じライフサイクルを持つことを保証
    @StateObject private var paywallViewModel = PaywallViewModel()

    var body: some View {
        VStack(spacing: 20) {
            Text("アプリへようこそ!")

            Button("プレミアムにアップグレード") {
                // ボタンがタップされたら、シートを表示するフラグを設定
                showPaywall = true
            }
        }
        .sheet(isPresented: $showPaywall) {
            // これはシートのコンテンツです
            // PaywallViewを表示し、ViewModelからOfferingを渡します

            // Offeringを取得中は読み込みインジケーターを表示
            if paywallViewModel.isLoading {
                ProgressView()
            } else if let offering = paywallViewModel.offering {
                // Offeringが利用可能になったら、PaywallViewに渡す
                PaywallView(offering: offering)
            } else {
                // オプション:Offeringを読み込めなかった場合のエラーやメッセージを表示
                Text("申し訳ありません。現在サブスクリプションオプションを読み込めませんでした。")
            }
        }
        .onAppear {
            // ビューが表示されたときにOfferingを更新することもできますが、
            // ViewModelのinitが最初の取得を処理しています
            // Task {
            //     await paywallViewModel.fetchOffering()
            // }
        }
    }
}

アプリのトップレベルビュー(ルートビューなど)にいくつかのモディファイアをアタッチできます。これにより、表示ロジックが自動的に処理されます。

iPhoneでは、RevenueCatペイウォールはシートまたはフルスクリーンのいずれかで表示でき、SwiftUIまたはUIKitに統合するためのいくつかのオプションがあります:

  • presentPaywallIfNeededを使用したEntitlementに基づく自動表示
  • presentPaywallIfNeededを使用したカスタム表示ロジック
  • PaywallViewまたはPaywallViewControllerを使用した手動統合

例えば:

swift
import SwiftUI
import RevenueCat
import RevenueCatUI

@main
struct MyApp: App {
    // ... (initコード) ...

    var body: some Scene {
        WindowGroup {
            ContentView()
                // このモディファイアは「premium」Entitlementを確認します
                // ユーザーがそれを持っていない場合、ペイウォールシートが表示されます
                .presentPaywallIfNeeded(
                    requiredEntitlementIdentifier: "premium",
                    purchaseCompleted: { customerInfo in
                        // ここは購入を祝う絶好の場所です!
                        print("購入完了: \(customerInfo.entitlements)")
                    },
                    restoreCompleted: { customerInfo in
                        // Entitlementがアクティブになった場合、ペイウォールは自動的に閉じます
                        print("復元完了: \(customerInfo.entitlements)")
                    }
                )
        }
    }
}

設定完了!🥳 これで、ユーザーが必要なEntitlementを持っていない場合に、ペイウォールエディターで設定したのとまったく同じデザインでペイウォールを表示できるようになります。

すでに見たように、ペイウォールシステムはサーバードリブンUIに基づいて構築されています。これは、アプリの更新をプッシュしたり、App Storeのレビューを経ることなく、ダッシュボードから直接ペイウォールのコンテンツとデザインを動的に更新できることを意味します。

まとめ

このコードラボでは、RevenueCatのiOS SDKを統合し、アプリ内課金を実装し、SwiftUIでペイウォールを構築する方法を学びました。さあ、アプリをリリースしてもっとお金を稼ぎましょう!💰

以下のリソースを通じて、SwiftUIでのiOSプロジェクトでのRevenueCat SDKの使用についてさらに学ぶこともできます: