Kotlin quickstart

Add Voidhash to a native Android app and show your first paywall.

This guide adds Voidhash to an existing Android app. By the end you will have the SDK installed, a paywall on screen, and an access check that gates a premium feature.

Before you start

  • Your app sets minSdk 23.
  • You build with AGP 8.9.0.
  • You build with Kotlin 2.0.21.

Install the SDK

Add the SDK to your Gradle build. The SDK ships as a Gradle module inside the npm package @voidhash/android, so point your build at the installed package directory.

settings.gradle.kts
includeBuild("node_modules/@voidhash/android")

Then depend on the module from your app.

app/build.gradle.kts
dependencies {
    implementation("com.voidhash.sdk")
}

If you prefer to vendor the sources, include them directly instead.

settings.gradle.kts
include(":voidhash-core", ":voidhash-sdk")
project(":voidhash-core").projectDir = file("third_party/voidhash/core")
project(":voidhash-sdk").projectDir = file("third_party/voidhash/sdk")

Add the billing permission to your manifest. The SDK contributes INTERNET through its own manifest, so you do not need to add that one.

<uses-permission android:name="com.android.vending.BILLING" />

Make sure Play Billing 8.0.0, Play Services Base, OkHttp 4.x, and kotlinx-coroutines are on the runtime classpath.

Configure the client

Create the client in your Application class with your project's publishable key.

App.kt
import com.voidhash.sdk.Voidhash
import com.voidhash.sdk.VoidhashOptions
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.lifecycle.lifecycleScope

class App : Application() {
    override fun onCreate() {
        super.onCreate()

        val voidhash = Voidhash.configure(
            context = this,
            publishableKey = "vh_pk_...",
            options = VoidhashOptions(debug = BuildConfig.DEBUG),
        )

        ProcessLifecycleOwner.get().lifecycleScope.launch {
            voidhash.initialize()
        }
    }
}

The publishable key is safe to include in the app. Never ship vh_sk_... secret keys.

configure is synchronous and cheap. initialize() does the real work: it connects to Google Play, resolves the project schema, and reconciles anything the store still reports as unfinished. You can call initialize() repeatedly. Only the first successful call does work, and a failed call can be retried. The client is also reachable as Voidhash.shared.

Configure one test offer in Studio

Set up the smallest catalog that can show a paywall and grant access.

  1. Create a perk such as premium.
  2. Create a product, choose its billing duration, and attach the perk.
  3. Create a paywall that includes the product, then publish it.
  4. Create a paywall location such as onboarding and assign the published paywall.

Connect Google Play Console before you test a release build. See Store setup for the steps. For the model behind the catalog, see Products and perks and Paywalls.

Present the paywall

Resolve the paywall assigned to a location and present it from an activity.

voidhash.presentPaywall(activity, location = "onboarding", listener = object : PaywallListener {
    override fun onPurchaseCompleted(transaction: VoidhashTransaction) = unlockPremium()
    override fun onEvent(name: String, properties: Map<String, Any?>) = track(name, properties)
    override fun onDismiss() = Unit
})

presentPaywall returns false when the backend has no published paywall for the location. Fall back to your own screen instead of leaving the customer with nothing.

The SDK presents the paywall fullscreen and speaks the paywall bridge protocol natively, so the paywall's actions work without extra code. Purchases, restores, close, and external links are handled for you. Custom events and logs are forwarded to the listener.

Check access

Gate a feature on an active perk grant from the person snapshot.

val person = voidhash.getCurrentPerson()

val hasPremium = person?.activePerkIds?.contains("premium") == true

The snapshot refreshes after a successful purchase or restore. See Check access for caching behavior and failure handling.

Run a test purchase

Build and run the app, then buy through the presented paywall. Use a device signed into an account in a Play testing track.

Purchases sync to the server first. The SDK acknowledges the purchase only after validation succeeds. Consumables are consumed instead of acknowledged.

Next steps