Self-hosted APK distribution

Memby is handed out from a NAS or web server rather than a store, so:

- UpdateChecker gains a static-manifest source alongside Gitea. A .json
  update URL is read as a manifest ({version, apkUrl, notes}); anything
  else is still treated as a Gitea host. apkUrl may be relative and is
  resolved against the manifest's own URL.
- Release signing config reads memby.keystore from local.properties or
  the environment. Without it the build still succeeds but warns loudly:
  an unsigned APK will not install, and a changed key forces every user
  to uninstall before they can update.
- release.ps1 bumps the version, runs tests, builds a signed APK and
  assembles dist/out/ (landing page, latest.json, versioned APK) ready to
  copy onto the NAS.
- Keystores and dist/out are gitignored.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
ponzischeme89
2026-07-27 08:22:55 +12:00
co-authored by Claude Opus 5
parent 2ce405c540
commit 08360b75e4
10 changed files with 534 additions and 8 deletions
+60
View File
@@ -119,6 +119,66 @@ server is a property change plus a reinstall, with no user action. Leaving the p
3. **Preview screensaver** to test it, or **Set as system screensaver** to open the TV's
screensaver settings and choose "Memby Screensaver".
## Distributing builds
Memby is handed out as an APK from your own web server or NAS, and updates itself from
the same folder.
### One-time: a signing key
Android identifies an app by `applicationId` **plus signing key**. Every update must be
signed with the *same* key, or the TV rejects it as a different app. Lose the key and
every user has to uninstall and reinstall.
```powershell
keytool -genkeypair -v -keystore memby-release.jks -alias memby `
-keyalg RSA -keysize 4096 -validity 10000
```
Keep the `.jks` somewhere backed up and **outside the repo** (`*.jks` is gitignored), then
point `local.properties` at it — also gitignored:
```properties
memby.keystore=C:/keys/memby-release.jks
memby.keystorePassword=
memby.keyAlias=memby
memby.keyPassword=
```
Without these, `assembleRelease` still builds but the APK is unsigned and will not
install. The build prints a warning saying so.
### Each release
```powershell
.\release.ps1 -Version 0.1.54 -Notes "Faster home screen" -BaseUrl https://nas.example.com/memby
```
That bumps `versionName`/`versionCode`, runs the tests, builds a signed APK, and fills
`dist/out/` with:
```
index.html the page people are sent to
latest.json the update manifest the app polls
memby-0.1.54.apk the build
```
Copy those to the folder the NAS serves. Old APKs can stay alongside — only `latest.json`
decides what the app offers, so rolling back is editing one file.
### How TVs update themselves
In Memby's Settings, set the update URL to `https://nas.example.com/memby/latest.json`.
**Check for updates** then downloads and installs on the TV, no computer involved. A URL
ending in `.json` is read as a static manifest; anything else is treated as a Gitea host
(`/api/v1/repos/{owner}/{repo}/releases/latest`), so either source works.
The manifest's `apkUrl` may be relative (`memby-0.1.54.apk`) and is resolved against the
manifest's own URL, so the folder keeps working if the NAS is reached by another name.
First install on each TV still has to be manual — the **Downloader** app pointed at the
landing page is the usual route, and the page explains it.
## Upgrading to v0.1.53
The package and install identity both became `com.ponzischeme89.memby` in this release