Skip to content

feat: offer updates as a browser download instead of installing them inside the app - #312

Merged
nofuturekid merged 1 commit into
mainfrom
feat/update-via-browser-download
Nov 13, 2026
Merged

nofuturekid merged 1 commit into
mainfrom
feat/update-via-browser-download

Conversation

@nofuturekid

@nofuturekid nofuturekid commented Nov 13, 2026 •

Copy link
Copy Markdown
Collaborator

What and why

The GitHub (direct) build no longer installs updates itself. It keeps the update check and the "Update available" sheet; Download now sends the browser to the release APK, and a separate Release page button opens the release page. REQUEST_INSTALL_PACKAGES and all installer code are gone, and the main manifest strips the permission from every flavor and library (tools:node="remove"), with a unit test that fails if it comes back.

Why, with the evidence (2026-11-13, real Android 9 phone with Google Play Protect):

  • Every current GitHub build (v0.1.45-beta1, v0.1.45, v0.1.46-beta1, a new file each time) was stopped on install or update: first "App scan recommended", then Google's cloud scan rated it "potentially unwanted" and showed "Harmful app blocked". The only way on is "More details > Install anyway". A maintainer's Pixel on Android 17 was stopped as well. The F-Droid build never showed a warning.
  • The official CI build of this pull request (same version 0.1.46-beta1, same signing key, but without the install permission and without the installer code) went through the same cloud scan 35 minutes later on the same phone and was rated "This app seems safe"; the system installer then also says the app needs no special access.
  • The new flow was tried on the phone: banner and Settings button, sheet with notes, size and SHA-256, Download opens the release APK in the browser, Release page opens the release page.
  • Not proven: that the permission is the only factor (one phone, one day, one Play Store version; Google's classifier can change). The "App scan recommended" step itself remains for every new file.

Decision: Accepted in ADR-0046 (2026-11-13), to go into the next beta.

Closes #306 (the permission round trip it describes no longer exists).
Closes #307 (the blocked-update message it improves is no longer shown, because the app no longer installs).

What changed

  • UpdateRepository: the browser is only sent to HTTPS links under https://github.com/hellwand/nova/releases/; another host, another repository or a non-https scheme returns an error (tests for each).
  • Sheet text says that the browser downloads the file, that it is opened to install, and that Android and Play Protect may ask something first; banner says "tap for details"; "Release page" uses the app's own button on its own row.
  • Removed: REQUEST_INSTALL_PACKAGES and app/src/direct/AndroidManifest.xml, the PackageInstaller session, InstallStatusReceiver, UpdateController, ApkInstaller, UpdateInstaller, UpdateModule, UpdateControllerTest.
  • Tests: UpdateRepositoryTest (links, pre-release filter, drafts, checksum), NoInstallPermissionTest (permission absent, remove marker present).
  • Docs: ADR-0046 Accepted with the device result; dated amendments in ADR-0008, ADR-0034 and ADR-0040 and their index rows; README and website section "Google Play Protect" (the two dialogs, what we observed, how to verify with SHA-256 and the signing certificate digest, what changes, F-Droid as the alternative); privacy policy, HANDOFF, CONTRIBUTING and two test comments no longer describe the installer; CHANGELOG entries under Unreleased.

Cost

No one-tap update. Users of versions up to 0.1.46 still have the old updater and may see the Play Protect dialogs one last time when updating to the first release with this change.

Not in this pull request

Version bump and release (version stays 0.1.46 / 129), .github/ (a stale mention of the in-app updater in ci.yml and SECURITY.md is tracked separately), the store flavor's behaviour, signing, and objects.githubusercontent.com in network_security_config.xml (harmless now that the app no longer reaches it; left alone).

Checks

  • ./scripts/local-ci.sh on the rebased state: LOCAL CI PASSED in 138s; 255 unit tests, 0 failures, 0 skipped.
  • aapt2 dump permissions on the built direct and store release APKs: INTERNET, ACCESS_NETWORK_STATE and the app-internal DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION; no install-packages permission.

🤖 Generated with Claude Code

…inside the app

The GitHub build keeps the update check (latest release, pre-release switch,
Update available banner and sheet) but no longer installs anything itself.
Download sends the browser to the release's APK (the release page when the
release has no APK), a separate link opens the release page, and the sheet
shows the file's SHA-256 when GitHub lists one. The browser is only sent to
HTTPS links under this repository's GitHub releases.

REQUEST_INSTALL_PACKAGES, the PackageInstaller session, the status receiver,
the install-permission flow, the in-app APK download and their tests are
removed, and the main manifest strips the permission from every flavor and
library; a unit test fails if it comes back. Why: on 2026-11-13 Google Play
Protect blocked every GitHub build that could install packages, and the CI
build of this change (same version and key, no permission) was rated "This
app seems safe" on the same phone, see ADR-0046 (Accepted). The store flavor
behaves as before.

README and website explain the Play Protect dialogs and how to verify a
download; ADR-0008, ADR-0034 and ADR-0040 point to ADR-0046.

Closes #306, closes #307

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@nofuturekid
nofuturekid force-pushed the feat/update-via-browser-download branch from 83fd363 to be8efe0 Compare November 13, 2026 13:38
@nofuturekid
nofuturekid marked this pull request as ready for review November 13, 2026 13:39
@nofuturekid
nofuturekid merged commit be8efe0 into main Nov 13, 2026
12 checks passed
@nofuturekid
nofuturekid deleted the feat/update-via-browser-download branch November 13, 2026 13:46

This branch was previously deployed

1 inactive deployment
github-pages — be8efe01 Deployed Nov 13, 2026 by nofuturekid via deploy #9
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.

Update failure by Play Protect shows only a raw error code In-app update does not continue after granting the install permission

1 participant