Skip to content
The mobile SDKs are available on request. Email support@grona.ai to get access.

Test and debug

This page shows what the SDK is doing on a test device. The grona-debug artifact adds a screen that lists the active configuration, every campaign and why it is live or not, bound slots and recent events. A logger routes SDK warnings to Logcat. The debug view works only in debuggable builds. The logger receives messages in any build you pass it to, so the example below passes it only in debuggable builds.

  1. Add the debug artifact to debug builds only, as on Install the SDK:

    app/build.gradle.kts
    dependencies {
    debugImplementation("ai.grona:grona-debug:0.1.0")
    }
  2. Call Grona.openDebugView from a hidden menu or a developer setting in your debug build:

    import ai.grona.sdk.Grona
    // In an activity, for example from a hidden developer menu
    Grona.openDebugView(this)
  3. Tap Refresh on the debug screen after you change something in the app.

openDebugView does nothing when the app is not debuggable or the artifact is missing. In an app that is not debuggable it logs a warning. The debug screen is not exported, has no intent filters and blocks screenshots.

Section Contents
SDK SDK version, workspace, configuration source (bundled, cache or remote), configuration version, key id, expiry, last configuration error, consent state, the last 4 characters of the install id, whether a shopper is identified, and whether demo mode is in effect
Campaigns Each campaign’s name, id and placement, whether it would render now for this shopper, and if not, why (for example activation off, holdout, no grant or audience: profile unknown). Also the assigned arm and variant
Pins Local pins, with a field to pin a variant on this device and a button to clear pins
Slots Every bound slot and decision with its placement, screen and key, and the campaign it shows
Recent events Up to 200 recent events, newest first, with identifiers shortened

Local pins work only in debuggable apps and never create a grant. The recent-events list is kept only in debuggable apps, so release builds keep no copy of order ids, totals or product ids for it.

GronaLogger receives SDK diagnostics. It is silent by default. Send them to Logcat in debuggable builds:

AcmeMarketApp.kt
package com.example.acmemarket
import ai.grona.sdk.Grona
import ai.grona.sdk.GronaLogger
import ai.grona.sdk.GronaOptions
import android.app.Application
import android.content.pm.ApplicationInfo
import android.util.Log
class AcmeMarketApp : Application() {
override fun onCreate() {
super.onCreate()
val debuggable = (applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) != 0
val logger = if (debuggable) {
GronaLogger { priority, message -> Log.println(priority, "Grona", message) }
} else {
GronaLogger.NONE
}
val options = GronaOptions.Builder("acme-market")
.logger(logger)
// ... the other options from Initialize the SDK
.build()
Grona.init(this, options, AcmeGronaHost(this))
}
}

priority uses the android.util.Log levels: 3 debug, 4 info, 5 warning, 6 error. Messages start with Grona:. The SDK never passes customer ids, basket contents, tokens or keys to the logger. Your logger is called from Grona’s background threads and from the main thread, so keep it thread-safe and away from views.

Warning What to fix
the <placement> anchor is GONE or ... is INVISIBLE A slot or decision anchor is hidden. Keep it VISIBLE at zero height when empty, or the control arm is never measured. Logged once per anchor, in debuggable builds only.
identify ignored: customer id must match ... The customer id has characters outside [A-Za-z0-9._:-] or is longer than 128.
identify: an all-digit id of 9 or more characters ... The id looks like a phone number or national id. Pass an opaque internal id.
profile ignored: it is not bound to the identified customer setProfile came before identify, or for another customer.
decision() must be called on the main thread; posting it Call Grona.decision from the main thread.
preview link rejected: ... The preview link is malformed. See Preview links.
not the main process; Grona stays inactive Grona.init ran in a secondary process.
  • Empty slots. In the layout inspector, an empty slot is VISIBLE with zero height. No hidden-anchor warning appears.
  • Campaign state. Each campaign you expect is live in the debug view, or shows a reason you understand.
  • Basket. Progress bars and substitutes follow the cart as you change it. If not, a cart path is missing setBasket.
  • Consent. Under UNKNOWN no events are sent. After GRANTED, events reach your events endpoint.
  • Release build. openDebugView does nothing, and your R8 build runs without extra rules.

To pick up a configuration change during a test without waiting, call Grona.refresh with a listener. See Refresh on demand. To see one variant, use a preview link or a local pin.