Skip to main content

Background

Get set up with the Helium SDK for Android. Reach out over your Helium slack channel or email [email protected] for any questions.

Installation

Add the Helium SDK to your project using Gradle.

Requirements

  • Kotlin Version: 2.0.0 or higher
  • Java Version: 8 or higher
  • Minimum Android SDK: 23 or higher
  • Compile Android SDK: 35 or higher

1. Add repositories to your settings.gradle.kts file:

Ensure you have mavenCentral() and google() in your repositories blocks.
// settings.gradle.kts

pluginManagement {
    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
// app/build.gradle.kts

dependencies {
    // Choose one of the UI modules:
    implementation("com.tryhelium.paywall:core:0.1.11")
    // Other app dependencies
}

Initialize Helium

You need to initialize Helium before you can present a paywall. The best place to do this is in your MainActivity’s onCreate() method.
// In your MainActivity class's onCreate() method
import com.tryhelium.paywall.core.HeliumEnvironment

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val heliumPaywallDelegate = PlayStorePaywallDelegate(this) // Or your custom delegate

        Helium.initialize(
            context = this,
            apiKey = "YOUR_API_KEY",
            heliumPaywallDelegate = heliumPaywallDelegate,
            environment = HeliumEnvironment.SANDBOX // Or HeliumEnvironment.PRODUCTION
        )
    }
}
Helium.initialize
method
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:
// In your Activity or Fragment
lifecycleScope.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
            }
        }
    }
}

HeliumPaywallDelegate

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.

Presenting Paywalls

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.
// From an Activity or Fragment
Helium.presentUpsell(
    context = this,
    trigger = "sdk_test"
)
Helium.presentUpsell
method
Looking for alternative presentation methods? Check out the guide on Ways to Show a Paywall.

PaywallEventHandlers

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.

Option 1: Using PaywallEventHandlers

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.
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.
// Add the listener
override fun onResume() {
    super.onResume()
    Helium.shared.addPaywallEventListener(paywallEventHandlers)
}

// Remove the listener to avoid leaks
override fun onPause() {
    super.onPause()
    Helium.shared.removeHeliumEventListener(paywallEventHandlers)
}

Option 2: Implementing HeliumEventListener

For a more centralized approach, your class can implement the HeliumEventListener interface and handle all events in a single onHeliumEvent method.
// In your Activity or Fragment
import com.tryhelium.paywall.core.event.HeliumEventListener
import com.tryhelium.paywall.core.event.HeliumEvent
import com.tryhelium.paywall.core.event.PaywallOpen
import com.tryhelium.paywall.core.event.PaywallClose

class 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

Fallbacks and Loading Budgets

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.
// In your Activity's or Application's onCreate() method
Helium.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.
// In your Activity's or Application's onCreate() method
val fallbackView = YourFallbackView(this) // Your custom fallback view

Helium.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)
        )
    )
)