# `MobDev.ReleaseAndroid`
[🔗](https://github.com/genericjam/mob_dev/blob/master/lib/mob_dev/release_android.ex#L1)

Builds the signed release AAB for a Mob Android app.

Called by `mix mob.release --android`. The pipeline:

  1. Regenerate the `mob.exs` `url_schemes` intent filter in
     `AndroidManifest.xml` (`MobDev.UrlSchemes`), so the release doesn't
     depend on a dev build having stamped the current setting.
  2. Regenerate the plugin-derived files (runtime manifest, driver tables,
     migrations, images) and run the same native build as
     `mix mob.deploy --native` (`MobDev.NativeBuild.build_android_native/2`)
     for every Gradle `abiFilters` ABI: `jniLibs/<abi>/lib<app>.so` is
     rebuilt with the current plugins linked in, never reused from the last
     deploy (MOB-404). No device needed.
  3. Copy the arm64 OTP tree to a temp staging dir and add:
     - App + dep BEAMs (flattened into `{app_name}/`)
     - App `priv/` → `{app_name}/priv/`
     - exqlite BEAMs → `lib/exqlite-{vsn}/ebin/` (OTP lib structure needed
       for `:code.lib_dir(:exqlite)` to resolve correctly at runtime)
  4. Run `MobDev.OtpAssetBundle.build/2` — strips unused OTP libs (never
     one the app's runtime dependency closure needs, see
     `MobDev.OtpRequiredApps`) and optional BEAM chunks, then zips the tree
     to `src/release/assets/otp.zip`.
  5. Run `./gradlew bundleRelease` — signs the AAB using the keystore
     configured in `android/keystore.properties`.

`MobBridge.extractOtpIfNeeded()` (Kotlin) extracts `otp.zip` into
`<filesDir>/otp/` on first launch. Without this zip the app crashes
immediately — the BEAM has no runtime or application BEAMs to load.

The zip is written to the `release`-variant asset source set, not the
shared `main` one — Gradle only merges `src/release/assets/` into release
builds, so a leftover zip from a prior release build can never leak into
(and silently poison) a subsequent debug build. See
`decisions/2026-07-24-release-otp-zip-variant-scoped-assets.md`.

# `build_aab`

```elixir
@spec build_aab(keyword()) :: {:ok, Path.t()} | {:error, String.t()}
```

Runs the full Android release pipeline and returns `{:ok, aab_path}` or
`{:error, reason}`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
