Overview

A full-featured Jetpack Compose Android starter with Supabase, RevenueCat, push notifications, and analytics wired in.

The Kotlin (Android) template is a full-featured Jetpack Compose starter for phones and tablets. It ships with a Supabase backend, RevenueCat subscriptions, account-bound Pro entitlements, Firebase Cloud Messaging, deep links, analytics, crash reporting, and the Android launch gates already wired together.

The Android plumbing above is real and integrated. Some product surfaces are intentionally Example or Removable demo features for you to replace before launch.

Minimum SDK: 26. Target SDK: 37. Application id: com.soarstarter.kotlin.

Graceful degradation

The template reads local Android configuration from local.properties into BuildConfig. Missing string keys become empty strings, and the owning controllers check those values before starting service-specific work. That lets you build and boot the app first, then wire Supabase, RevenueCat, FCM, PostHog, Sentry, and release signing one at a time. See Configuration.

Tech stack

LayerChoice
UIJetpack Compose + Material 3
ArchitectureMVVM (ViewModel + StateFlow) + Repository pattern
Dependency injectionHilt with KSP
NavigationNavigation Compose with type-safe @Serializable routes
Backendsupabase-kt (Auth, PostgREST, Storage, Edge Functions)
NetworkKtor OkHttp engine + Coroutines / Flow
PersistenceDataStore Preferences for app state; supabase-kt SettingsSessionManager for restored auth sessions
Image loadingCoil 3
PushFirebase Cloud Messaging
SubscriptionsRevenueCat purchases + Supabase entitlement read model
AnalyticsPostHog Android SDK
Crash reportingSentry Android SDK
Biometricandroidx.biometric / BiometricPrompt
Play servicesPlay In-App Updates + Play In-App Review
Deep linksApp Links + custom soar:// scheme
i18nvalues/strings.xml + values-zh/strings.xml with runtime locale switching

Feature status

Features are labelled consistently throughout these docs:

  • Integrated — fully wired; activates when its key or service is configured.
  • Example — a working demo feature meant to be replaced with your own.
  • Removable demo — the Showcase tab and gated guides; the code is fenced for deletion.
  • Play-only — needs Google Play services and/or a Play-delivered build.
FeatureStatusNotes
AuthenticationIntegratedEmail/password, sign-up with email OTP, forgot/reset password, change email/password, sign out other sessions
Google Sign-InIntegratedAndroid Credential Manager ID token -> Supabase; hidden when GOOGLE_WEB_CLIENT_ID is empty
ProfileExampleAvatar, personal info, account security, theme/language controls
TodosExampleFull CRUD reference feature; pushed from the Home stack, not a tab
Upload sampleExamplePhoto picker -> Supabase Storage bucket sample-uploads
SubscriptionsIntegratedRevenueCat purchase UI; entitlement source of truth is the Supabase subscriptions read model
Push notificationsIntegratedFCM token registration, in-app inbox, and signed-in test-push function
Deep linksIntegratedsoar:// plus HTTPS App Links via LINKING_DOMAIN
AnalyticsIntegratedPostHog identify/reset and typed events
Crash reportingIntegratedSentry setup, ErrorBoundary, user tagging, feedback events
App gatesIntegratedBiometric lock, update gate, onboarding, legal consent, auth routing
Permissions primingIntegratedNotifications, camera, and advertising-ID tracking education screens
Store reviewPlay-onlyGoogle Play in-app review smart trigger
In-App UpdatesPlay-onlyForce/soft update prompts; falls back to Play URL
i18nIntegratedEnglish + Simplified Chinese; runtime switch through LocaleController and LocalizedAppHost
ThemingIntegratedLight, dark, system, and dynamic color settings persisted in DataStore
Offline bannerIntegratedConnectivity-backed OfflineBanner component
Toast / hapticsIntegratedTop toast host with success/error haptic feedback
Refer a friendExampleAndroid share sheet via ACTION_SEND
Component galleryExampleLocal Compose component catalog and detail demos
Showcase + guidesRemovable demoFour-tab shell includes Showcase; developer guides are purchase-gated inside it

App surface map

The app is composed outside-in:

  • Activity hostMainActivity applies theme and locale, then wraps the app in BiometricGate -> ErrorBoundary -> AppNavGraph, with ToastHost mounted over the navigation content.
  • Gate stackAppNavGraph evaluates UpdateGate -> OnboardingGate -> ConsentGate, then mounts the main navigation graph. Auth routes are pushed when a signed-in-only action needs them, and popped when SessionController.currentUser becomes non-null.
  • Main shellMainShellRoute owns four tabs (Home, Component, Showcase, Me) plus a navigation drawer. The Todos screen lives under the Home graph (AppRoutes.Todos), so it is a canonical example feature rather than a fifth tab.

Cross-platform entitlement

The Android app treats public.subscriptions as the account entitlement source of truth. RevenueCat handles Google Play purchase and restore flows, then the revenuecat-webhook Edge Function writes provider = play_store rows into Supabase. EntitlementController reads that table through SubscriptionRepository; it does not treat RevenueCat CustomerInfo as the unlock source for account-gated surfaces. The RevenueCat entitlement id is the hardcoded constant pro.

Start here

On this page