One Shot ships to the App Store and the Play Store from the same codebase you already have. You
don't build three separate front-ends; you build the web app, and two thin native shells,
`mobile/ios` and `mobile/android`, wrap your existing Hotwire web views and present them natively:
native navigation, native tab bars, and the ability to drop to a fully native screen wherever you
actually need one.

## How the shells work

Each shell loads your Rails app inside a native web view and follows a **path configuration** that
Rails itself serves, at `/configurations/ios.json` and `/configurations/android.json`
(`app/controllers/configurations_controller.rb`). Change a navigation rule there, and both apps
pick it up immediately, with no new build and no App Review. This is the mechanism that keeps a
Hotwire Native app from needing a native release for every navigation tweak.

## Auth works differently in-app than on the web

Magic **codes**, not links, work fine inside an embedded web view exactly as they do on the web,
since the whole flow is just entering a six-digit number. Social sign-in is different: Google
actively blocks OAuth from running inside an embedded web view, so each shell opens
Google and Apple sign-in externally instead, in `ASWebAuthenticationSession` on iOS and Chrome
Custom Tabs on Android, then hands the resulting session back to the app. The path configuration
marks every `/auth/` route `external` specifically so the shells know to intercept it rather than
load it in-webview. See [Auth in the App](/docs/mobile-apps/auth-in-the-app) for the full mechanics.

## The one thing you can't route around: in-app purchases

Apple and Google require digital subscriptions purchased inside an app to go through their own
purchase systems, StoreKit and Play Billing, taking a cut of roughly 15 to 30 percent. Your
existing Stripe checkout can't run inside the app to unlock a digital feature. One Shot handles
this honestly rather than pretending otherwise: Stripe stays the foundation for web and PWA
purchases, and the two native shells switch to StoreKit and Play Billing only when running inside
the app, with the receipt verified server-side and fed into the exact same `Subscription` record
Stripe would have created. See [In-App Purchases](/docs/mobile-apps/in-app-purchases) for how the
bridge works end to end.

## What you need before you start

An Apple Developer Program membership ($99/year, also required for Sign in with Apple), a Google
Play Console account ($25 one time), signing certificates or a keystore, and, eventually, passing
each store's review. None of this is required to develop the shells locally against a dev server;
it's required to ship.

## Building each shell

- [iOS Setup](/docs/mobile-apps/ios-setup)
- [Android Setup](/docs/mobile-apps/android-setup)

Both READMEs walk through pointing the shell at your Rails app's URL, opening the project in Xcode
or Android Studio, and running it.
