Skip to main content

Kotlin Multiplatform

What is RevenueCat?โ€‹

RevenueCat provides a backend and a wrapper around StoreKit and Google Play Billing to make implementing in-app purchases and subscriptions easy. With our SDK, you can build and manage your app business on any platform without having to maintain IAP infrastructure. You can read more about how RevenueCat fits into your app or you can sign up free to start building.

Requirementsโ€‹

Android 5.0+ (API 21+)
iOS 13.0+

Installationโ€‹

Adding the dependencyโ€‹

Purchases for Kotlin Multiplatform (Google Play and iOS App Store) is available on Maven Central and can be included via Gradle.

Release

Add the following coordinates to your libs.versions.toml.

[versions] 
purchases-kmp = "1.1.0+13.3.0"

[libraries]
# Required
purchases-core = { module = "com.revenuecat.purchases:purchases-kmp-core", version.ref = "purchases-kmp" }
# Optional: adds extension properties representing timestamps as kotlinx-datetime Instants.
purchases-datetime = { module = "com.revenuecat.purchases:purchases-kmp-datetime", version.ref = "purchases-kmp" }
# Optional: adds suspending functions that return Arrow's Either to indicate success / failure.
purchases-either = { module = "com.revenuecat.purchases:purchases-kmp-either", version.ref = "purchases-kmp" }
# Optional: adds suspending functions that return kotlin.Result to indicate success / failure.
purchases-result = { module = "com.revenuecat.purchases:purchases-kmp-result", version.ref = "purchases-kmp" }

You can now add the dependency to your commonMain source set in your module's build.gradle.kts.

kotlin {
// ...
sourceSets {
// ...
commonMain.dependencies {
// Add the purchases-kmp dependencies.
implementation(libs.purchases.core)
implementation(libs.purchases.datetime) // Optional
implementation(libs.purchases.either) // Optional
implementation(libs.purchases.result) // Optional
}
}
}

Opt in to ExperimentalForeignApiโ€‹

Since the SDK uses generated Kotlin bindings for native code on iOS, you will need to opt in to ExperimentalForeignApi in your iOS source sets. To do so, add the following to your module's build.gradle.kts.

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

Since the SDK depends on a native RevenueCat iOS framework, PurchasesHybridCommon, this will need to be linked to your existing iOS project. You have 2 options do to so: using Swift Package Manager and using CocoaPods. It's easiest to pick the dependency manager you're already using in your iOS project.

Using Swift Package Managerโ€‹

To add PurchasesHybridCommon to your iOS project using Swift Package Manager, do the following:

  1. Select File ยป Add Packages Dependencies... and enter the repository URL https://github.com/RevenueCat/purchases-hybrid-common into the search bar (top right).
  2. Then set the Dependency Rule to Exact, and specify the version number to be equal to everything after the '+' in the purchases-kmp version.
  3. When "Choose Package Products for purchases-hybrid-common" appears, select PurchasesHybridCommon. If you plan to use Paywalls, select PurchasesHybridCommonUI too.
  4. Lastly, click "Add Package".

The library should now have been added to the Package Dependencies section.

Using CocoaPodsโ€‹

There are 2 approaches to add PurchasesHybridCommon to your iOS project using CocoaPods. The approach depends on how you currently integrate your existing Kotlin Multiplatform code with your iOS project.

1. Directly as a local iOS frameworkโ€‹

Follow these instructions if your Kotlin Multiplatform module is integrated directly with your iOS project as a local iOS framework. That is, Xcode is calling the embedAndSignAppleFrameworkForXcode Gradle task (or the old packForXcode task) as part of the build. At the time of writing, if you generated your Kotlin Multiplatform project using the online wizard, this is how it's set up.

In this scenario, you need to specify the transitive dependency on PurchasesHybridCommon in your Podfile. Add the following:

# This version must be equal to everything after the '+' in the purchases-kmp version.
pod 'PurchasesHybridCommon', '13.3.0'
2. Using Cocoapodsโ€‹

Follow these instructions if your Kotlin Multiplatform module is integrated with your iOS project using CocoaPods. That is, you've applied the kotlin("native.cocoapods") Gradle plugin, and set it up such that the Podfile specifies a dependency on your Kotlin Multiplatform module. (See also the Kotlin docs.)

In this scenario, you can specify the transitive dependency on PurchasesHybridCommon using Gradle. To do so, add the following to your libs.versions.toml:

[versions] 
# This version must be equal to everything after the '+' in the purchases-kmp version.
purchases-common = "13.3.0"

Now you can add the following to your module's build.gradle.kts:

kotlin {
// ...
cocoapods {
// Your existing Cocoapods options are here.

// Add the PurchasesHybridCommon dependency.
pod("PurchasesHybridCommon") {
version = libs.versions.purchases.common.get()
extraOpts += listOf("-compiler-option", "-fmodules")
}
}
}

Set the correct launchMode for Androidโ€‹

Depending on your user's payment method, they may be asked by Google Play to verify their purchase in their (banking) app. This means they will have to background your app and go to another app to verify the purchase. If your Activity's launchMode is set to anything other than standard or singleTop, backgrounding your app can cause the purchase to get cancelled. To avoid this, set the launchMode of your Activity to standard or singleTop in your Android app's AndroidManifest.xml file:

<activity 
android:name="com.your.Activity"
android:launchMode="standard" /> <!-- or singleTop -->

You can find Android's documentation on the various launchMode options here.

Import Purchasesโ€‹

You should now be able to import Purchases.

import com.revenuecat.purchases.kmp.CustomerInfo
import com.revenuecat.purchases.kmp.Entitlement
import com.revenuecat.purchases.kmp.Offering
import com.revenuecat.purchases.kmp.Purchases
import com.revenuecat.purchases.kmp.models.Period
import com.revenuecat.purchases.kmp.models.Price
import com.revenuecat.purchases.kmp.models.StoreProduct
โš ๏ธ

On Android, Purchases uses AndroidX App Startup under the hood. Make sure you have not removed the androidx.startup.InitializationProvider completely in your manifest. If you need to remove specific initializers, such as androidx.work.WorkManagerInitializer, set tools:node="merge" on the provider, and tools:node="remove" on the meta-data of the initializer you want to remove.

 <provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>

Next Stepsโ€‹