← All work
Product · 2026

Native Android Shell for a Community Hub & AI Chat

A startup-community hub + digital loyalty-wallet platform

Overview

The Android twin of the iOS client: a Kotlin + Jetpack Compose shell around the community hub and its AI chat (a customised LibreChat fork). Tabs are WebViews that share one session; the chat tab swaps the bottom bar for a native composer; sign-in, notifications, QR scanning, the intro flow and the phone-to-phone “Bump” gesture are native. Built in 33 commits across roughly four weeks, at feature parity with iOS and released through Play Console internal testing.

Why It Exists

The community needed the same native experience on Android as on iPhone without a second product codebase. A single-module Compose app over shared-cookie WebViews lets one Clerk sign-in cover every tab, keeps the content on the web, and adds the pieces a WebView cannot provide well: keyboard-correct composer, speech input, camera, push channels, App Links and motion sensing.

What We Built

One Gradle module (id.ambasada.hub, minSdk 26, compile/target SDK 36) organised by feature package: web (ModuleWebView persistent WebViews with shared cookies, no pinch-zoom, a native retry screen on load failure, and WebBridge implementing the contract where the page calls window.ambasada.postMessage(json) and native calls window.ambasadaNative.*), registry (tabs loaded from the hub’s /api/app/registry with a bundled copy in assets/registry.json), ui (TabShell with a Material top bar that shows the wordmark or the page’s own title, NotificationsScreen overlaid on the tabs so the Home page keeps serving data, Theme), composer (ComposerBar with dictation, attachments, tool toggles and the ”@” send/stop/leave control, kept above the keyboard; SpeechInput), auth (native sign-in through the Clerk Android SDK, a ticket exchange into the web session, legal consent, a persisted sign-in store), welcome (native intro pages matching iOS), push (one-time consent sheet, notification channels, PushManager, settings that mirror the phone), session (session and inbox stores driven by the pages rather than URLs), scan (CameraX + ML Kit barcode scanner), navigation (Router that sends chat URLs to the Chat tab and keeps cold-start deep links on their tab) and bump (BumpMotion sampling at 100 Hz with a registry-tuned spike threshold, BumpRoom over a socket, BumpProtocol, and a match that opens a card, a sheet or a full hub page). The manifest declares verified App Links for the hub and chat hosts, the ambasada:// scheme and a callback scheme for Clerk. Twelve JUnit suites cover sign-in flow and ticket exchange, bump protocol / room / spike detection / magnetic ring, registry, session and welcome logic, with OkHttp MockWebServer for network paths.

Release engineering is in the repo: release signing read from the environment (the keystore stays out of git), R8 minification and resource shrinking, a versionCode derived from the build hour (YYMMDDHH), and fastlane lanes to build the App Bundle, upload the EN/RO Play listing (copy, icon, feature graphic, screenshots generated by a Node script), push to internal testing and promote to production.

Technologies & Approach

Kotlin 2.4 with the Compose compiler plugin, Material 3 and the Compose BOM; AndroidX webkit for the WebViews; kotlinx.serialization for the registry and bridge payloads; coroutines throughout; CameraX with ML Kit for scanning; OkHttp for native network calls; Clerk’s Android SDK for OAuth sign-in; the AndroidX splash-screen API for a branded launch into a native loading state. Dependencies live in a Gradle version catalog. The bridge contract and registry format are identical to the iOS client, so the web app serves both shells without platform branches.

Outcome / Impact

A Play-ready Android app that reached parity with the iOS client in a third of the commits by reusing the same web content, bridge contract and registry, and adding native sign-in, push inbox, scanner, composer and Bump on top. Listing, release lanes and signing are reproducible from a shell, and the first internal release went through Play Console.

Capabilities Demonstrated

  • Hybrid Android architecture: shared-cookie WebViews in Jetpack Compose with a typed JavaScript bridge
  • Registry-driven tab shell fetched from the backend with a bundled fallback
  • Native composer with dictation, attachments and tool toggles over a web chat
  • Native OAuth sign-in via Clerk exchanged into a web session ticket
  • Phone-to-phone “Bump” contact sharing from accelerometer spikes plus a pairing room
  • Push notifications with channels, one-time consent and a native inbox
  • Verified App Links and custom schemes with tab-aware deep-link routing
  • CameraX + ML Kit barcode scanning for member cards
  • Google Play listing, screenshots and release lanes managed as code with fastlane; environment-based release signing
  • Cross-platform parity with a sibling iOS client from a shared contract, covered by JUnit tests
More work See all work