1. Add repositories to your settings.gradle.kts file:
Ensure you have mavenCentral() and google() in your repositories blocks.
Copy
Ask AI
// settings.gradle.ktspluginManagement { repositories { gradlePluginPortal() google() mavenCentral() }}dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() // You might have other repositories here }}
If you don’t have a dependencyResolutionManagement block, ensure google() and mavenCentral() are present in your pluginManagement { repositories { ... } } block.
2. Add the dependencies to your module-level build.gradle.kts file (e.g., app/build.gradle.kts):
Core (Android View System)
Jetpack Compose UI
RevenueCat
Copy
Ask AI
// app/build.gradle.ktsdependencies { // Choose one of the UI modules: implementation("com.tryhelium.paywall:core:0.1.11") // Other app dependencies}
Copy
Ask AI
// app/build.gradle.ktsdependencies { // Choose one of the UI modules: implementation("com.tryhelium.paywall:compose-ui:0.1.11") // Other app dependencies}
Copy
Ask AI
// app/build.gradle.ktsdependencies { // If you're using RevenueCat, add this dependency: implementation("com.tryhelium.paywall:revenue-cat:0.1.11") // Other app dependencies}
The environment to use: HeliumEnvironment.SANDBOX for development and testing, or HeliumEnvironment.PRODUCTION for your live app. Note that Helium automatically forces SANDBOX for debug builds.
(Optional) If set, a custom user id to use instead of Helium’s. We’ll use this id when forwarding to third party analytics services, so this can be used for attribution (e.g. an amplitude user id, or a custom user id from your own analytics service)
(Optional) Pass in custom user traits to be used for targeting, personalization, and dynamic content. It can be created with a map where keys are strings and values are wrapped in the appropriate HeliumUserTraitsArgument type.
Copy
Ask AI
val customUserTraits = HeliumUserTraits( traits = mapOf( "testTrait" to HeliumUserTraitsArgument.IntParam(1), "account_age_in_days" to HeliumUserTraitsArgument.StringParam("20") ))
(Optional) The logger to use for Helium SDK logging. Defaults to standard output.
Checking Download Status
In most cases there is no need to check download status. Helium will display a loading indication if a paywall is presented before download has completed.
The downloadStatus is a Kotlin Flow that emits HeliumConfigStatus states. The possible states are:
HeliumConfigStatus.NotYetDownloaded: The initial state before the download has started.
HeliumConfigStatus.Downloading: Indicates that the paywall configuration is currently being downloaded.
HeliumConfigStatus.DownloadFailure: Indicates that the paywall configuration download has failed.
HeliumConfigStatus.DownloadSuccess: Indicates that the paywall configuration has been successfully downloaded.
Here’s how you can observe the downloadStatus flow in your Activity or Fragment:
Copy
Ask AI
// In your Activity or FragmentlifecycleScope.launch { Helium.shared.downloadStatus.collect { status -> when (status) { is HeliumConfigStatus.NotYetDownloaded -> { // Handle not yet downloaded state } is HeliumConfigStatus.Downloading -> { // Handle downloading state } is HeliumConfigStatus.DownloadFailure -> { // Handle download failure } is HeliumConfigStatus.DownloadSuccess -> { // Handle download success } } }}
You can provide an implementation of the HeliumPaywallDelegate or use one of the default implementations that we have provided, such as PlayStorePaywallDelegate or RevenueCatPaywallDelegate.
PlayStorePaywallDelegate
RevenueCatPaywallDelegate
Custom Delegate
Use the PlayStorePaywallDelegate to handle purchases using Google Play Billing.
Use the RevenueCatPaywallDelegate to handle purchases if your app is using RevenueCat. Make sure you add the revenue-cat dependency as shown in the installation section.
You can also create a custom delegate and implement your own purchase logic.The HeliumPaywallDelegate is defined as follows:
Copy
Ask AI
interface HeliumPaywallDelegate { suspend fun makePurchase( productDetails: ProductDetails, basePlanId: String?, offerId: String?, ): HeliumPaywallTransactionStatus suspend fun restorePurchases(): Boolean fun onHeliumEvent(event: HeliumEvent)}
The makePurchase function is called by the Helium SDK when a user initiates a purchase. It provides you with the following parameters:
productDetails: The ProductDetails object from the billing library for the selected product.
basePlanId: The identifier of the base plan, if applicable (for subscriptions).
offerId: The identifier of the offer, if applicable (for subscriptions with special offers).
You must have a trigger and workflow configured in the dashboard in order to show a paywall.
The recommended and simplest way to present a paywall is by using the Helium.presentUpsell function. This function handles the creation and presentation of the paywall activity for you.
Copy
Ask AI
// From an Activity or FragmentHelium.presentUpsell( context = this, trigger = "sdk_test")
(Optional) A Boolean to determine if the paywall should be displayed in fullscreen immersive mode, where the system bars (status and navigation) are hidden. Defaults to false.
The Helium SDK allows you to listen for various paywall-related events. This is useful for tracking analytics, responding to user interactions, or handling the paywall lifecycle.There are two ways to listen for events: using the PaywallEventHandlers class for specific callbacks, or implementing the HeliumEventListener interface to receive all events.
You can create an instance of PaywallEventHandlers and provide lambdas for the events you are interested in.The available handlers are:
onOpen: Called when a paywall is displayed to the user.
onClose: Called when a paywall is closed for any reason.
onDismissed: Called when the user explicitly dismisses a paywall without purchasing.
onPurchaseSucceeded: Called when a purchase completes successfully.
onOpenFailed: Called when a paywall fails to open.
onCustomPaywallAction: Called when a custom action is triggered from the paywall.
To register your handlers, use Helium.shared.addPaywallEventListener. You can either tie the listener to a lifecycle (recommended) or manage it manually.Lifecycle-Aware (Recommended)
Pass a LifecycleOwner (like an Activity or Fragment) to have the listener automatically removed when the lifecycle is destroyed.
Copy
Ask AI
class MyActivity : AppCompatActivity() { private val paywallEventHandlers = PaywallEventHandlers( onOpen = { event -> print("Paywall opened: ${event.paywallName}") }, onClose = { event -> print("Paywall closed: ${event.paywallName}") } // ... other event handlers ) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Add the listener once, it will be cleaned up automatically Helium.shared.addPaywallEventListener(this, paywallEventHandlers) }}
Manual Management
If you don’t provide a LifecycleOwner, you are responsible for removing the listener to prevent memory leaks.
Copy
Ask AI
// Add the listeneroverride fun onResume() { super.onResume() Helium.shared.addPaywallEventListener(paywallEventHandlers)}// Remove the listener to avoid leaksoverride fun onPause() { super.onPause() Helium.shared.removeHeliumEventListener(paywallEventHandlers)}
For a more centralized approach, your class can implement the HeliumEventListener interface and handle all events in a single onHeliumEvent method.
Copy
Ask AI
// In your Activity or Fragmentimport com.tryhelium.paywall.core.event.HeliumEventListenerimport com.tryhelium.paywall.core.event.HeliumEventimport com.tryhelium.paywall.core.event.PaywallOpenimport com.tryhelium.paywall.core.event.PaywallCloseclass MyActivity : AppCompatActivity(), HeliumEventListener { override fun onResume() { super.onResume() // Register this class as the listener Helium.shared.addPaywallEventListener(this, this) } override fun onPause() { super.onPause() // Unregister to prevent memory leaks Helium.shared.removeHeliumEventListener(this) } override fun onHeliumEvent(event: HeliumEvent) { when (event) { is PaywallOpen -> { // Handle paywall open } is PaywallClose -> { // Handle paywall close } // ... handle other event types } }}
Usage Suggestions:
Use onDismiss for post-paywall navigation when the paywall is dismissed but a user’s entitlement hasn’t changed
Use onPurchaseSucceeded for your post purchase flow (e.g., a premium onboarding navigation)
Use onClose to handle a paywall close, regardless of reason
If a paywall has not completed downloading when you attempt to present it, a loading state can be displayed. By default, Helium will show this loading state (a shimmer view) for up to 2 seconds (2000ms). You can configure this behavior, turn it off, or set trigger-specific loading budgets using the HeliumFallbackConfig object during initialization.If the loading budget expires before the paywall is ready, a fallback paywall will be shown if one is provided. Otherwise, the loading state will hide, and a PaywallOpenFailed event will be dispatched.There are three options for fallbacks in the Android SDK:
Fallback bundles: A pre-packaged paywall bundle stored in your app’s assets directory.
Default fallback view: A custom Android View to be used for all triggers.
Fallback view per trigger: A map of trigger names to specific Android Views.
All of this is configured via the HeliumFallbackConfig object passed into Helium.initialize().Here are some examples:1. Providing a fallback bundle:Place your fallback JSON file in the src/main/assets directory of your module. Then, initialize Helium with the fallbackBundleName.
Copy
Ask AI
// In your Activity's or Application's onCreate() methodHelium.initialize( // ... other parameters environment = HeliumEnvironment.SANDBOX, // Or HeliumEnvironment.PRODUCTION fallbackConfig = HeliumFallbackConfig.withFallbackBundle( fallbackBundleName = "fallback-bundle-name.json" ))
2. Providing a fallback view and configuring loading budgets:You can also provide a custom View and fine-tune the.
Copy
Ask AI
// In your Activity's or Application's onCreate() methodval fallbackView = YourFallbackView(this) // Your custom fallback viewHelium.initialize( // ... other parameters environment = HeliumEnvironment.SANDBOX, // Or HeliumEnvironment.PRODUCTION fallbackConfig = HeliumFallbackConfig( fallbackView = fallbackView, useLoadingState = true, // Show a loading state before fallback loadingBudgetInMs = 3000, // Global loading budget (in milliseconds) perTriggerLoadingConfig = mapOf( "onboarding" to HeliumFallbackConfig(loadingBudgetInMs = 4000), "quick_upgrade" to HeliumFallbackConfig(useLoadingState = false) ) ))