Quickstart: Android
This quickstart adds the Grona Android SDK to your app, starts it when the app launches, and shows Grona content in the home_top placement on your home screen. At the end you check the result in the SDK’s debug view. It takes one Application class, one host interface, one view in a layout and one line of code on the screen.
The Android SDK is at version 0.1.0. It supports Android 7.0 (API level 24) and later.
Before you start
Section titled “Before you start”Grona sets up your workspace for apps and gives you these values. The examples on this page use Acme Market’s.
| Value | Example |
|---|---|
| Workspace key | acme-market |
| Config URL | https://api.grona.ai/v1/mobile/workspaces/acme-market/config |
| Events URL | https://api.grona.ai/v1/mobile/events |
| Preview pairing URL | https://api.grona.ai/v1/mobile/preview/pair |
| Configuration key id and public key | acme-market-2026-10 and a base64 public key |
| Signed bundled configuration | A config.json file |
Add the SDK
Section titled “Add the SDK”-
Add the dependencies to your app module.
grona-debugadds the debug view to debug builds only.app/build.gradle.kts dependencies {implementation("ai.grona:grona-core:0.1.0")debugImplementation("ai.grona:grona-debug:0.1.0")}For the repository setup and the build requirements (
compileSdk, Java and Kotlin versions), see Install the SDK. -
Add the bundled configuration. Save the signed file from Grona as
app/src/main/assets/grona/config.json. The SDK applies it at launch and when the device is offline, before the first download from the config URL.
Initialise the SDK
Section titled “Initialise the SDK”-
Implement
GronaHost. The SDK calls it on the main thread to look up products, add them to the basket, replace a basket line and open screens. This minimal version knows no products and accepts no actions, which is enough for a first banner or message without a call to action:app/src/main/java/com/example/acmemarket/AcmeGronaHost.kt package com.example.acmemarketimport ai.grona.sdk.GronaAddResultimport ai.grona.sdk.GronaHostimport ai.grona.sdk.GronaLineimport ai.grona.sdk.GronaProductimport ai.grona.sdk.GronaRouteimport ai.grona.sdk.GronaSource// A minimal host. The full version in Handle actions takes your Application.class AcmeGronaHost : GronaHost {override fun product(productId: String): GronaProduct? = nulloverride fun add(lines: List<GronaLine>, source: GronaSource): GronaAddResult = GronaAddResult.REJECTEDoverride fun replace(productId: String, with: GronaLine, source: GronaSource): GronaAddResult = GronaAddResult.REJECTEDoverride fun navigate(route: GronaRoute, source: GronaSource): Boolean = false}Content that names products or adds them to the basket shows nothing until
productreturns your products from a fast in-memory lookup andaddadds them. See Handle actions. -
Call
Grona.initinApplication.onCreate. Build the options with the values from Grona:app/src/main/java/com/example/acmemarket/AcmeMarketApp.kt package com.example.acmemarketimport ai.grona.sdk.Gronaimport ai.grona.sdk.GronaOptionsimport android.app.Applicationclass AcmeMarketApp : Application() {override fun onCreate() {super.onCreate()val options = GronaOptions.Builder("acme-market").bundledConfigAsset("grona/config.json").configUrl("https://api.grona.ai/v1/mobile/workspaces/acme-market/config").eventsUrl("https://api.grona.ai/v1/mobile/events").previewUrl("https://api.grona.ai/v1/mobile/preview/pair").configKey("acme-market-2026-10", CONFIG_PUBLIC_KEY).build()Grona.init(this, options, AcmeGronaHost())}private companion object {// Base64 DER SubjectPublicKeyInfo from Grona; a public key, not a secretconst val CONFIG_PUBLIC_KEY = "REPLACE_WITH_CONFIG_PUBLIC_KEY_FROM_GRONA"}}build()throwsIllegalArgumentExceptionif there is noconfigKey, if a URL does not start withhttps://, or if the workspace key is not valid. After that, the SDK never throws into your app.Grona.initreturns at once and does its work off the main thread. It is ignored outside your app’s main process and on repeat calls. -
Register the
Applicationclass in your manifest:app/src/main/AndroidManifest.xml <applicationandroid:name=".AcmeMarketApp"... > -
Pass the shopper’s consent answer. Consent starts as
UNKNOWN: events stay in memory and no events are sent. CallsetConsentafterinitwith the answer from your own consent flow, and again whenever it changes:import ai.grona.sdk.Gronaimport ai.grona.sdk.GronaConsentfun onAnalyticsConsentChanged(allowed: Boolean?) {Grona.setConsent(when (allowed) {true -> GronaConsent.GRANTEDfalse -> GronaConsent.DENIEDnull -> GronaConsent.UNKNOWN},)}Consent controls events, not rendering: Grona content still shows under
DENIED, and nothing is collected. See Consent.
Show the home_top placement
Section titled “Show the home_top placement”-
Add a
GronaSlotViewwhere the content should appear, withapp:gronaPlacementset tohome_top:app/src/main/res/layout/activity_home.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ai.grona.sdk.GronaSlotViewandroid:id="@+id/gronaHomeTop"android:layout_width="match_parent"android:layout_height="wrap_content"app:gronaPlacement="home_top" /><!-- The rest of your home screen --></LinearLayout> -
Set the slot’s screen when the screen is created. Setting
screenstarts the slot; until then it shows nothing.app/src/main/java/com/example/acmemarket/HomeActivity.kt package com.example.acmemarketimport ai.grona.sdk.GronaScreenimport ai.grona.sdk.GronaSlotViewimport android.os.Bundleimport androidx.appcompat.app.AppCompatActivityclass HomeActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_home)findViewById<GronaSlotView>(R.id.gronaHomeTop).screen = GronaScreen.HOME}} -
Run the app. If the configuration has a campaign for
home_topand you are in its treatment arm, the component appears at the top of the home screen.
Check it in the debug view
Section titled “Check it in the debug view”Open the debug view from a debug-only menu or button in your app:
Grona.openDebugView(this)It shows the configuration the SDK applied, the slots on screen, each campaign with your arm, and recent events. It opens only when grona-debug is in the build and the app is debuggable; otherwise the call does nothing.
If the slot is empty, check your arm for the campaign. Control and holdout show nothing by design. To see the treatment on your device, pin the variant locally from the debug view or open a preview link.
Next steps
Section titled “Next steps”- Identify shoppers and pass their basket and context.
- Render Grona components in more placements.
- Host-rendered decisions to draw content with your own views.
- Google Play Data safety before you release.