From 6ad17594187fd2c067fb483143d700af06d16ddf Mon Sep 17 00:00:00 2001
From: Konrad Kollnig <5175206+kasnder@users.noreply.github.com>
Date: Sun, 12 Jul 2026 13:35:41 +0200
Subject: [PATCH 1/9] Make Rust build F-Droid compatible
---
.github/workflows/test.yml | 7 +-
FDROID-UPDATE.md | 129 ++++++++++++++++++++++++++++++++++
README.md | 7 +-
app/build.gradle | 26 ++++---
rust-toolchain.toml | 9 +++
scripts/setup_rust_android.sh | 28 ++++++++
wgbridge-rs/README.md | 38 +++++-----
7 files changed, 208 insertions(+), 36 deletions(-)
create mode 100644 FDROID-UPDATE.md
create mode 100644 rust-toolchain.toml
create mode 100755 scripts/setup_rust_android.sh
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 7fdbdeff0..76faa07dd 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -22,10 +22,7 @@ jobs:
distribution: 'temurin'
- name: Set up Rust
- run: |
- rustup toolchain install stable --profile minimal
- rustup target add armv7-linux-androideabi aarch64-linux-android i686-linux-android x86_64-linux-android
- cargo install cargo-ndk
+ run: ./scripts/setup_rust_android.sh
- name: Cache cargo registry and build
uses: actions/cache@v6
@@ -40,7 +37,7 @@ jobs:
uses: gradle/actions/setup-gradle@v6
- name: Run Rust unit tests
- run: cargo test --manifest-path wgbridge-rs/Cargo.toml
+ run: cargo test --manifest-path wgbridge-rs/Cargo.toml --locked --offline
- name: Run unit tests
run: ./gradlew testGithubDebugUnitTest
diff --git a/FDROID-UPDATE.md b/FDROID-UPDATE.md
new file mode 100644
index 000000000..62ae7443b
--- /dev/null
+++ b/FDROID-UPDATE.md
@@ -0,0 +1,129 @@
+# Updating TrackerControl on F-Droid
+
+TrackerControl's WireGuard engine is compiled from Rust source. New F-Droid
+build entries must prepare the pinned Rust toolchain and Cargo dependencies
+before F-Droid starts its offline Gradle build.
+
+The examples below use release `2026071201` / `2026.07.12`. Substitute the
+actual version code and version name for later releases.
+
+## 1. Tag the release
+
+Only tag a commit that includes the current `rust-toolchain.toml`,
+`wgbridge-rs/Cargo.lock`, and `scripts/setup_rust_android.sh` files.
+
+```bash
+git tag 2026071201
+git push origin 2026071201
+```
+
+TrackerControl's F-Droid metadata uses numeric tags as release identifiers.
+
+## 2. Prepare an fdroiddata merge request
+
+Fork [fdroid/fdroiddata](https://gitlab.com/fdroid/fdroiddata), then clone the
+fork and create a branch:
+
+```bash
+git clone https://gitlab.com/YOUR_USERNAME/fdroiddata.git
+cd fdroiddata
+git remote add upstream https://gitlab.com/fdroid/fdroiddata.git
+git switch -c trackercontrol-2026071201
+```
+
+Edit:
+
+```text
+metadata/net.kollnig.missioncontrol.fdroid.yml
+```
+
+Append this entry under `Builds:`:
+
+```yaml
+ - versionName: 2026.07.12-fdroid
+ versionCode: 2026071201
+ commit: '2026071201'
+ subdir: app
+ sudo:
+ - apt-get update
+ - apt-get install -y rustup gcc libc-dev
+ gradle:
+ - fdroid
+ prebuild:
+ - ../scripts/setup_rust_android.sh
+ ndk: r27c
+```
+
+Update the current-version fields at the bottom of the file:
+
+```yaml
+CurrentVersion: 2026.07.12-fdroid
+CurrentVersionCode: 2026071201
+```
+
+Keep the automatic-update configuration unchanged:
+
+```yaml
+AutoUpdateMode: Version
+UpdateCheckMode: Tags ^[0-9]+$
+```
+
+## 3. Validate the metadata
+
+With `fdroidserver` installed and available on `PATH`, run from the
+`fdroiddata` checkout:
+
+```bash
+fdroid readmeta
+fdroid lint net.kollnig.missioncontrol.fdroid
+```
+
+For an end-to-end local application check, first provision the pinned Rust
+dependencies while networking is available, then build the release offline:
+
+```bash
+./scripts/setup_rust_android.sh
+./gradlew :app:assembleFdroidRelease --offline
+```
+
+The APK should contain `libwgbridge.so` for `armeabi-v7a`, `arm64-v8a`, `x86`,
+and `x86_64`.
+
+## 4. Submit the metadata change
+
+From the `fdroiddata` checkout:
+
+```bash
+git add metadata/net.kollnig.missioncontrol.fdroid.yml
+git commit -m "Update TrackerControl to 2026071201"
+git push origin trackercontrol-2026071201
+```
+
+Open a merge request from that branch into `fdroid/fdroiddata:master`.
+
+Suggested merge-request description:
+
+```text
+TrackerControl now builds its WireGuard engine from Rust source.
+
+The prebuild step installs the repository-pinned Rust toolchain, Android
+targets, and cargo-ndk, and fetches Cargo.lock dependencies. The Gradle build
+itself runs Cargo with --locked --offline.
+
+Locally verified with:
+./gradlew :app:assembleFdroidRelease --offline
+```
+
+## If the update bot opens a merge request first
+
+The checkupdates bot normally copies the previous build recipe, which does not
+contain the Rust preparation steps. Its source branch belongs to F-Droid's bot
+fork and may not be editable by the TrackerControl maintainers.
+
+Create the complete merge request from the TrackerControl maintainer's own
+`fdroiddata` fork as described above. Comment on the bot merge request with a
+link to the replacement and ask F-Droid's maintainers to close the bot merge
+request in favor of it.
+
+F-Droid's general contribution guide is available at
+.
diff --git a/README.md b/README.md
index e4d99bae8..debb7f084 100644
--- a/README.md
+++ b/README.md
@@ -133,11 +133,10 @@ In combination with F-Droid, this repository uses automated builds and follows a
You need:
- Android Studio (with the Android SDK and build tools)
-- Android NDK (any recent version)
-- Rust via [rustup](https://rustup.rs) with the Android targets, for the WireGuard engine ([gotatun](https://github.com/mullvad/gotatun), built from source in `wgbridge-rs/`):
+- Android NDK 27.2.12479018 (r27c)
+- Rust via [rustup](https://rustup.rs), for the WireGuard engine ([gotatun](https://github.com/mullvad/gotatun), built from source in `wgbridge-rs/`). The compiler, Android targets, and `cargo-ndk` version are pinned; install them and pre-fetch locked crates with:
```bash
- rustup target add armv7-linux-androideabi aarch64-linux-android i686-linux-android x86_64-linux-android
- cargo install cargo-ndk
+ ./scripts/setup_rust_android.sh
```
Build from within Android Studio, or use the provided gradle wrapper — see the [Android developer documentation](https://developer.android.com/studio/build/building-cmdline). If you find any problems with these instructions, please file an issue.
diff --git a/app/build.gradle b/app/build.gradle
index f78459324..af113769e 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -9,6 +9,7 @@ def wgbridgeSrcDir = file("$rootDir/wgbridge-rs")
def wgbridgeOutDir = file("$buildDir/rustJniLibs")
def wgbridgeAbis = ['armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64']
def wgbridgeNdkVersion = '27.2.12479018' // keep in sync with defaultConfig.ndkVersion
+def wgbridgeCargoNdkVersion = '4.1.2' // keep in sync with scripts/setup_rust_android.sh
// Resolve the NDK directory the way AGP does (local.properties, then env),
// since modern AGP extensions no longer expose android.ndkDirectory.
@@ -70,7 +71,7 @@ tasks.register('wgbridgeBuild') {
Could not find a `cargo` executable. Install Rust via rustup
(https://rustup.rs), then:
rustup target add armv7-linux-androideabi aarch64-linux-android i686-linux-android x86_64-linux-android
- cargo install cargo-ndk
+ cargo install cargo-ndk@${wgbridgeCargoNdkVersion} --locked
and either add ~/.cargo/bin to PATH (restart Android Studio),
or pass -PcargoBin=/path/to/cargo to Gradle.
""".stripIndent())
@@ -104,20 +105,23 @@ tasks.register('wgbridgeBuild') {
env['CARGO_ENCODED_RUSTFLAGS'] = rustFlags.join('\u001f')
env.remove('RUSTFLAGS')
- // cargo-ndk drives the per-ABI cross-compilation and linker setup.
- def cargoNdk = "${System.getProperty('user.home')}/.cargo/bin/cargo-ndk"
- if (!file(cargoNdk).canExecute() &&
- !env['PATH'].split(File.pathSeparator).any { file("$it/cargo-ndk").canExecute() }) {
- logger.lifecycle('Installing cargo-ndk ...')
- providers.exec {
- environment env
- commandLine cargoBin, 'install', 'cargo-ndk'
- }.result.get().assertNormalExitValue()
+ // Tool installation must happen before Gradle runs. In particular,
+ // F-Droid disables network access for the actual build phase.
+ def cargoNdkAvailable = file("${System.getProperty('user.home')}/.cargo/bin/cargo-ndk").canExecute() ||
+ env['PATH'].split(File.pathSeparator).any { file("$it/cargo-ndk").canExecute() }
+ if (!cargoNdkAvailable) {
+ throw new GradleException("""
+ Could not find cargo-ndk ${wgbridgeCargoNdkVersion}. Run:
+ ./scripts/setup_rust_android.sh
+ Gradle deliberately does not install build tools because release
+ and F-Droid builds must be able to run without network access.
+ """.stripIndent())
}
def args = [cargoBin, 'ndk']
wgbridgeAbis.each { args += ['-t', it] }
- args += ['--platform', '23', '-o', wgbridgeOutDir.absolutePath, 'build', '--release']
+ args += ['--platform', '23', '-o', wgbridgeOutDir.absolutePath,
+ 'build', '--release', '--locked', '--offline']
providers.exec {
workingDir wgbridgeSrcDir
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
new file mode 100644
index 000000000..47e85ae94
--- /dev/null
+++ b/rust-toolchain.toml
@@ -0,0 +1,9 @@
+[toolchain]
+channel = "1.95.0"
+profile = "minimal"
+targets = [
+ "aarch64-linux-android",
+ "armv7-linux-androideabi",
+ "i686-linux-android",
+ "x86_64-linux-android",
+]
diff --git a/scripts/setup_rust_android.sh b/scripts/setup_rust_android.sh
new file mode 100755
index 000000000..1324692dd
--- /dev/null
+++ b/scripts/setup_rust_android.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+set -eu
+
+ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
+CARGO_NDK_VERSION=4.1.2
+
+if ! command -v rustup >/dev/null 2>&1; then
+ echo "rustup is required; install it before running this script." >&2
+ exit 1
+fi
+
+# rust-toolchain.toml pins the compiler and Android targets. This command is
+# idempotent and makes the required components available before offline builds.
+rustup toolchain install 1.95.0 --profile minimal \
+ --target aarch64-linux-android \
+ --target armv7-linux-androideabi \
+ --target i686-linux-android \
+ --target x86_64-linux-android
+
+if ! command -v cargo-ndk >/dev/null 2>&1 || \
+ [ "$(cargo-ndk --version 2>/dev/null | awk '{print $2}')" != "$CARGO_NDK_VERSION" ]; then
+ cargo install "cargo-ndk@$CARGO_NDK_VERSION" --locked
+fi
+
+# Populate Cargo's cache while networking is allowed. wgbridgeBuild passes
+# --offline and --locked so the later Gradle/F-Droid build cannot fetch or
+# silently change dependencies.
+cargo fetch --manifest-path "$ROOT/wgbridge-rs/Cargo.toml" --locked
diff --git a/wgbridge-rs/README.md b/wgbridge-rs/README.md
index fd2d08125..a9996a560 100644
--- a/wgbridge-rs/README.md
+++ b/wgbridge-rs/README.md
@@ -49,17 +49,20 @@ as its output, so it's skipped when the Rust source hasn't changed.
### Prerequisites
-- **Rust ≥ 1.95** via [rustup](https://rustup.rs), with the Android targets:
+- **Rust 1.95.0** via [rustup](https://rustup.rs). The version and Android
+ targets are pinned in the repository's `rust-toolchain.toml`.
+- **cargo-ndk 4.1.2**.
+- **Android NDK 27.2.12479018 (r27c)** (the Gradle task points cargo-ndk at
+ the NDK configured for the app module).
- ```bash
- rustup target add armv7-linux-androideabi aarch64-linux-android \
- i686-linux-android x86_64-linux-android
- ```
+Install the pinned Rust prerequisites and pre-fetch the locked crates with:
-- **cargo-ndk**: `cargo install cargo-ndk` (the Gradle task installs it
- automatically if missing).
-- **Android NDK ≥ 27** (the Gradle task points cargo-ndk at the NDK
- configured for the app module).
+```bash
+./scripts/setup_rust_android.sh
+```
+
+The Gradle build is intentionally offline: it never installs tools or fetches
+crates. This keeps local, CI, and F-Droid builds on the same inputs.
### Manual build (debugging)
@@ -84,20 +87,23 @@ cargo test
## F-Droid build metadata
-The F-Droid build server doesn't ship Rust by default. Add the following
-to the `Builds:` entry in `metadata/net.kollnig.missioncontrol.yml`:
+The F-Droid build server doesn't ship the required Rust setup by default. Add
+the following to the new `Builds:` entry in
+`metadata/net.kollnig.missioncontrol.fdroid.yml`:
```yaml
sudo:
- apt-get update
- - apt-get install -y curl build-essential
+ - apt-get install -y rustup gcc libc-dev
prebuild:
- - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal
- - source $HOME/.cargo/env
- - rustup target add armv7-linux-androideabi aarch64-linux-android i686-linux-android x86_64-linux-android
- - cargo install cargo-ndk
+ - ../scripts/setup_rust_android.sh
+ndk: r27c
```
+The existing `gradle: [fdroid]` setting remains unchanged. The prebuild step
+runs while dependency downloads are allowed; Gradle subsequently compiles the
+locked crate graph with Cargo offline.
+
## Java/Kotlin API surface
The Java classes in `app/src/main/java/net/kollnig/missioncontrol/wgbridge/`
From 8eb022a304ebabc7dd97b1d455d27f10d9fb26f5 Mon Sep 17 00:00:00 2001
From: Konrad Kollnig <5175206+kasnder@users.noreply.github.com>
Date: Sun, 12 Jul 2026 13:38:59 +0200
Subject: [PATCH 2/9] Test F-Droid release build in CI
---
.github/workflows/test.yml | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 76faa07dd..4c2de67f5 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -3,6 +3,7 @@ name: Test
on:
push:
branches: [ master, main ]
+ tags: [ '[0-9]*' ]
pull_request:
branches: [ master, main ]
@@ -21,9 +22,6 @@ jobs:
java-version: '17'
distribution: 'temurin'
- - name: Set up Rust
- run: ./scripts/setup_rust_android.sh
-
- name: Cache cargo registry and build
uses: actions/cache@v6
with:
@@ -33,14 +31,28 @@ jobs:
wgbridge-rs/target
key: cargo-${{ runner.os }}-${{ hashFiles('wgbridge-rs/Cargo.lock') }}
+ - name: Set up Rust
+ run: ./scripts/setup_rust_android.sh
+
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v6
+ - name: Prefetch Gradle dependencies
+ run: ./gradlew :app:dependencies
+
- name: Run Rust unit tests
run: cargo test --manifest-path wgbridge-rs/Cargo.toml --locked --offline
- name: Run unit tests
- run: ./gradlew testGithubDebugUnitTest
-
- - name: Build debug APK
- run: ./gradlew assembleGithubDebug
+ run: ./gradlew testGithubDebugUnitTest --offline
+
+ - name: Build F-Droid release APK offline
+ run: ./gradlew :app:assembleFdroidRelease --offline
+
+ - name: Verify WireGuard libraries in F-Droid APK
+ run: |
+ APK=$(find app/build/outputs/apk/fdroid -type f -name '*.apk' -print -quit)
+ test -n "$APK"
+ for ABI in armeabi-v7a arm64-v8a x86 x86_64; do
+ test "$(unzip -Z1 "$APK" "lib/$ABI/libwgbridge.so")" = "lib/$ABI/libwgbridge.so"
+ done
From c9b68a8b24874bd52d5afb484add89cacb27e3f2 Mon Sep 17 00:00:00 2001
From: Konrad Kollnig <5175206+kasnder@users.noreply.github.com>
Date: Sun, 12 Jul 2026 13:47:44 +0200
Subject: [PATCH 3/9] Prevent Crowdin translating resource references
---
app/src/main/res/values-ru-rRU/strings.xml | 5 -----
app/src/main/res/values-uk-rUA/strings.xml | 5 -----
app/src/main/res/values-zh-rCN/strings.xml | 5 -----
app/src/main/res/values/strings.xml | 2 +-
4 files changed, 1 insertion(+), 16 deletions(-)
diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml
index b1198b747..78ea45f6b 100644
--- a/app/src/main/res/values-ru-rRU/strings.xml
+++ b/app/src/main/res/values-ru-rRU/strings.xml
@@ -263,11 +263,6 @@
Whois %1$s
Порт %1$d
Скопировать
-
- - @string/blocking_mode_minimal
- - Строка/blocking_mode_standard
- - Строка/blocking_mode_strict
-
Отключить доступ в интернет для этого приложения
Название приложения
diff --git a/app/src/main/res/values-uk-rUA/strings.xml b/app/src/main/res/values-uk-rUA/strings.xml
index 035aae9c0..bc64ec540 100644
--- a/app/src/main/res/values-uk-rUA/strings.xml
+++ b/app/src/main/res/values-uk-rUA/strings.xml
@@ -376,11 +376,6 @@
Whois %1$s
Порт %1$d
Копіювати
-
- - @string/режим_блокування_мінімальний
- - @string/режим_блокування_стандартний
- - @string/режим_блокування_суворий
-
Вимкнути доступ до Інтернету для цієї програми
Назва програми
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index 1754079cc..5e6b84276 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -378,11 +378,6 @@
Whois %1$s
端口 %1$d
复制
-
- - 最小
- - 标准
- - 严格
-
禁止此应用访问互联网
应用程序名称
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 269e8916e..ece6610a5 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -439,7 +439,7 @@ Your internet traffic is not being sent to a remote VPN server.
Port %1$d
Copy
-
+
- @string/blocking_mode_minimal
- @string/blocking_mode_standard
- @string/blocking_mode_strict
From 9948340ff2c69957b4700d817e54d45547a196a2 Mon Sep 17 00:00:00 2001
From: Konrad Kollnig <5175206+kasnder@users.noreply.github.com>
Date: Sun, 12 Jul 2026 13:54:17 +0200
Subject: [PATCH 4/9] Provision native tools before offline CI build
---
.github/workflows/test.yml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 4c2de67f5..ab85a87ca 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -22,6 +22,9 @@ jobs:
java-version: '17'
distribution: 'temurin'
+ - name: Install Android native build tools
+ run: sdkmanager "cmake;3.22.1" "ndk;27.2.12479018"
+
- name: Cache cargo registry and build
uses: actions/cache@v6
with:
From b0c4edfbc14185b25f92f1ed20bfcfcc945540a9 Mon Sep 17 00:00:00 2001
From: Konrad Kollnig <5175206+kasnder@users.noreply.github.com>
Date: Sun, 12 Jul 2026 13:58:01 +0200
Subject: [PATCH 5/9] Use hosted Android SDK manager path
---
.github/workflows/test.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index ab85a87ca..6ca3d8e2d 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -23,7 +23,7 @@ jobs:
distribution: 'temurin'
- name: Install Android native build tools
- run: sdkmanager "cmake;3.22.1" "ndk;27.2.12479018"
+ run: "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" "cmake;3.22.1" "ndk;27.2.12479018"
- name: Cache cargo registry and build
uses: actions/cache@v6
From e6c472ef86fdedd3afd149e437d3cd458688b1d1 Mon Sep 17 00:00:00 2001
From: Konrad Kollnig <5175206+kasnder@users.noreply.github.com>
Date: Sun, 12 Jul 2026 14:33:23 +0200
Subject: [PATCH 6/9] Fix native tool setup workflow syntax
---
.github/workflows/test.yml | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 6ca3d8e2d..086b36ed9 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -23,7 +23,10 @@ jobs:
distribution: 'temurin'
- name: Install Android native build tools
- run: "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" "cmake;3.22.1" "ndk;27.2.12479018"
+ run: |
+ "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" \
+ "cmake;3.22.1" \
+ "ndk;27.2.12479018"
- name: Cache cargo registry and build
uses: actions/cache@v6
From ce59be5bd1a8bc11ff751805fa3fc91cf64feb54 Mon Sep 17 00:00:00 2001
From: Konrad Kollnig <5175206+kasnder@users.noreply.github.com>
Date: Sun, 12 Jul 2026 14:37:24 +0200
Subject: [PATCH 7/9] Run unit tests against F-Droid flavor
---
.github/workflows/test.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 086b36ed9..6cfc1ff22 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -50,7 +50,7 @@ jobs:
run: cargo test --manifest-path wgbridge-rs/Cargo.toml --locked --offline
- name: Run unit tests
- run: ./gradlew testGithubDebugUnitTest --offline
+ run: ./gradlew testFdroidDebugUnitTest --offline
- name: Build F-Droid release APK offline
run: ./gradlew :app:assembleFdroidRelease --offline
From bd234a55a0a0810bd041ac6a0c793fc548274d0e Mon Sep 17 00:00:00 2001
From: Konrad Kollnig <5175206+kasnder@users.noreply.github.com>
Date: Sun, 12 Jul 2026 14:41:49 +0200
Subject: [PATCH 8/9] Prefetch Android lint dependencies
---
.github/workflows/test.yml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 6cfc1ff22..1cb129c7b 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -44,7 +44,9 @@ jobs:
uses: gradle/actions/setup-gradle@v6
- name: Prefetch Gradle dependencies
- run: ./gradlew :app:dependencies
+ run: |
+ ./gradlew :app:dependencies
+ ./gradlew :app:dependencies --configuration androidLintTool
- name: Run Rust unit tests
run: cargo test --manifest-path wgbridge-rs/Cargo.toml --locked --offline
From 26f0ddaabd978b01953720d298b041b7761456ec Mon Sep 17 00:00:00 2001
From: Konrad Kollnig <5175206+kasnder@users.noreply.github.com>
Date: Sun, 12 Jul 2026 14:51:58 +0200
Subject: [PATCH 9/9] Materialize lint artifacts before offline build
---
.github/workflows/test.yml | 2 +-
app/build.gradle | 10 ++++++++++
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 1cb129c7b..2dd583c0f 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -46,7 +46,7 @@ jobs:
- name: Prefetch Gradle dependencies
run: |
./gradlew :app:dependencies
- ./gradlew :app:dependencies --configuration androidLintTool
+ ./gradlew :app:prefetchAndroidLintDependencies
- name: Run Rust unit tests
run: cargo test --manifest-path wgbridge-rs/Cargo.toml --locked --offline
diff --git a/app/build.gradle b/app/build.gradle
index af113769e..55ccb7669 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,6 +11,16 @@ def wgbridgeAbis = ['armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64']
def wgbridgeNdkVersion = '27.2.12479018' // keep in sync with defaultConfig.ndkVersion
def wgbridgeCargoNdkVersion = '4.1.2' // keep in sync with scripts/setup_rust_android.sh
+// Resolves the lint tool artifacts while networking is available so release
+// builds can subsequently run with Gradle's --offline flag (as on F-Droid).
+tasks.register('prefetchAndroidLintDependencies') {
+ description = 'Downloads the Android lint tool artifacts for a later offline build.'
+ group = 'build setup'
+ doLast {
+ configurations.named('androidLintTool').get().resolve()
+ }
+}
+
// Resolve the NDK directory the way AGP does (local.properties, then env),
// since modern AGP extensions no longer expose android.ndkDirectory.
def findNdkDirectory = { ->