Android Setup
Building the Android shell in Android Studio.
The Android shell is a thin native wrapper around your existing Hotwire web views, built on Hotwire Native for Android. Setup means creating an Android Studio project, adding a few Gradle dependencies, and dropping in the provided Kotlin sources.
Creating the project
Open Android Studio and choose New Project, Empty Views Activity, named OneShot (package, for
example, com.oneshot). Set minSdk = 28, the floor Hotwire Native Android requires, and add the
dependencies in Kotlin DSL (build.gradle.kts):
dependencies {
implementation("dev.hotwire:core:1.+")
implementation("dev.hotwire:navigation-fragments:1.+")
implementation("androidx.browser:browser:1.8.0") // Custom Tabs for OAuth
implementation("com.android.billingclient:billing-ktx:7.+") // Play Billing (for IAP)
}
Adding the shell's source files
Add the Kotlin sources from mobile/android/src/ to your package, replacing the generated
MainActivity, and copy activity_main.xml into app/src/main/res/layout/. Add these permissions
to the manifest:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.android.vending.BILLING" />
MainActivity already sets the content view, registers the route-decision handler, and calls
BillingManager.syncEntitlements(this) on launch; there's nothing else to wire up manually.
Pointing it at your app
Set your app's URL in Config.kt. The Android emulator reaches a Rails server running on your host
machine at http://10.0.2.2:3000, not localhost.
The app icon
Replace the default ic_launcher using Android Studio's Image Asset Studio (right-click res, New,
Image Asset), which generates both the adaptive icon layers and the density mipmaps from a source
image. Also export a 512x512 icon for the Play Store listing itself.
Verify the adaptive foreground layer isn't blank. Image Asset Studio can generate an empty
foreground image even when the legacy square icon looks correct, and on API 26+ launchers, which
use the adaptive icon, that renders as a featureless colored square with no visible logo at all.
Composite mipmap-*/ic_launcher_foreground.webp over the background color to sanity-check it
before you ship.
What's in the shell
Config.kt: the base URL and the path-configuration URL.activity_main.xml: the content layout, a full-screenNavigatorHostfragment.MainActivity.kt: theHotwireActivityhost; registers the route-decision handler, andhandleExternalRoutedispatches/auth/and/iap/*to native handling.ExternalRouteDecisionHandler.kt: intercepts/auth/(OAuth) and/iap/*(Play Billing) so neither loads inside the web view.OAuthLauncher.kt: opens Google and Apple sign-in in a Chrome Custom Tab. See Auth in the App.BillingManager.kt: the full Play Billing flow, connecting, querying subscriptions, launching the purchase, acknowledging it, and posting the token to/iap/purchase, plussyncEntitlements(), which re-asserts active purchases on every launch. See In-App Purchases.
In-app purchase support is wired but optional: web Stripe billing works without any of the Play Billing code running. Sign in with Apple is hidden on Android entirely, since Apple only requires it on iOS.
Local development gotchas
http://10.0.2.2:3000 is cleartext HTTP, which Android blocks by default. For debug builds, allow
it with a network security configuration that permits cleartext traffic to 10.0.2.2, or set
android:usesCleartextTraffic="true" on a debug manifest. This isn't needed once you're pointed at
an https:// host.
Next
See the equivalent setup for iOS: iOS Setup. Or move on to Submitting to the Stores for release signing.