summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJonatan Rhodin <jonatan.rhodin@mullvad.net>2025-01-08 09:33:44 +0100
committerJonatan Rhodin <jonatan.rhodin@mullvad.net>2025-01-08 10:48:48 +0100
commit1c1ca559b69810904538c2e46c2326d2ebcaa014 (patch)
treee42cb4535910bdeeb25018786035a21130e5ff31
parentac9ac4b824b62d60f64be46f69a4678152d64fb5 (diff)
downloadmullvadvpn-1c1ca559b69810904538c2e46c2326d2ebcaa014.tar.xz
mullvadvpn-1c1ca559b69810904538c2e46c2326d2ebcaa014.zip
Add gradle rust plugin
-rw-r--r--.github/workflows/android-app.yml85
-rw-r--r--.github/workflows/daemon.yml1
-rw-r--r--.github/workflows/testframework.yml1
-rw-r--r--android/BuildInstructions.md10
-rw-r--r--android/app/build.gradle.kts110
-rw-r--r--android/build.gradle.kts3
-rwxr-xr-xandroid/build.sh (renamed from build-apk.sh)61
-rw-r--r--android/buildSrc/src/main/kotlin/Versions.kt1
-rw-r--r--android/docker/Dockerfile2
-rw-r--r--android/docs/BuildInstructions.macos.md24
-rw-r--r--android/docs/DebugInstructions.md16
-rw-r--r--android/gradle/libs.versions.toml6
-rwxr-xr-xandroid/scripts/update-lockfile.sh4
-rw-r--r--building/android-container-image.txt2
-rwxr-xr-xbuilding/containerized-build.sh2
15 files changed, 176 insertions, 152 deletions
diff --git a/.github/workflows/android-app.yml b/.github/workflows/android-app.yml
index 5e784b5d69..a035439ead 100644
--- a/.github/workflows/android-app.yml
+++ b/.github/workflows/android-app.yml
@@ -98,7 +98,7 @@ jobs:
retention-days: 7
generate-relay-list:
- name: Generate relay list
+ name: Generate relay list # Used by wait for jobs.
needs: prepare
runs-on: ubuntu-latest
container:
@@ -129,11 +129,8 @@ jobs:
- name: Generate
if: steps.cache-relay-list.outputs.cache-hit != 'true'
- env:
- RUSTFLAGS: --deny warnings
- run: |
- mkdir -p android/app/build/extraAssets
- cargo run --bin relay_list > android/app/build/extraAssets/relays.json
+ shell: bash
+ run: ./android/gradlew -p android generateRelayList
- name: Upload
uses: actions/upload-artifact@v4
@@ -144,7 +141,7 @@ jobs:
retention-days: 7
build-native:
- name: Build native
+ name: Build native # Used by wait for jobs.
needs: prepare
runs-on: ubuntu-latest
container:
@@ -152,18 +149,14 @@ jobs:
strategy:
matrix:
include:
- - arch: "x86_64"
- abi: "x86_64"
- target: "x86_64-linux-android"
- - arch: "i686"
- abi: "x86"
- target: "i686-linux-android"
- - arch: "aarch64"
- abi: "arm64-v8a"
- target: "aarch64-linux-android"
- - arch: "armv7"
- abi: "armeabi-v7a"
- target: "armv7-linux-androideabi"
+ - abi: "x86_64"
+ task-variant: "X86_64"
+ - abi: "x86"
+ task-variant: "X86"
+ - abi: "arm64-v8a"
+ task-variant: "Arm64"
+ - abi: "armeabi-v7a"
+ task-variant: "Arm"
steps:
# Fix for HOME path overridden by GH runners when building in containers, see:
# https://github.com/actions/runner/issues/863
@@ -197,27 +190,28 @@ jobs:
env:
cache_hash: ${{ steps.native-lib-cache-hash.outputs.native_lib_hash }}
with:
- path: ./android/app/build/extraJni
+ path: ./android/app/build/rustJniLibs/android
key: android-native-libs-${{ runner.os }}-${{ matrix.abi }}-${{ env.cache_hash }}
- name: Build native libraries
if: steps.cache-native-libs.outputs.cache-hit != 'true'
- env:
- RUSTFLAGS: --deny warnings
- BUILD_TYPE: debug
- run: |
- ARCHITECTURES="${{ matrix.abi }}"
- UNSTRIPPED_LIB_PATH="$CARGO_TARGET_DIR/${{ matrix.target }}/$BUILD_TYPE/libmullvad_jni.so"
- STRIPPED_LIB_PATH="./android/app/build/extraJni/${{ matrix.abi }}/libmullvad_jni.so"
- NDK_TOOLCHAIN_STRIP_TOOL="$NDK_TOOLCHAIN_DIR/llvm-strip"
- cargo build --target ${{ matrix.target }} --verbose --package mullvad-jni --features api-override
- $NDK_TOOLCHAIN_STRIP_TOOL --strip-debug --strip-unneeded -o "$STRIPPED_LIB_PATH" "$UNSTRIPPED_LIB_PATH"
+ uses: burrunan/gradle-cache-action@v1
+ with:
+ job-id: jdk17
+ arguments: cargoBuild${{ matrix.task-variant }}
+ gradle-version: wrapper
+ build-root-directory: android
+ execution-only-caches: false
+ # Disable if logs are hard to follow.
+ concurrent: true
+ read-only: ${{ github.ref != 'refs/heads/main' }}
+
- name: Upload native libs
uses: actions/upload-artifact@v4
with:
- name: native-libs-${{ matrix.arch }}
- path: android/app/build/extraJni
+ name: native-libs-${{ matrix.abi }}
+ path: android/app/build/rustJniLibs/android
if-no-files-found: error
retention-days: 7
@@ -290,7 +284,9 @@ jobs:
uses: burrunan/gradle-cache-action@v1
with:
job-id: jdk17
- arguments: compileOssProdDebugKotlin
+ arguments: |
+ compileOssProdDebugKotlin
+ -x cargoBuild
gradle-version: wrapper
build-root-directory: android
execution-only-caches: false
@@ -299,24 +295,26 @@ jobs:
read-only: ${{ github.ref != 'refs/heads/main' }}
- name: Wait for other jobs (native, relay list)
- uses: kachick/wait-other-jobs@v2.0.3
+ uses: kachick/wait-other-jobs@v3.6.0
with:
+ wait-seconds-before-first-polling: '0'
wait-list: |
[
{
"workflowFile": "android-app.yml",
- "jobName": "build-native"
+ "jobMatchMode": "prefix",
+ "jobName": "Build native"
},
{
"workflowFile": "android-app.yml",
- "jobName": "generate-relay-list"
+ "jobName": "Generate relay list"
}
]
- uses: actions/download-artifact@v4
with:
pattern: native-libs-*
- path: android/app/build/extraJni
+ path: android/app/build/rustJniLibs/android
merge-multiple: true
- uses: actions/download-artifact@v4
@@ -328,7 +326,9 @@ jobs:
uses: burrunan/gradle-cache-action@v1
with:
job-id: jdk17
- arguments: assembleOssProdDebug
+ arguments: |
+ assembleOssProdDebug
+ -x cargoBuild
gradle-version: wrapper
build-root-directory: android
execution-only-caches: true
@@ -341,7 +341,9 @@ jobs:
if: github.event.inputs.run_firebase_tests == 'true'
with:
job-id: jdk17
- arguments: assemblePlayStagemoleDebug
+ arguments: |
+ assemblePlayStagemoleDebug
+ -x cargoBuild
gradle-version: wrapper
build-root-directory: android
execution-only-caches: true
@@ -396,7 +398,10 @@ jobs:
uses: burrunan/gradle-cache-action@v1
with:
job-id: jdk17
- arguments: ${{ matrix.assemble-command }}
+ arguments: |
+ ${{ matrix.assemble-command }}
+ -x cargoBuild
+ -x generateRelayList
gradle-version: wrapper
build-root-directory: android
execution-only-caches: false
diff --git a/.github/workflows/daemon.yml b/.github/workflows/daemon.yml
index 2b6241d76f..2727d6697b 100644
--- a/.github/workflows/daemon.yml
+++ b/.github/workflows/daemon.yml
@@ -10,7 +10,6 @@ on:
- '!.github/CODEOWNERS'
- '!android/**'
- '!audits/**'
- - '!build-apk.sh'
- '!build.sh'
- '!ci/**'
- 'ci/check-rust.sh'
diff --git a/.github/workflows/testframework.yml b/.github/workflows/testframework.yml
index f8d729d271..288aee4273 100644
--- a/.github/workflows/testframework.yml
+++ b/.github/workflows/testframework.yml
@@ -10,7 +10,6 @@ on:
- '.github/workflows/daemon.yml'
- '!android/**'
- '!audits/**'
- - '!build-apk.sh'
- '!build.sh'
- '!ci/**'
- '!clippy.toml'
diff --git a/android/BuildInstructions.md b/android/BuildInstructions.md
index c80214f013..e89d1b3102 100644
--- a/android/BuildInstructions.md
+++ b/android/BuildInstructions.md
@@ -118,10 +118,10 @@ Linux distro:
```bash
cd "$ANDROID_HOME" # Or some other directory to place the Android NDK
- wget https://dl.google.com/android/repository/android-ndk-r27b-linux.zip
- unzip android-ndk-r27b-linux.zip
+ wget https://dl.google.com/android/repository/android-ndk-r27c-linux.zip
+ unzip android-ndk-r27c-linux.zip
- cd android-ndk-r27b
+ cd android-ndk-r27c
export ANDROID_NDK_HOME="$PWD"
```
@@ -162,7 +162,7 @@ Run the following command to download wireguard-go-rs submodule: `git submodule
### Debug build
Run the following command to build a debug build:
```bash
-../build-apk.sh --dev-build
+../android/build.sh --dev-build
```
### Release build
@@ -170,7 +170,7 @@ Run the following command to build a debug build:
2. Move, copy or symlink the directory from step 1 to [./credentials/](./credentials/) (`<repository>/android/credentials/`).
3. Run the following command to build:
```bash
- ../build-apk.sh --app-bundle
+ ../android/build.sh --app-bundle
```
## Configure signing key
diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts
index 5fed7575d4..dd1444302c 100644
--- a/android/app/build.gradle.kts
+++ b/android/app/build.gradle.kts
@@ -1,7 +1,9 @@
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
import com.android.build.gradle.internal.tasks.factory.dependsOn
import com.github.triplet.gradle.androidpublisher.ReleaseStatus
+import java.io.ByteArrayOutputStream
import java.io.FileInputStream
+import java.io.FileOutputStream
import java.util.Properties
import org.gradle.internal.extensions.stdlib.capitalized
@@ -13,6 +15,7 @@ plugins {
alias(libs.plugins.kotlin.ksp)
alias(libs.plugins.compose)
alias(libs.plugins.protobuf.core)
+ alias(libs.plugins.rust.android.gradle)
id(Dependencies.junit5AndroidPluginId) version Versions.junit5Plugin
}
@@ -21,7 +24,6 @@ val repoRootPath = rootProject.projectDir.absoluteFile.parentFile.absolutePath
val extraAssetsDirectory = layout.buildDirectory.dir("extraAssets").get()
val relayListPath = extraAssetsDirectory.file("relays.json").asFile
val defaultChangelogAssetsDirectory = "$repoRootPath/android/src/main/play/release-notes/"
-val extraJniDirectory = layout.buildDirectory.dir("extraJni").get()
val credentialsPath = "${rootProject.projectDir}/credentials"
val keystorePropertiesFile = file("$credentialsPath/keystore.properties")
@@ -35,6 +37,7 @@ android {
namespace = "net.mullvad.mullvadvpn"
compileSdk = Versions.compileSdkVersion
buildToolsVersion = Versions.buildToolsVersion
+ ndkVersion = Versions.ndkVersion
defaultConfig {
val localProperties = gradleLocalProperties(rootProject.projectDir, providers)
@@ -126,7 +129,6 @@ android {
.getOrDefault("OVERRIDE_CHANGELOG_DIR", defaultChangelogAssetsDirectory)
assets.srcDirs(extraAssetsDirectory, changelogDir)
- jniLibs.srcDirs(extraJniDirectory)
}
}
@@ -239,12 +241,14 @@ android {
createDistBundle.dependsOn("bundle$capitalizedVariantName")
- // Ensure all relevant assemble tasks depend on our ensure tasks.
- tasks["assemble$capitalizedVariantName"].apply {
- dependsOn(tasks["ensureRelayListExist"])
- dependsOn(tasks["ensureJniDirectoryExist"])
- dependsOn(tasks["ensureValidVersionCode"])
- }
+ // Ensure we have relay list ready before merging assets.
+ tasks["merge${capitalizedVariantName}Assets"].dependsOn(tasks["generateRelayList"])
+
+ // Ensure that we have all the JNI libs before merging them.
+ tasks["merge${capitalizedVariantName}JniLibFolders"].dependsOn("cargoBuild")
+
+ // Ensure all relevant assemble tasks depend on our ensure task.
+ tasks["assemble$capitalizedVariantName"].dependsOn(tasks["ensureValidVersionCode"])
}
}
@@ -255,6 +259,80 @@ junitPlatform {
}
}
+cargo {
+ val isReleaseBuild = isReleaseBuild()
+ val enableApiOverride = !isReleaseBuild || isAlphaOrDevBuild()
+ module = repoRootPath
+ libname = "mullvad-jni"
+ // All available targets:
+ // https://github.com/mozilla/rust-android-gradle/tree/master?tab=readme-ov-file#targets
+ targets =
+ gradleLocalProperties(rootProject.projectDir, providers)
+ .getProperty("CARGO_TARGETS")
+ ?.split(",") ?: listOf("arm", "arm64", "x86", "x86_64")
+ profile =
+ if (isReleaseBuild) {
+ "release"
+ } else {
+ "debug"
+ }
+ prebuiltToolchains = true
+ targetDirectory = "$repoRootPath/target"
+ features {
+ if (enableApiOverride) {
+ defaultAnd(arrayOf("api-override"))
+ }
+ }
+ targetIncludes = arrayOf("libmullvad_jni.so")
+ extraCargoBuildArguments = buildList {
+ add("--package=mullvad-jni")
+ if (isReleaseBuild) {
+ add("--locked")
+ }
+ }
+}
+
+tasks.register<Exec>("generateRelayList") {
+ workingDir = File(repoRootPath)
+ standardOutput = ByteArrayOutputStream()
+
+ onlyIf { isReleaseBuild() || !relayListPath.exists() }
+
+ commandLine("cargo", "run", "--bin", "relay_list")
+
+ doLast {
+ val output = standardOutput as ByteArrayOutputStream
+ // Create file if needed
+ relayListPath.parentFile.mkdirs()
+ relayListPath.createNewFile()
+ FileOutputStream(relayListPath).use { it.write(output.toByteArray()) }
+ }
+}
+
+tasks.register<Exec>("cargoClean") {
+ workingDir = File(repoRootPath)
+ commandLine("cargo", "clean")
+}
+
+if (
+ gradleLocalProperties(rootProject.projectDir, providers)
+ .getProperty("CLEAN_CARGO_BUILD")
+ ?.toBoolean() != false
+) {
+ tasks["clean"].dependsOn("cargoClean")
+}
+
+// This is a hack and will not work correctly under all scenarios.
+// See DROID-1696 for how we can improve this.
+fun isReleaseBuild() =
+ gradle.startParameter.getTaskNames().any { it.contains("release", ignoreCase = true) }
+
+fun isAlphaOrDevBuild(): Boolean {
+ val localProperties = gradleLocalProperties(rootProject.projectDir, providers)
+ val versionName = generateVersionName(localProperties)
+ return versionName.contains("dev") || versionName.contains("alpha")
+}
+
androidComponents {
beforeVariants { variantBuilder ->
variantBuilder.enable =
@@ -276,22 +354,6 @@ configure<org.owasp.dependencycheck.gradle.extension.DependencyCheckExtension> {
skipConfigurations = listOf("lintClassPath")
}
-tasks.register("ensureRelayListExist") {
- doLast {
- if (!relayListPath.exists()) {
- throw GradleException("Missing relay list: $relayListPath")
- }
- }
-}
-
-tasks.register("ensureJniDirectoryExist") {
- doLast {
- if (!extraJniDirectory.asFile.exists()) {
- throw GradleException("Missing JNI directory: $extraJniDirectory")
- }
- }
-}
-
// This is a safety net to avoid generating too big version codes, since that could potentially be
// hard and inconvenient to recover from.
tasks.register("ensureValidVersionCode") {
diff --git a/android/build.gradle.kts b/android/build.gradle.kts
index 24bcb0e4d0..b43f4fec86 100644
--- a/android/build.gradle.kts
+++ b/android/build.gradle.kts
@@ -14,6 +14,7 @@ plugins {
alias(libs.plugins.kotlin.ksp) apply false
alias(libs.plugins.kotlin.parcelize) apply false
alias(libs.plugins.protobuf.core) apply false
+ alias(libs.plugins.rust.android.gradle) apply false
alias(libs.plugins.detekt) apply true
alias(libs.plugins.dependency.versions) apply true
@@ -68,6 +69,8 @@ buildscript {
classpath("$prebuilt:linux-x86_64@tar.gz")
classpath("$prebuilt:macos-aarch64@tar.gz")
classpath("$prebuilt:macos-x86_64@tar.gz")
+
+ classpath("org.mozilla.rust-android-gradle:plugin:${libs.versions.rust.android.gradle}")
}
}
diff --git a/build-apk.sh b/android/build.sh
index da09e06479..43dc034ff8 100755
--- a/build-apk.sh
+++ b/android/build.sh
@@ -18,15 +18,11 @@ BUILD_BUNDLE="no"
BUNDLE_TASKS=(createPlayProdReleaseDistBundle)
RUN_PLAY_PUBLISH_TASKS="no"
PLAY_PUBLISH_TASKS=()
-CARGO_ARGS=( "--release" )
-CARGO_TARGET_DIR=${CARGO_TARGET_DIR:-"target"}
-SKIP_STRIPPING=${SKIP_STRIPPING:-"no"}
while [ -n "${1:-""}" ]; do
if [[ "${1:-""}" == "--dev-build" ]]; then
BUILD_TYPE="debug"
GRADLE_BUILD_TYPE="debug"
- CARGO_ARGS=()
GRADLE_TASKS=(createOssProdDebugDistApk)
BUNDLE_TASKS=(createOssProdDebugDistBundle)
elif [[ "${1:-""}" == "--fdroid" ]]; then
@@ -37,15 +33,13 @@ while [ -n "${1:-""}" ]; do
BUILD_BUNDLE="yes"
elif [[ "${1:-""}" == "--enable-play-publishing" ]]; then
RUN_PLAY_PUBLISH_TASKS="yes"
- elif [[ "${1:-""}" == "--skip-stripping" ]]; then
- SKIP_STRIPPING="yes"
fi
shift 1
done
if [[ "$GRADLE_BUILD_TYPE" == "release" ]]; then
- if [ ! -f "$SCRIPT_DIR/android/credentials/keystore.properties" ]; then
+ if [ ! -f "$SCRIPT_DIR/credentials/keystore.properties" ]; then
echo "ERROR: No keystore.properties file found" >&2
echo " Please configure the signing keys as described in the README" >&2
exit 1
@@ -54,28 +48,16 @@ fi
if [[ "$BUILD_TYPE" == "release" ]]; then
if [[ "$PRODUCT_VERSION" == *"-dev-"* ]]; then
- CARGO_ARGS+=( "--features" "api-override" )
GRADLE_TASKS+=(createPlayDevmoleReleaseDistApk createPlayStagemoleReleaseDistApk)
BUNDLE_TASKS+=(createPlayDevmoleReleaseDistBundle createPlayStagemoleReleaseDistBundle)
elif [[ "$PRODUCT_VERSION" == *"-alpha"* ]]; then
echo "Removing old Rust build artifacts"
- CARGO_ARGS+=( "--locked" )
- cargo clean
- CARGO_ARGS+=( "--features" "api-override" )
GRADLE_TASKS+=(createPlayStagemoleReleaseDistApk)
BUNDLE_TASKS+=(createPlayStagemoleReleaseDistBundle)
PLAY_PUBLISH_TASKS=(publishPlayStagemoleReleaseBundle)
- else
- echo "Removing old Rust build artifacts"
- CARGO_ARGS+=( "--locked" )
- cargo clean
fi
-else
- CARGO_ARGS+=( "--features" "api-override" )
fi
-pushd "$SCRIPT_DIR/android"
-
# Fallback to the system-wide gradle command if the gradlew script is removed.
# It is removed by the F-Droid build process before the build starts.
if [ -f "gradlew" ]; then
@@ -89,48 +71,7 @@ else
fi
$GRADLE_CMD --console plain clean
-mkdir -p "app/build/extraAssets"
-mkdir -p "app/build/extraJni"
-popd
-
-for ARCHITECTURE in ${ARCHITECTURES:-aarch64 armv7 x86_64 i686}; do
- case "$ARCHITECTURE" in
- "x86_64")
- TARGET="x86_64-linux-android"
- ABI="x86_64"
- ;;
- "i686")
- TARGET="i686-linux-android"
- ABI="x86"
- ;;
- "aarch64")
- TARGET="aarch64-linux-android"
- ABI="arm64-v8a"
- ;;
- "armv7")
- TARGET="armv7-linux-androideabi"
- ABI="armeabi-v7a"
- ;;
- esac
-
- echo "Building mullvad-daemon for $TARGET"
- cargo build "${CARGO_ARGS[@]}" --target "$TARGET" --package mullvad-jni
-
- STRIP_TOOL="${NDK_TOOLCHAIN_DIR}/llvm-strip"
- TARGET_LIB_PATH="$SCRIPT_DIR/android/app/build/extraJni/$ABI/libmullvad_jni.so"
- UNSTRIPPED_LIB_PATH="$CARGO_TARGET_DIR/$TARGET/$BUILD_TYPE/libmullvad_jni.so"
-
- if [[ "$SKIP_STRIPPING" == "yes" ]]; then
- cp "$UNSTRIPPED_LIB_PATH" "$TARGET_LIB_PATH"
- else
- $STRIP_TOOL --strip-debug --strip-unneeded -o "$TARGET_LIB_PATH" "$UNSTRIPPED_LIB_PATH"
- fi
-done
-
-echo "Updating relays.json..."
-cargo run --bin relay_list "${CARGO_ARGS[@]}" > android/app/build/extraAssets/relays.json
-cd "$SCRIPT_DIR/android"
$GRADLE_CMD --console plain "${GRADLE_TASKS[@]}"
if [[ "$BUILD_BUNDLE" == "yes" ]]; then
diff --git a/android/buildSrc/src/main/kotlin/Versions.kt b/android/buildSrc/src/main/kotlin/Versions.kt
index 223331cfc5..d08012324b 100644
--- a/android/buildSrc/src/main/kotlin/Versions.kt
+++ b/android/buildSrc/src/main/kotlin/Versions.kt
@@ -4,6 +4,7 @@ object Versions {
const val buildToolsVersion = "35.0.0"
const val minSdkVersion = 26
const val targetSdkVersion = 35
+ const val ndkVersion = "27.2.12479018"
const val junitJupiter = "5.11.4"
const val junit5Android = "1.6.0"
diff --git a/android/docker/Dockerfile b/android/docker/Dockerfile
index 17a68510ed..32175853a6 100644
--- a/android/docker/Dockerfile
+++ b/android/docker/Dockerfile
@@ -8,7 +8,7 @@
# -v $GRADLE_CACHE_VOLUME_NAME:/root/.gradle:Z \
# -v $ANDROID_CREDENTIALS_DIR:/build/android/credentials:Z \
# -v /path/to/repository_root:/build:Z \
-# mullvadvpn-app-build-android ./build-apk.sh --dev-build
+# mullvadvpn-app-build-android ./android/build.sh --dev-build
#
# See the base image Dockerfile in the repository root (../../Dockerfile)
# for more information.
diff --git a/android/docs/BuildInstructions.macos.md b/android/docs/BuildInstructions.macos.md
index 78bf345d1d..0368c1e917 100644
--- a/android/docs/BuildInstructions.macos.md
+++ b/android/docs/BuildInstructions.macos.md
@@ -17,7 +17,7 @@ brew install --cask android-studio
Install the following packages:
```bash
-brew install protobuf gcc go openjdk@17 rustup-init
+brew install protobuf gcc go openjdk@17 rustup-init python3
```
> __*NOTE:*__ Ensure that you setup `openjdk@17` to be the active JDK, follow instructions in
@@ -38,7 +38,7 @@ Open Android Studio -> Tools -> SDK Manager, and install `Android SDK Command-li
Install the necessary Android SDK tools
```bash
-~/Library/Android/sdk/cmdline-tools/latest/bin/sdkmanager "platforms;android-35" "build-tools;35.0.0" "platform-tools" "ndk;27.1.12297006"
+~/Library/Android/sdk/cmdline-tools/latest/bin/sdkmanager "platforms;android-35" "build-tools;35.0.0" "platform-tools" "ndk;27.2.12479018"
```
Install Android targets
@@ -50,7 +50,7 @@ Export the following environmental variables, and possibly store them for exampl
`~/.zprofile` or `~/.zshrc` file:
```bash
export ANDROID_HOME="$HOME/Library/Android/sdk"
-export ANDROID_NDK_HOME="$ANDROID_HOME/ndk/27.1.12297006"
+export ANDROID_NDK_HOME="$ANDROID_HOME/ndk/27.2.12479018"
export NDK_TOOLCHAIN_DIR="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin"
export AR_aarch64_linux_android="$NDK_TOOLCHAIN_DIR/llvm-ar"
export AR_armv7_linux_androideabi="$NDK_TOOLCHAIN_DIR/llvm-ar"
@@ -74,10 +74,23 @@ git submodule update --init --recursive --depth=1 wireguard-go-rs
```
## 4. Debug build
+
+### Android Studio
+
+Create the file `android/local.properties` if it does not exist and add the following line:
+
+```bash
+rust.pythonCommand=/opt/homebrew/bin/python3
+```
+
+You should now be able to run the app directly from Android Studio.
+
+### `android/build.sh`
+
Run the build script in the root of the project to assemble all the native libraries and the app:
```bash
-./build-apk.sh --dev-build
+./android/build.sh --dev-build
```
Once the build is complete you should receive a message looking similar to this:
@@ -92,9 +105,6 @@ Once the build is complete you should receive a message looking similar to this:
**********************************
```
-Your native binaries have now been built, any subsequent builds that does not have changes to the
-native code can be done in Android Studio or using gradle.
-
# Build options and configuration
For configuring signing or options to your build continue with the general [build instructions](../BuildInstructions.md).
diff --git a/android/docs/DebugInstructions.md b/android/docs/DebugInstructions.md
index e4c9100e0e..9faa5237b2 100644
--- a/android/docs/DebugInstructions.md
+++ b/android/docs/DebugInstructions.md
@@ -1,15 +1,13 @@
## Debugging the native libraries in Android Studio with LLDB
-1. Make sure the native libraries have been built with debug symbols. If using the `build-apk.sh`
- script, run `SKIP_STRIPPING=yes ../build-apk.sh --dev-build`.
-2. In Android Studio, go to `Run -> Edit configurations...`
-3. Make sure the `app` configuration is selected.
-4. In the `Debugger` tab, select `Dual (Java + Native)`
-5. Start debugging the app as usual from Android Studio. The app should now stop on a SIGURG signal.
-6. Select the `LLDB` tab in the debugger. Now you can set breakpoints etc, e.g.
+1. In Android Studio, go to `Run -> Edit configurations...`
+2. Make sure the `app` configuration is selected.
+3. In the `Debugger` tab, select `Dual (Java + Native)`
+4. Start debugging the app as usual from Android Studio. The app should now stop on a SIGURG signal.
+5. Select the `LLDB` tab in the debugger. Now you can set breakpoints etc, e.g.
`breakpoint set -n open_tun`
-7. Before continuing run `pro hand -p true -s false SIGURG`
-8. Click `Resume Program` and the app will resume until the breakpoint is hit.
+6. Before continuing run `pro hand -p true -s false SIGURG`
+7. Click `Resume Program` and the app will resume until the breakpoint is hit.
NOTE: When running LLDB, Android Studio can sometimes get into a state where it will try to
connect to the debugger when running the app normally, which blocks the app from starting.
diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml
index 3428c8a8b9..bab6a4fd49 100644
--- a/android/gradle/libs.versions.toml
+++ b/android/gradle/libs.versions.toml
@@ -54,6 +54,9 @@ kotlinx-serialization = "2.1.0"
protobuf-gradle-plugin = "0.9.4"
protobuf = "4.29.2"
+# Rust Android Gradle
+rust-android-gradle = "0.9.5"
+
# Misc
commonsvalidator = "1.9.0"
dependency-check = "10.0.4"
@@ -186,6 +189,9 @@ protobuf-protoc = { id = "com.google.protobuf:protoc", version.ref = "protobuf"
grpc-protoc-gen-grpc-java = { id = "io.grpc:protoc-gen-grpc-java", version.ref = "grpc" }
grpc-protoc-gen-grpc-kotlin = { id = "io.grpc:protoc-gen-grpc-kotlin", version.ref = "grpc-kotlin-jar" }
+# Rust Android Gradle
+rust-android-gradle = { id = "org.mozilla.rust-android-gradle.rust-android", version.ref = "rust-android-gradle" }
+
# Misc
dependency-check = { id = "org.owasp.dependencycheck", version.ref = "dependency-check" }
dependency-versions = { id = "com.github.ben-manes.versions", version.ref = "dependency-versions" }
diff --git a/android/scripts/update-lockfile.sh b/android/scripts/update-lockfile.sh
index e400caed72..0c20ae31c3 100755
--- a/android/scripts/update-lockfile.sh
+++ b/android/scripts/update-lockfile.sh
@@ -20,8 +20,8 @@ GRADLE_TASKS=(
"lint"
)
EXCLUDED_GRADLE_TASKS=(
- "-xensureRelayListExist"
- "-xensureJniDirectoryExist"
+ "-xgenerateRelayList"
+ "-xcargoBuild"
)
export GRADLE_OPTS
diff --git a/building/android-container-image.txt b/building/android-container-image.txt
index 0f1f220ce4..973dbf7a5c 100644
--- a/building/android-container-image.txt
+++ b/building/android-container-image.txt
@@ -1 +1 @@
-ghcr.io/mullvad/mullvadvpn-app-build-android:7b6bc0f44
+ghcr.io/mullvad/mullvadvpn-app-build-android:7b6bc0f44 \ No newline at end of file
diff --git a/building/containerized-build.sh b/building/containerized-build.sh
index 86b0148a72..16e09ea8f2 100755
--- a/building/containerized-build.sh
+++ b/building/containerized-build.sh
@@ -18,7 +18,7 @@ case $platform in
shift 1
;;
android)
- build_command=("./build-apk.sh")
+ build_command=("./android/build.sh")
shift 1
;;
*)