Kotlin (Android)
orca-android wraps Google Play Billing so you don’t have to deal with BillingClient connection state, product queries, and acknowledgement flows yourself. You call Orca, it talks to Play Billing and your Orca dashboard underneath.
Requires Java 11+ and minSdk 24.
Install it
Section titled “Install it”Add JitPack as a repository:
dependencyResolutionManagement { repositories { maven { url = uri("https://jitpack.io") } google() mavenCentral() }}Then add the dependency:
implementation("com.github.maxint-app:orca-android:main")The flow, end to end
Section titled “The flow, end to end”1. Configure it once, with a Context
Section titled “1. Configure it once, with a Context”Do this in your Application.onCreate(). It needs an app-level Context because it registers activity lifecycle callbacks internally — that’s how it knows which Activity to launch the Play purchase flow from later.
import com.maxint.orca.core.*
class MyApp : Application() { override fun onCreate() { super.onCreate() Orca.configure( this, OrcaConfiguration( publicKey = "your_public_key", environment = OrcaEnvironment.SANDBOX, // PRODUCTION for release customerEmail = null, ) ) }}2. Identify the customer
Section titled “2. Identify the customer”Call this once you know who’s logged in. Orca uses this email to check and record entitlements — it’s independent of the Google account making the purchase.
Orca.identify("user@example.com")3. Show the paywall
Section titled “3. Show the paywall”queryProducts() fetches your entitlements, queries Play Billing for the matching SKUs, and returns them merged and ready to render:
val products = Orca.queryProducts()
products.forEach { println("${it.name} — ${it.formattedPrice}")}products is List<StoreProduct>, a sealed interface with three concrete types:
when (product) { is StoreProduct.Subscription -> { // product.subscriptionPeriodDays tells you the billing period } is StoreProduct.Consumable -> { // repeatable purchases, like in-game currency } is StoreProduct.NonConsumable -> { // one-time unlocks }}Every type has id, name, price, formattedPrice, currencyCode, and entitlement — the last one is what you hand to purchase.
4. Let them buy it
Section titled “4. Let them buy it”Pass the entitlement from the product the user picked. This must be called from a screen where an Activity is currently in the foreground — that’s how the Play purchase sheet gets launched.
val selected = products.first { it.id == "pro_monthly" }Orca.purchase(selected.entitlement)Trying to buy a non-consumable the customer already owns throws an IllegalStateException instead of double-charging them.
5. Gate features behind what they own
Section titled “5. Gate features behind what they own”val active = Orca.activeEntitlements()val isPro = active.any { it.entitlementId == "pro_tier" }Or work with product data directly if that’s more convenient for your UI:
val activeProducts = Orca.activeProduct()Both of these are safe to call repeatedly — results are cached until the next purchase.
6. Sign out
Section titled “6. Sign out”Orca.logout()A complete mini example
Section titled “A complete mini example”A paywall list in Compose that fetches products and buys the tapped one:
@Composablefun Paywall() { var products by remember { mutableStateOf<List<StoreProduct>>(emptyList()) } val scope = rememberCoroutineScope()
LaunchedEffect(Unit) { products = Orca.queryProducts() }
LazyColumn { items(products) { product -> Button(onClick = { scope.launch { Orca.purchase(product.entitlement) } }) { Text("${product.name} — ${product.formattedPrice}") } } }}What’s in listEntitlements()
Section titled “What’s in listEntitlements()”The raw catalog Orca has configured, without the Play Billing product details merged in. Useful if you want to build your own comparison table:
val entitlements = Orca.listEntitlements()Things worth knowing
Section titled “Things worth knowing”- All the network and billing calls are
suspendfunctions — call them from a coroutine. - Purchases require a visible
Activity; callingpurchasewith the app backgrounded throws. - There’s no built-in purchase event stream in this SDK — after a purchase completes, just re-fetch
activeEntitlements()to refresh your UI state.
Server-side work
Section titled “Server-side work”orca-android is client-only. Cancelling subscriptions, listing customers, or validating webhooks needs a server SDK running on your backend:
- TypeScript server SDK for Node backends
- Go server SDK for Go backends