Kotlin quickstart
Add Voidhash to a native Android app, buy a product and unlock a perk.
Install the Kotlin SDK in an existing Android app, sell a product, and unlock a perk with a test purchase. The test purchase runs in development mode, so you don't need Google Play Console yet.
Before you start
- Your app sets
minSdk23 andcompileSdk35, and builds with Android Gradle Plugin 8.9.0 and Kotlin 2.0.21. - In Studio, you have a project with a perk
premiumand a productpro_monthlythat unlocks it and has a billing duration. See Products and perks.
Set up
Install the SDK
The SDK is distributed as source in the Voidhash repository. Clone it into your project:
git clone https://github.com/voidhashcom/voidhash.git third_party/voidhashInclude the SDK's Gradle build in yours:
includeBuild("third_party/voidhash/libraries/android")Depend on the SDK. Gradle substitutes the included module for this coordinate, so it needs no version:
android {
buildFeatures {
buildConfig = true
}
}
dependencies {
implementation("com.voidhash:sdk")
implementation("androidx.lifecycle:lifecycle-process:2.8.7")
}The included build needs to find the Android SDK too: set ANDROID_HOME, or copy your project's
local.properties into third_party/voidhash/libraries/android.
To pin a commit, see Install.
Add the billing permission to AndroidManifest.xml. The SDK's manifest contributes the others.
<uses-permission android:name="com.android.vending.BILLING" />Configure the client
Configure Voidhash in your Application class, and register it with android:name=".App" on the
manifest's <application> element.
import android.app.Application
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.voidhash.sdk.Voidhash
import com.voidhash.sdk.VoidhashOptions
import kotlinx.coroutines.launch
class App : Application() {
override fun onCreate() {
super.onCreate()
val voidhash = Voidhash.configure(
context = this,
publishableKey = if (BuildConfig.DEBUG) "vh_pk_test_..." else "vh_pk_...",
options = VoidhashOptions(
debug = BuildConfig.DEBUG,
dev = BuildConfig.DEBUG,
),
)
ProcessLifecycleOwner.get().lifecycleScope.launch {
voidhash.initialize()
}
}
}Debug builds use the test publishable key and buy from a simulated store; release builds use the production key and Google Play. Copy both keys from Settings → API keys. See API keys.
configure returns at once. initialize() connects to Google Play, loads your project's
configuration and resumes unfinished purchases. Elsewhere in your app, reach the client through
Voidhash.shared.
Show products and buy
Load your products, show the price, and buy pro_monthly from an activity:
import android.os.Bundle
import android.widget.Button
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.lifecycle.lifecycleScope
import com.voidhash.sdk.Voidhash
import com.voidhash.sdk.VoidhashException
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.launch
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val voidhash = Voidhash.shared ?: return
val button = Button(this).also { setContentView(it) }
lifecycleScope.launch {
val product = voidhash.getProducts().firstOrNull { it.slug == "pro_monthly" }
?: return@launch
button.text = "Upgrade for ${product.displayPrice}"
button.setOnClickListener {
lifecycleScope.launch {
try {
voidhash.purchase(this@MainActivity, product)
if (voidhash.getCurrentPerson()?.hasActivePerk("premium") == true) {
button.text = "Premium unlocked"
}
} catch (error: CancellationException) {
throw error
} catch (error: VoidhashException) {
when (error.code) {
"USER_CANCELLED" -> Unit
"PURCHASE_PENDING" -> show("Waiting for approval.")
else -> show("Purchase failed: ${error.description}")
}
}
}
}
}
}
private fun show(message: String) {
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
}
}purchase opens the purchase sheet, sends the purchase to Voidhash and refreshes the person.
USER_CANCELLED means the person closed the sheet, which isn't a failure. PURCHASE_PENDING waits
for approval, such as a pending payment method; the SDK unlocks the perk once it completes. See
Make and restore purchases for every failure.
Check access
Gate premium features on the perk, not on the purchase result:
import com.voidhash.sdk.Voidhash
suspend fun hasPremium(): Boolean =
Voidhash.shared?.getCurrentPerson()?.hasActivePerk("premium") == trueThe SDK refreshes the person after every purchase and restore. See Check access for caching and offline behavior.
Test a purchase
Run a debug build on a device or emulator and tap the button. A Test purchase confirmation sheet replaces Google Play's, and the button changes to "Premium unlocked". The purchase appears in Studio under the Test environment.
Buy through Google Play (optional)
Once the simulated purchase works, test the real Google Play sheet. License testers aren't charged.
- Connect Google Play (Help center) and map
pro_monthlyto your Play product. - Add your Google account as a license tester and as a tester of an internal test track.
- Upload a release build, which uses the production key without
dev, to that track and install it from Google Play.
The purchase appears in Studio under Sandbox. See Test purchases (Help center).
Next steps
- See a complete sample app: products, restore, a paywall with a fallback screen, sign-in and a feature flag.
- Identify users when they sign in.
- Troubleshooting when something doesn't work.
- Show a paywall designed in Studio.
Something wrong or missing on this page? Tell us by email or on Discord.