From dbae6d594b8c9ef477bac65fe5676003e4e38071 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 28 Jul 2026 06:54:05 +0000 Subject: [PATCH 1/2] Fix release asset ordering so the in-app updater fetches the APK GitHub's API returns release assets sorted by name, not upload order. The app's checkUpdate() always downloads assets[0], so once build_and_sign.sh started attaching SHA256SUMS.txt and BUILD-INFO.txt alongside the APK, those alphabetically-earlier names could be picked up instead of the APK (#681). Rename the metadata files using the APK filename as a literal prefix so it always sorts first. --- docs/RELEASING.md | 10 ++++++++-- scripts/build_and_sign.sh | 9 +++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/RELEASING.md b/docs/RELEASING.md index ab5870f2..a5f889b7 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -65,8 +65,14 @@ The script writes the signed APK and verification metadata to `output/release-2026071301/` and creates a draft GitHub release containing: - `TrackerControl-githubRelease-latest.apk` -- `SHA256SUMS.txt` -- `BUILD-INFO.txt` +- `TrackerControl-githubRelease-latest.apk.sha256sums` +- `TrackerControl-githubRelease-latest.apk.build-info.txt` + +The two metadata files are named with the APK filename as a prefix so they +always sort alphabetically after it. The GitHub API returns release assets +ordered by name, and the app's in-app update checker always downloads +`assets[0]`; without this ordering it can fetch `BUILD-INFO.txt` instead of +the APK (#681). Install and test the APK from the draft, then publish the release in GitHub. diff --git a/scripts/build_and_sign.sh b/scripts/build_and_sign.sh index eee5fb0f..38e12f7a 100755 --- a/scripts/build_and_sign.sh +++ b/scripts/build_and_sign.sh @@ -129,9 +129,14 @@ readonly OUTPUT_DIR=${RELEASE_OUTPUT_DIR:-"$ROOT/output/release-$TAG"} mkdir -p "$OUTPUT_DIR" readonly ALIGNED_APK="$TEMP_DIR/TrackerControl-githubRelease-aligned.apk" readonly TEMP_SIGNED_APK="$TEMP_DIR/TrackerControl-githubRelease-signed.apk" +# Asset names must sort alphabetically after the APK: the GitHub API +# returns release assets ordered by name, and the app's update checker +# (ServiceSinkhole#checkUpdate) always takes assets[0] as the download. +# Using the APK filename as a literal prefix guarantees it sorts first +# under any lexicographic comparison, regardless of case-folding rules. readonly SIGNED_APK="$OUTPUT_DIR/TrackerControl-githubRelease-latest.apk" -readonly SIGNED_SUMS="$OUTPUT_DIR/SHA256SUMS.txt" -readonly OUTPUT_BUILD_INFO="$OUTPUT_DIR/BUILD-INFO.txt" +readonly SIGNED_SUMS="$OUTPUT_DIR/TrackerControl-githubRelease-latest.apk.sha256sums" +readonly OUTPUT_BUILD_INFO="$OUTPUT_DIR/TrackerControl-githubRelease-latest.apk.build-info.txt" [[ ! -e $SIGNED_APK ]] || fail "signed output already exists: $SIGNED_APK" printf 'Aligning and signing the APK...\n' From ab26d949201a7ecd68be665ce3e1764bbe71828e Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 28 Jul 2026 06:59:51 +0000 Subject: [PATCH 2/2] Show release version name in update notification, not asset filename checkUpdate() already opened the release's html_url (the GitHub release page) rather than a direct asset link, so tapping the notification was never downloading a raw file. But its title used the first release asset's filename, which is confusing and, per #681, could be a metadata file rather than the APK depending on asset ordering. Use the release's display name (e.g. "Version 2026072702") instead, falling back to a formatted tag if the release has no name. --- .../eu/faircode/netguard/ServiceSinkhole.java | 28 ++++++++++--------- app/src/main/res/values/strings.xml | 1 + 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/eu/faircode/netguard/ServiceSinkhole.java b/app/src/main/java/eu/faircode/netguard/ServiceSinkhole.java index a449bcf8..0ff81506 100644 --- a/app/src/main/java/eu/faircode/netguard/ServiceSinkhole.java +++ b/app/src/main/java/eu/faircode/netguard/ServiceSinkhole.java @@ -803,22 +803,24 @@ private void checkUpdate() { JSONObject jroot = jarray.getJSONObject(0); // JSONObject jroot = new JSONObject(json.toString()); if (jroot.has("tag_name") && jroot.has("html_url") && jroot.has("assets")) { + // Always link to the release page rather than a specific + // asset: the user picks the right download there, and + // the notification doesn't depend on asset ordering. String url = jroot.getString("html_url"); JSONArray jassets = jroot.getJSONArray("assets"); if (jassets.length() > 0) { - JSONObject jasset = jassets.getJSONObject(0); - if (jasset.has("name")) { - long available = jroot.getLong("tag_name"); - String name = jasset.getString("name"); - Log.i(TAG, "Tag " + available + " name " + name + " url " + url); - - long current = Util.getSelfVersionCode(ServiceSinkhole.this); - if (current < available) { - Log.i(TAG, "Update available from " + current + " to " + available); - showUpdateNotification(name, url); - } else - Log.i(TAG, "Up-to-date current version " + current); - } + long available = jroot.getLong("tag_name"); + String name = (jroot.has("name") && !jroot.isNull("name") && jroot.getString("name").length() > 0) + ? jroot.getString("name") + : getString(R.string.title_version, available); + Log.i(TAG, "Tag " + available + " name " + name + " url " + url); + + long current = Util.getSelfVersionCode(ServiceSinkhole.this); + if (current < available) { + Log.i(TAG, "Update available from " + current + " to " + available); + showUpdateNotification(name, url); + } else + Log.i(TAG, "Up-to-date current version " + current); } } } catch (JSONException ex) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b3825919..4f8f7323 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -346,6 +346,7 @@ Your internet traffic is not being sent to a remote VPN server. No active internet connection TrackerControl is busy Update available, tap to download + Version %1$d You can allow (greenish) or deny (reddish) Wi-Fi or mobile internet access by tapping on the icons next to an app Incoming (push) messages are mostly handled by the system component Play services, which is allowed internet access by default Managing all (system) apps can be enabled in the settings