Kotlin Multiplatform 課金とペイウォールの概要

0:02:00

RevenueCatのKMP(Kotlin Multiplatform)SDKコードラボへようこそ!

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

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

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

overview

RevenueCat SDKのインポート

0:07:00

まず最初に、アプリ内課金を実装する前に、RevenueCat SDKを既存または新規プロジェクトにインポートする必要があります。開始するには、build.gradle.ktsファイルに以下の依存関係を追加します:

GitHubで最新リリースバージョンを確認できます。

gradle
[versions]
purchases-kmp = "1.8.6+14.0.2"

[libraries]
purchases-core = { module = "com.revenuecat.purchases:purchases-kmp-core", version.ref = "purchases-kmp" }
purchases-ui = { module = "com.revenuecat.purchases:purchases-kmp-ui", version.ref = "purchases-kmp" }

モジュールのbuild.gradle.ktsでcommonMainソースセットに依存関係を追加できます。

gradle
kotlin {
    // ...
    sourceSets {
        // ...
        commonMain.dependencies {
            // purchases-kmp依存関係を追加
            implementation(libs.purchases.core)
            implementation(libs.purchases.ui)
        }
    }
}

ExperimentalForeignApiのオプトイン

SDKはネイティブiOSコードのKotlin生成バインディングを活用するため、iOSソースセットでExperimentalForeignApiにオプトインする必要があります。これを有効にするには、モジュールのbuild.gradle.ktsファイルに以下の設定を追加します:

kotlin
kotlin {
    // ...
    sourceSets {
        // ...
        named { it.lowercase().startsWith("ios") }.configureEach {
            languageSettings {
                optIn("kotlinx.cinterop.ExperimentalForeignApi")
            }
        }
    }
}

ネイティブiOS SDKのリンク

SDKはネイティブRevenueCat iOSフレームワークPurchasesHybridCommonに依存しているため、既存のiOSプロジェクトにリンクする必要があります。このコードラボでは、CocoaPodsを使用してネイティブiOS SDKを設定します。

完全なKotlinプロジェクトをCocoaPods依存関係として含めることができます。これを行うには、プロジェクトのPodfileで生成された.podspecファイルを含むディレクトリへの名前とパスを指定して依存関係を定義します。

  1. Kotlin CocoaPods GradleプラグインとRevenueCat KMP SDKバージョンをバージョンカタログに追加します。
gradle/libs.versions.tomlファイルの[plugins]ブロックに以下を追加します:
gradle
[versions]
# このバージョンはpurchases-kmpバージョンの'+'の後のすべてと等しい必要があります
purchases-common = "13.3.0"

[plugins]
kotlin-cocoapods = { id = "org.jetbrains.kotlin.native.cocoapods", version.ref = "kotlin" }
  1. ルートのbuild.gradle.ktsファイルで、plugins {}ブロックに以下のエイリアスを追加します:
gradle
alias(libs.plugins.kotlin.cocoapods) apply false
  1. CocoaPodsを統合したいモジュール(例:composeApp)で、そのplugins {}ブロックに同じエイリアスを追加します:
gradle
alias(libs.plugins.kotlin.cocoapods)
  1. 次に、以下のようにcocoapods環境を設定します:
kotlin
kotlin {
    cocoapods {
        // 必須プロパティ
        // ここで必要なPodバージョンを指定
        // それ以外の場合、Gradleプロジェクトバージョンが使用されます
        version = "1.0"
        summary = "Kotlin/Nativeモジュールの説明"
        homepage = "Kotlin/Nativeモジュールのホームページへのリンク"

        // オプションのプロパティ
        // Gradleプロジェクト名を変更する代わりに、ここでPod名を設定
        name = "MyCocoaPod"

        // .. 他のCocoapodsオプションはここに

        // PurchasesHybridCommon依存関係を追加
        pod("PurchasesHybridCommon") {
            version = libs.versions.purchases.common.get()
            extraOpts += listOf("-compiler-option", "-fmodules")
        }
    }
}
  1. 最後に、PodfileのiOSアプリターゲットに以下のpost_installスクリプトを追加します。例えば、Kotlin Multiplatformモジュールの名前がsharedの場合、スクリプトは以下のようになります:
text
target 'iosApp' do
  use_frameworks!
  platform :ios, '16.0'
  pod 'shared', :path => '../shared', :platforms => :ios

  # 以下のpost_installスクリプトを追加:
  post_install do |installer|
    installer.pods_project.targets.each do |target|
      if target.name == 'shared'
        target.build_configurations.each do |config|
          config.build_settings.delete('ASSETCATALOG_COMPILER_APPICON_NAME')
        end
      end
    end
  end
end

RevenueCat SDKのインポートに成功しました。次は初期化ステップに進みましょう。

初期化

0:02:00

次は、プロジェクトでPurchases SDKを初期化する時間です。パブリックAPIキーのみを使用してPurchasesを設定してください。これはプロジェクト設定 > プラットフォームでアプリの設定に移動して見つけることができます。

kotlin
import com.revenuecat.purchases.kmp.LogLevel
import com.revenuecat.purchases.kmp.Purchases
import com.revenuecat.purchases.kmp.configure

// 共通の初期化ロジックがある場合は、そこでconfigure()を呼び出します。
// そうでない場合は、各プラットフォームでアプリのライフサイクルの早い段階で呼び出します。
// 注意:各プラットフォームで正しいAPIキーを使用していることを確認してください。
// これにはKotlin Multiplatformのexpect/actualメカニズムを使用できます。

Purchases.logLevel = LogLevel.DEBUG
Purchases.configure(apiKey = "<google_or_apple_api_key>") {
    appUserId = "<app_user_id>"
    // その他の設定オプション
}

.configureメソッドのapp_user_idフィールドは、RevenueCatがアプリ内のユーザーを識別するために使用されます。カスタムユーザー識別子を提供するか、省略してRevenueCatに匿名IDを自動生成させることができます。詳細については、ユーザーの識別ガイドを参照してください。

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

Entitlementの検証

0:03:00

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

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

以下のコードスニペットを使用して、ユーザーがアクティブなEntitlementを持っているかどうかを簡単に確認できます:

kotlin
val ENTITLEMENT_IDENTIFIER = ".." // RevenueCatダッシュボードから特定のEntitlement識別子を取得
val customerInfo = Purchases.sharedInstance.awaitCustomerInfo()
val isEntitled = customerInfo?.entitlements[ENTITLEMENT_IDENTIFIER]?.isActive == true

ユーザーが特定のEntitlementを持っているかどうかを確認したら、アプリのビジネスモデルに基づいてどのように進めるかを決定できます。

例えば、アプリが広告サポートの場合、AdMobバナーを表示または非表示にすることを選択できます。または、ペイウォールや購入ダイアログを表示して、ユーザーが高度な機能やコンテンツをロック解除できるようにすることもできます。

そのロジックを実装する方法の例を以下に示します:

kotlin
@Composable
fun ContentScreen(isEntitled: Boolean) {
    if (isEntitled) {
      // ユーザーがこのEntitlementへのアクセスを付与されている場合、バナーを表示する必要はありません
    } else {
      // ここでバナーUIを表示するか、ペイウォールを表示
      ..
    }
}

アプリ内課金の実装

0:04:00

次に、広告なし体験を提供するためのアプリ内課金を実装しましょう。開始するには、まずRevenueCatダッシュボードから関連する商品情報を取得する必要があります。この商品データは、ユーザーに購入オプションを提示するために使用されます。

以下の例に示すように、Purchases.sharedInstance.awaitGetProducts()を呼び出すことで利用可能な商品を取得できます:

kotlin
// RevenueCatサーバーから商品情報を取得
val products = Purchases.sharedInstance.awaitGetProducts(
  productIds = listOf("paywall_tester.subs"),
)

// アプリ内課金を進行
val purchaseResult = Purchases.sharedInstance.awaitPurchase(
  storeProduct = products.first()
)

paywall_tester.subs:weeklypaywall_tester.subs:monthlypaywall_tester.subs:yearlyなど、複数の商品バリエーションを提供している場合、productIdsフィールドの値としてベース商品識別子paywall_tester.subsを使用することで商品の取得を簡素化できます。これにより、RevenueCatはすべての関連商品バリエーションをリストとして取得し、ペイウォールUIで動的に提示できます。

商品データを取得したら、Purchases.sharedInstance.awaitPurchase(product)を呼び出すことでアプリ内課金フローを開始できます。これにより自動的にGoogle Play購入ダイアログがトリガーされ、ユーザーはアプリ内でトランザクションを完了できます。

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

ペイウォールの実装

0:07:00

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

ビジネスロジック

まず、RevenueCatダッシュボードから現在のOfferingを取得する必要があります。Offeringは、月額、年額、または生涯プランなど、ユーザーに提示される利用可能な購入オプションを定義します。これは、以下の例に示すように、Purchases.sharedInstance.awaitOfferings()メソッドを使用して簡単に行えます。

kotlin
internal class DetailsRepositoryImpl : DetailsRepository {

  override fun fetchOffering(): Flow<ApiResponse<Offering>> = flow {
    try {
      val offerings = Purchases.sharedInstance.awaitOfferings()
      offerings.current?.let { currentOffering ->
        val response = ApiResponse.of { currentOffering }
        emit(response)
      }
    } catch (e: PurchasesException) {
      ApiResponse.exception(e)
    }
  }
}

RevenueCat KMP SDKにはKotlinコルーチンのネイティブサポートがあり、コルーチンベースのアーキテクチャを使用するプロジェクトにシームレスにフィットします。現在のOfferingはFlowとしても公開されており、変更をリアクティブに観察し、UIを適宜更新できます。

Compose MultiplatformでのペイウォールUI

この時点で、すべての準備が整っているはずです。com.revenuecat.purchases:purchases-kmp-ui SDKを既に追加している場合は、Compose Multiplatformを使用してペイウォールUIを簡単に構築できます。

RevenueCatのUIライブラリは、PaywallDialogなどの組み込みコンポーネントを提供しており、ペイウォール画面やダイアログを素早く表示できます。これらのコンポーネントは完全にカスタマイズ可能で、アプリのデザインに合わせて外観と動作を調整するためのさまざまな設定オプションを提供しています。

Compose Multiplatformを使用してペイウォールを実装およびカスタマイズするのがいかに簡単かを示す例を以下に示します:

kotlin
val currentOffering by viewModel.offering.collectAsState()

val options = remember {
    PaywallOptions(dismissRequest = { TODO("閉じる処理") }) {
        offering = currentOffering
        shouldDisplayDismissButton = true
    }
}

Paywall(options)

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

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

まとめ

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

以下のリソースでRevenueCat SDKの使用についてさらに学ぶこともできます: