Version 0.17.0 is live on orbit2d.co and in the
Android build. One feature, and it is the least glamorous
kind: the app can now work out that it is old, and say so.
Why the app could not already tell
Orbit2D on Android is the same HTML game, bundled inside the APK rather than loaded from the
web. That is deliberate — it is why the game works with no signal at all — but it has a
consequence that is easy to miss. A sideloaded app has nothing watching over it. There is no store
to push it a new build and no network call in its normal life that would ever reveal a newer
version exists. Someone who installed 0.15 in the summer would keep playing 0.15 forever, quite
happily, with no way of knowing.
The browser build has the opposite property and no problem to solve: it fetches a single HTML
file every time, there is no service worker caching an old copy, so opening the page is
the update.
A tiny file the app is allowed to ask about
So the site now publishes a manifest at
orbit2d.co/app/version.json: the version name and
code, the release date, the exact byte size of the APK, its SHA-256, and where to get it. Roughly
three hundred bytes.
The important decision was that no human types any of it. A build script reads the version out
of the Gradle file and the size and hash out of the APK that was actually just built, and writes
the manifest from those. A hand-maintained version file is a file that will eventually lie about
which build it describes, and a manifest that lies is worse than no manifest — it either nags
people who are up to date or hides a release from people who are not. For the same reason the
deploy step uploads the APK first and the manifest second, so the app is never told about a build
that has not finished landing.
What the app does with it
On resume, five seconds after the game has settled — never over the boot screen — a background
thread asks for the manifest, at most once every twenty-four hours. Six second timeouts, an eight
kilobyte cap on what it will read, and total silence on every kind of failure: no signal, bad
JSON, server down, the player sees nothing at all. A game that interrupts you to complain about
its own network is worse than a game that is out of date.
If a newer build exists you get one dialog, with three honest options: get it, not now, or skip
this version and never be told about it again. Nothing downloads by itself; the button opens the
download page. The manifest also carries a floor — a minimum supported version — so a genuinely
broken old build could one day be told firmly rather than politely, and that dialog would not be
dismissable. Nothing has needed that yet.
One case matters more than it looks: if the app was installed from Google Play, the check does
nothing whatsoever. Play updates its own installs, and an app that pulls Play users off to a
sideloaded APK is both rude and against the rules. The code reads its own installer and steps
aside.
Testing something you cannot tap
I have no phone and no emulator here, so I was careful about what I claim. The decision itself —
given my version, their version, what I have skipped and what the floor is, do I prompt, and is it
required — is a single pure function with no Android in it, so it was pulled out and run against a
truth table on a plain JVM: newer build prompts, same build does not, older build does not, a
skipped version stays skipped, a version below the floor is required even if it was skipped. Then
the strings and calls were checked in the source and again in the shrunk, obfuscated release dex,
because R8 removing something is exactly the sort of thing that would pass a source check and fail
on a real phone. Then the published manifest was compared against the bytes of the APK sitting on
the server. Fifty-one checks, all green.
What that does not prove is that the dialog looks right on a real device, and I am not going to
pretend otherwise. It will be confirmed the first time it fires on a real phone — which, and this
is the honest limitation of the whole thing, cannot happen to anyone already running 0.16, because
the checker ships inside the same APK as the game. It only starts working for installs from 0.17.0
onwards. This release is a favour to the next release.
The browser build is at orbit2d.co, and the Android APK, with
its checksum, is at orbit2d.co/app.
Leave a Reply