Quickstart for Android
This page is for an Android developer. It shows how an app draws a screen that a manager published in HotLayout, using the native reader for Android: a Kotlin library (an AAR) that turns a JSON document, a theme and your data into a Jetpack Compose screen.
Access. The Android reader is not published in a public registry (it is not on Maven Central) and its source is not public. It is available to customers on request: access is given with a licence or a trial. Write to contact@hotlayout.com and you will get the library together with instructions for adding it to your project. The React and Flutter packages are open source; see Quickstart for React and Quickstart for Flutter.
Related pages: index · delivery · data dictionary · theme · localization · compatibility · widgets · quickstart for iOS
What you are integrating#
| Piece | What it is |
|---|---|
| Document | One JSON file: a set of screens built from widgets. Published by the builder as published.json. |
| Theme | One JSON file: the token names the project has and the values behind them. |
| Data | A map your app supplies: values for the paths the document is bound to (user.name, user.points). |
| Reader | The HotLayout Android library: it draws the three as a Compose screen. |
The reader renders document contract 9.27.0 and passes the shared tables of cases that the React and Flutter readers pass; its screens are covered by instrumented tests. As with every reader, the major version of the contract must match: it draws any 9.x document and no 8.x one (see Compatibility policy).
Requirements#
- Android 8.0 (API 26) or later
- Jetpack Compose; no other third-party dependencies
Draw a screen#
Load the document with the tolerant reader, read the theme, and call HotlayoutScreen from a composable:
val document = loadDocument(jsonText) // tolerant read + version gate
val theme = HotlayoutThemeSet.read(themeText) ?: HotlayoutThemeSet.builtIn
HotlayoutScreen(
document = document,
theme = theme,
data = dataScopeOf("user.name" to "Maya", "user.points" to 1850),
locale = Locale.getDefault().toLanguageTag(), // the device locale, as is
entry = "promo", // a named entry point, optional
fonts = HotlayoutFonts { name -> if (name == "Inter") inter else null },
onAction = { action, source ->
// The reader opens nothing itself. A standard action arrives checked:
runStandardAction(context, action)
},
onTrack = { event, source -> analytics.log(event.event, event.params) },
onScreenChange = { shown -> Log.i("screen", "${shown.screenId} ${shown.cause}") },
)checkDocumentVersion (verdicts Ok, NewerMinor, NewerMajor, OlderMajor, Unparsable), loadDocument and resolveLocale can also be used without the view.
Where jsonText and themeText come from is your choice: your backend after a signed webhook, or the published address of the project. See Delivery options.
What the reader does and does not do#
- The document is untrusted input. A piece of the wrong shape is skipped and reported through
onReport; it is never a crash. A tree deeper than 32 levels is refused. - The reader opens nothing by itself. Navigation inside a document (
navigate,navigate.back,navigate.section) is done by the reader.openUrl,deeplink,closeand the actions of your app go toonAction, and a standard action arrives already checked. - Images load only over
https:by default. Pass anImagePolicyto decide yourself. - Data stays with you. The reader takes the values you pass in
data; it never calls your backend.
Fonts#
Fonts are yours: the theme names a family and HotlayoutFonts gives the FontFamily. If the family has no Arabic (or other) letters, the platform draws them with a system fallback font chosen by the weight of the typeface. Static font files, one per weight, keep the weight. A variable font must be wrapped so that each weight is its own typeface, built with Typeface.Builder(...).setFontVariationSettings("'wght' N").setWeight(N); Font(resId, weight, variationSettings = …) alone draws bold Arabic as regular.
Window insets#
The reader adds the status bar, the cutout, the navigation bar and the keyboard itself, minus whatever an ancestor already consumed (safeDrawingPadding(), a Scaffold, consumeWindowInsets). The recommended host draws edge to edge (enableEdgeToEdge()) and lets the reader add the insets; a host that pads works as well and gets nothing added twice. safeAreaTop and safeAreaBottom still override the values of the window.
Status#
The reader draws every widget of contract 9.27.0 natively and passes the shared tables of cases: layout and alignment, composed text, lists and grids from data, tabs and accordions, stacks, progress scales, buttons and gestures (long press, swipe to confirm), input fields and forms, the fixed app bar and bottom zone, modal sheets and windows with the system back key, carousels, motion, pictures and width classes for tablets. Behaviour is also checked on a device: gestures, the keyboard, TalkBack, rotation and hostile documents.
Platform limits: blur (glass and the layer under a modal sheet) needs Android 12 (API 31) or newer; on older versions the page under a sheet is only dimmed and glass is drawn without blur.
Next#
- Widget reference — what each widget takes.
- Compatibility policy — what a reader does with a document newer than itself.
- Backend guide — the data your backend returns for the paths in the document.