Releases: GenericJam/mob_dev
Releases · GenericJam/mob_dev
0.6.15
Security
- Bumped
req0.5.18 → 0.6.2 (pullsfinch0.22.0 → 0.23.0), clearing
EEF-CVE-2026-49755 (HIGH) and EEF-CVE-2026-49756 (LOW) flagged by
mix mob.security_scan.reqis a transitive dep (viaigniter); the bump
stays withinigniter's~> 0.5requirement.
Fixed
mix mob.new_pluginno longer scaffolds plugins pinned to the abandoned
mob ~> 0.6.MobDev.Plugin.Scaffoldhard-coded{:mob, "~> 0.6"}in the
generatedmix.exsandmob_version: "~> 0.6"in every tier's manifest, so a
freshly scaffolded plugin could not activate against the published mob 0.7.x
(installed :mob 0.7.x does not satisfy mob_version "~> 0.6"). The requirement
is now derived at scaffold time from the mob actually resolved in the project
(Scaffold.detect_mob_requirement/0), falling back to a single
@fallback_mob_requirementconstant ("~> 0.7") when mob isn't loadable.
mix.exsand the manifest always agree. AScaffoldtest pins the default and
asserts a generated manifest validates against a matching mob version, so the
pin can't silently lag a future mob release. (#21)
0.6.14
Added
:extra_static_libshook on:static_nifsentries — a Mob app can now
link external per-ABI static archives alongside its project NIF archives.
Some project NIFs intentionally declareexternsymbols and don't host-link
their backing archive (avoiding a host/device archive mismatch duringmix compile); this lets the native app link resolve those symbols against the
correct per-ABI.a. Entries require concrete per-ABI keys (:ios_sim,
:ios_device,:android_arm64,:android_arm32,:android_x86_64), and the
matching archive paths are appended to the existing-Dproject_rust_libs=
link argument.-D<module>_static=trueis emitted only on the ABIs where the
entry applies, and iOS project-NIF filtering is now per-ABI so a device-only
guarded entry doesn't leak into simulator args. Also passes Zigler 0.16's
required generated-build flags when re-driving staged Zig NIF builds and
resolves Zigler dotfile sources withmatch_dot: true. Verified on a physical
SM-T577U (arm64-v8a) tablet via a Ghostty VT NIF. (#24)
Changed
mix mob.deploy --nativenow preserves on-device app data when the signing
key matches. The Android install path previously ran an unconditional
adb uninstallbeforeadb install, which wipedMOB_DATA_DIR(on-device
identity, screen stores) on every native deploy — even an in-place update
signed with the same (e.g. committed) debug keystore. It now attempts
adb install -rfirst and only falls back to uninstall + install when the
in-place update is genuinely rejected (INSTALL_FAILED_UPDATE_INCOMPATIBLE
from a signature mismatch,INSTALL_FAILED_VERSION_DOWNGRADE, etc.). Apps that
pin a committed debug keystore now keep their identity across--native
redeploys. Decision logic extracted toNativeBuild.needs_clean_reinstall?/2
and unit-tested.
Fixed
mix mob.deploy --native --androidnow fails fast with the real cause when
zigis missing (landed in code before 0.6.13; previously undocumented).
The Android JNI build is driven bybuild.zig; withzigoff PATH it used to
print a yellow "skipping build.zig step" warning and fall through to a CMake
fallback that references C sources mob 0.7+ no longer ships, dying ~150 lines
later with a misleadingCannot find source file: .../mob_nif.c. It now aborts
before Gradle with an actionable message (install zig 0.15.x, verify with
mix mob.doctor) whenbuild.zigis present,zigis absent, and the legacy
C sources are gone. Decision extracted toNativeBuild.zig_build_plan/3. (#20)
0.6.13
Changed
mix mob.deploy --nativenow preserves on-device app data when the signing
key matches. The Android install path previously ran an unconditional
adb uninstallbeforeadb install, which wipedMOB_DATA_DIR(on-device
identity, screen stores) on every native deploy — even an in-place update
signed with the same (e.g. committed) debug keystore. It now attempts
adb install -rfirst and only falls back to uninstall + install when the
in-place update is genuinely rejected (INSTALL_FAILED_UPDATE_INCOMPATIBLE
from a signature mismatch,INSTALL_FAILED_VERSION_DOWNGRADE, etc.). Apps that
pin a committed debug keystore now keep their identity across--native
redeploys. Decision logic extracted toNativeBuild.needs_clean_reinstall?/2
and unit-tested.
Fixed
mix mob.deploy --native --androidnow fails fast with the real cause when
zigis missing (landed in code before 0.6.13; previously undocumented).
The Android JNI build is driven bybuild.zig; withzigoff PATH it used to
print a yellow "skipping build.zig step" warning and fall through to a CMake
fallback that references C sources mob 0.7+ no longer ships, dying ~150 lines
later with a misleadingCannot find source file: .../mob_nif.c. It now aborts
before Gradle with an actionable message (install zig 0.15.x, verify with
mix mob.doctor) whenbuild.zigis present,zigis absent, and the legacy
C sources are gone. Decision extracted toNativeBuild.zig_build_plan/3. (#20)
0.6.12
Fixed
- 16 KB page-size alignment enforced at build time for every app. Android
15+ devices use 16 KB memory pages and Google Play requires every bundled
.soto have 16 KB-aligned LOAD segments. The-Wl,-z,max-page-size=16384
link flag lives in the app'sbuild.zig, which is copied once atmix mob.new
and never regenerated — so apps generated before the template carried the flag
kept linking 4 KB-aligned.soand failed Play.mix mob.deploy --nativenow
reads the app'sbuild.zigand, if its-sharedlink lacks the flag, injects
it before linking (idempotent — a no-op when already present, e.g. the current
mob_new template or a hand-fixed app). Pure core ininject_page_size_flag/1.
0.6.11
Added
mix mob.adopt— installs Mob into an existing Phoenix project,
the Igniter-based install-into-existing counterpart tomix mob.new
(which generates from scratch). Composable: the orchestrator runs the
sub-installersmob.adopt.{deps,bridge,screen,mob_app,mob_exs,native,finalize},
each invokable independently. Default LV-bridge mode wireswindow.mob
through a LiveViewphx-hookand generates amob_app.exthat boots the
host Phoenix endpoint on-device (SQLite Repo assumed);--no-live-view
generates a thin-client shell whose WebView opens a deployed server.
Pre-1.0: refuses loudly (via Igniter issues) on umbrella / non-Phoenix /
heavily-customisedapp.jsor root layout / non-SQLite LV hosts rather
than risk breaking the app. The native Android/iOS trees (--android/
--ios) render from mob_new's templates and require the mob_new archive
installed (mix archive.install hex mob_new) — mob_new stays the single
source of native templates; the Elixir-side adoption needs no archive.
Contributed as mob_new#8
by @ken-kost and relocated here — adopt is
an Igniter task that mutates an existing project (likemob.add_nif/
mob.enable), so it belongs in mob_dev (a Hex dep), not in mob_new (a
self-contained Mix archive that can't carry Igniter). See
decisions/2026-06-19-mob-adopt-lives-in-mob_dev.md. The shared
patcher/generator helpers are duplicated from mob_new into
MobDev.Adopt.{Patcher,Generator}pending the Phase-5 Igniter
reunification.
0.6.10
Added
- Plugin
:cpp_archiveNIFs — ship a C++ static library (e.g. an Nx
backend) from a plugin. Manifest-driven cross-compile +--whole-archive
static link (rule #11), with<module>_nif_initsymbol verification and
duplicate-init cross-validation. (#18)
Fixed
- cpp_archive builds now fail fast with a named error on an unsupported
Android ABI (e.g. the x86_64 emulator) instead of silently skipping — which
previously deferred an unresolved<module>_nif_initto an on-device link
failure. - The plugin manifest now requires a lowercase
:moduleatom for
:cpp_archiveentries (fail-loud instead of fail-open /libnil.a).
0.6.9
Fixed
mix mob.publish --androidnow commits when Google requires
changesNotSentForReview=true. Uploading a release while the app is under
policy review (or otherwise can't auto-send for review) made the Play Edits
:commitfail with HTTP 400 ("Please set the query parameter
changesNotSentForReview to true"), discarding the whole edit so nothing
reached the track.commit_edit/3now detects that 400 and retries the commit
with?changesNotSentForReview=true; the changes land on the track and are
sent for review from the Play Console UI. Verified uploading Io v13 to the
internal track.
0.6.8
Added
mix mob.connect --only <serial>(alias--device/-d, repeatable).
Restricts the run to devices whose serial/udid contains the given substring.
Without it, connect attaches to every running device, so one slow or locked
device (typically a plugged-in physical iPhone whose app restart blocks) could
stall the whole session before any node connected. Verified end-to-end against
a single Android phone:mix mob.connect --only ZY22CRLMWKtunnels, restarts,
and connectslivebook_mob_android_zy22crlmwk@127.0.0.1on its serial-derived
port 9633, then RPC into the device BEAM works (read live state, eval code).
0.6.7
Fixed
mix mob.connectreliability — dist ports keyed by device serial, not run
index. The Mac runs one shared EPMD; assigning ports as9100 + indexmeant
every project's first device claimed 9100, so two phones (or two projects'
device-0) registered the same port andadb forward tcp:9100could only reach
one — the other silently timed out. Ports are now derived from the device
serial (Tunnel.serial_base_port/1, a crc32 hash into 9100..9899) and bumped
past any port another live node/forward already holds (assign_dist_port/2).
A given phone always gets the same unique port across runs and projects, and
deploy and connect agree on it.Tunnel.setup/2→setup/1(port is now
serial-derived, not index-passed).- Stale-tunnel cleanup.
Tunnel.setupremoves the device's own old forwards
first (scoped to that serial), so prior runs no longer leave duplicate/wrong
forwards that poison the next connect. - Real diagnostics on connect failure. A timed-out node now reports why —
app not running / Standby-killed, dist never registered in EPMD, registered at
a different port, no forward, or cookie mismatch — instead of a black-box
"timed out".
0.6.6
Fixed
- Android native build skips ABIs the app's
build.zigdoesn't handle
instead of hard-failing. mob_dev builds arm64-v8a/armeabi-v7a/x86_64 by
default, but an app's app-ownedbuild.zig(copied atmix mob.newtime)
may predate x86_64 support (mob_new < 0.4.5) and reject-Dabi=x86_64. That
used to fail the whole native build — aborting before the
io.mob.plugin.MobPluginBootstrapregen, so the next gradle build then failed
on an unresolved bootstrap. Now each ABI is pre-flighted against the build.zig
(build_zig_supports_abi?/2) and unsupported ones are skipped with a warning
(gradleabiFilterswouldn't ship them anyway). Real failures of a SUPPORTED
ABI still halt the build.