Adds Mob (mobile framework) to an existing Phoenix-based Elixir project.
⚠ Experimental (pre-1.0)
mix mob.adopt is experimental. On anything outside the supported
shapes the task refuses with a clear message rather than risk
breaking your app. The supported surface will widen as we stabilise.
Supported (default — LV bridge)
- Single (non-umbrella) Phoenix project.
- Stock
assets/js/app.js(containsnew LiveSocket(...)). - Stock root layout (
lib/<app>_web/components/layouts/root.html.heexor the legacytemplates/layout/root.html.heex) with a<body>tag. - Ecto Repo uses the SQLite adapter (
:ecto_sqlite3in deps). The generatedmob_app.exmigrates<App>.Repoon-device; the SQLite assumption is hard-coded. Amix phx.new --database sqlite3project matches.
Supported (--no-live-view — thin-client)
Same Phoenix-shape requirements but no Ecto/Repo constraint —
the phone opens a deployed Phoenix server via WebView and runs no DB
on-device. Works against Postgres / MySQL / --no-ecto hosts.
Refused (loud, with guidance)
- Umbrella applications.
- Non-Phoenix projects (no
:phoenixdep). - Heavily customised
app.js(no recognisablenew LiveSocket(). - Heavily customised root layout (no recognisable
<body>tag, or no layout file at all). - LV mode + host Repo uses Postgres / MySQL / MSSQL (or no Repo
at all). Use
--no-live-viewinstead, or wait for the future--with-local-repomode that handles non-SQLite hosts via a separate on-device LocalRepo.
Composable, Igniter-based — mirrors
the architecture of team-alembic/phx_install.
This is the install-into-existing counterpart to mix mob.new, which
generates a project from scratch. mix mob.new is unaffected by this task.
Usage
mix mob.adopt [OPTIONS]Run from inside an existing Mix project. The target project must
declare {:igniter, "~> 0.7", only: [:dev, :test]} in its mix.exs
(most modern Phoenix-ecosystem projects already do).
The native trees (--android / --ios, on by default) render from
mob_new's templates, so they also require the mob_new archive
installed:
mix archive.install hex mob_newmob_new stays the single source of native templates (no duplication
across repos). The Elixir-side adoption (deps, LiveView bridge,
mob.exs, MobScreen) needs no archive — only --android/--ios do.
Options
--no-ios— skip the iOS native tree--no-android— skip the Android native tree--local—path:deps for:mob/:mob_dev; pre-fillmob.exspaths fromMOB_DIR/MOB_DEV_DIR. For Mob framework contributors.--python— iOS-only: pre-configure embedded CPython via Pythonx--host-url URL— writeconfig :mob, host_url: URLso the generatedMobScreenopensURLinstead of the defaulthttp://127.0.0.1:4000/. Use for thin-client deployments where the WebView points at a deployed Phoenix server (fly.io etc.).--no-live-view— skip the LiveView bridge patches (assets/js/app.jsMobHook,root.html.heexbridge div) AND generate a thin-clientmob_app.exthat does NOT boot Phoenix on-device. For Hologram-only or non-Phoenix hosts where the BEAM-on-device is just the native interop layer.
Both platforms emit by default. Passing both --no-ios and
--no-android raises.
What gets installed
:mob+:mob_devdeps inmix.exslib/<app>/mob_screen.ex—Mob.Screenopening a WebView atApplication.get_env(:mob, :host_url)(default localhost)mob.exs— build-environment config.gitignoreupdated to ignoremob.exsandroid/and/orios/native trees (gated by platform flags)lib/<app>/mob_app.ex+src/<app>.erlfor on-device BEAM entryerlc_paths/erlc_optionsadded tomix.exs
Default (no --no-live-view):
MobHookinjected intoassets/js/app.js- bridge
<div>injected intoroot.html.heex mob_app.exboots the host Phoenix endpoint on-device
With --no-live-view:
- LiveView bridge patches skipped
mob_app.exis the thin-client variant (use Mob.Appshell, noApplication.ensure_all_started)
Composability
Every sub-installer is invokable independently:
mix mob.adopt.deps # just bump mix.exs
mix mob.adopt.bridge # just patch app.js + root.html.heex
mix mob.adopt.screen # just generate mob_screen.ex
mix mob.adopt.mob_app # just generate mob_app.ex + .erl bootstrap
mix mob.adopt.mob_exs # just write mob.exs + .gitignore
mix mob.adopt.native # both native trees
mix mob.adopt.native.android
mix mob.adopt.native.ios
mix mob.adopt.finalize # post-install notice (no file changes)Each accepts the same flags as mob.adopt and respects them
individually. Run mix help mob.adopt.<sub> for sub-task docs.
On-device runtime services (Mob.ComponentRegistry,
Mob.NativeLogger, etc.) start imperatively inside
<App>.MobApp.start/0 — Mob.App is the behaviour the device
entry uses (via use Mob.App), never a supervision-tree child.
The native trees come from mob_new's priv/templates/mob.new/; the
Elixir-source content (mob_screen.ex, mob_app.ex, the LV bridge
patches) from MobDev.Adopt.Patcher / MobDev.Adopt.Generator, both
duplicated from mob_new pending the Phase-5 Igniter reunification.