Skip to content

feat(deploy): preserve app data on --native when signing key matches#23

Merged
GenericJam merged 2 commits into
masterfrom
feat/native-deploy-preserve-data
Jun 20, 2026
Merged

feat(deploy): preserve app data on --native when signing key matches#23
GenericJam merged 2 commits into
masterfrom
feat/native-deploy-preserve-data

Conversation

@GenericJam

Copy link
Copy Markdown
Owner

Problem

mix mob.deploy --native wiped on-device app data — MOB_DATA_DIR (the app's
identity, built-screen stores, anything in files/) — on every native
deploy. adb_install_all/3 ran an unconditional adb uninstall <pkg> before
adb install <apk>, so even an in-place update of an APK signed with the same
key (e.g. a committed debug keystore pinned precisely to avoid this) lost its data.

This makes a stable on-device identity impossible across --native redeploys: a
committed keystore stabilizes beam-only mix mob.deploy, but the native path
threw the data away regardless.

Root cause (verified empirically)

On one device, same keystore-signed APK:

Operation App data
mix mob.deploy --native wiped (firstInstallTime reset)
manual adb install -r <apk> preserved (firstInstallTime unchanged)

So install -r works fine — the explicit uninstall was the cause, not any
signature mismatch.

Fix

adb_install_all/3 now attempts adb install -r first (an in-place update that
preserves data when the signing key matches) and only falls back to
uninstall + install when the in-place update is genuinely rejected — a
non-zero exit or an INSTALL_FAILED_* line (INSTALL_FAILED_UPDATE_INCOMPATIBLE
for a real signature change, INSTALL_FAILED_VERSION_DOWNGRADE, etc.). When it
does fall back, it logs that app data will be cleared.

This strictly improves on the old behavior (which always uninstalled): the
fallback path is identical, it's just no longer the default.

The decision is a pure helper, NativeBuild.needs_clean_reinstall?/2, unit-tested
for the success / signature-mismatch / downgrade / non-zero-exit cases.

Tests

test/mob_dev/native_build_test.exs — 4 new cases; full file 156 passed.
Pre-push (format + credo + suite) green.

Docs

CHANGELOG.md [Unreleased] → Changed, so users can track the behavior change.

🤖 Generated with Claude Code

GenericJam and others added 2 commits June 20, 2026 11:42
adb_install_all ran an unconditional 'adb uninstall' before 'adb install',
wiping MOB_DATA_DIR (on-device identity, screen stores) on every native deploy
— even an in-place update signed with the same committed debug keystore.

Try 'adb install -r' first (preserves data when signatures match) and only
fall back to uninstall+install when the in-place update is genuinely rejected
(INSTALL_FAILED_UPDATE_INCOMPATIBLE, INSTALL_FAILED_VERSION_DOWNGRADE, ...).
Decision extracted to NativeBuild.needs_clean_reinstall?/2 and unit-tested.

Verified empirically: on the same device, 'mix mob.deploy --native' wiped the
seeded identity while a manual 'adb install -r' of the same keystore-signed APK
preserved it (firstInstallTime unchanged) — confirming the uninstall, not a
signature mismatch, was the cause.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The fallback printed "In-place update rejected — reinstalling clean
(app data will be cleared)" for any `install -r` failure, including a
transient adb error (e.g. device offline) where nothing is rejected and
the follow-up uninstall+install just re-fails without clearing data.

Split the notice: only a genuine package-state rejection (an
INSTALL_FAILED line, i.e. signature/version mismatch) claims app data
will be cleared; a non-zero exit without INSTALL_FAILED reports the adb
exit code and "retrying with a clean install". Also drops the em-dash
from user-facing output. Behaviour is unchanged; wording only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@GenericJam GenericJam merged commit 74bd1cd into master Jun 20, 2026
3 checks passed
@GenericJam GenericJam deleted the feat/native-deploy-preserve-data branch June 20, 2026 18:25
GenericJam added a commit that referenced this pull request Jun 20, 2026
…missing zig (#23, #20)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant