diff options
| author | Albin <albin@mullvad.net> | 2025-07-15 15:38:33 +0200 |
|---|---|---|
| committer | Albin <albin@mullvad.net> | 2025-07-15 15:38:33 +0200 |
| commit | 592636ad50e93c1990d7b08321378ea19a4c33e4 (patch) | |
| tree | 4314baf1bff9867ab1eb605f8e24f8bc70a25d38 /android | |
| parent | a3ec4507f0e0dcd35e1940e897eb1d3a51151940 (diff) | |
| parent | 3771dff76a96665db0f93c0ec8af5e944ec429ec (diff) | |
| download | mullvadvpn-592636ad50e93c1990d7b08321378ea19a4c33e4.tar.xz mullvadvpn-592636ad50e93c1990d7b08321378ea19a4c33e4.zip | |
Merge branch 'add-initial-android-devshell'
Diffstat (limited to 'android')
| -rw-r--r-- | android/BuildInstructions.md | 16 | ||||
| -rw-r--r-- | android/flake.lock | 193 | ||||
| -rw-r--r-- | android/flake.nix | 104 | ||||
| -rw-r--r-- | android/lib/daemon-grpc/build.gradle.kts | 17 | ||||
| -rw-r--r-- | android/nix/env-vars.nix | 84 |
5 files changed, 412 insertions, 2 deletions
diff --git a/android/BuildInstructions.md b/android/BuildInstructions.md index b287342fd4..a58a993b49 100644 --- a/android/BuildInstructions.md +++ b/android/BuildInstructions.md @@ -177,6 +177,22 @@ Run the following command to build a debug build: ../android/build.sh --app-bundle ``` +## Build using nix devshell +1. Install the nix package manager by following the [official instructions](https://nixos.org/download/). +2. Enable the experimental `nix-command` and `flake` features by following [these instructions](https://nixos.wiki/wiki/flakes). +3. Launch a devshell (in `<repository>/android`) by running: + ```bash + nix develop + ``` +4. Build the app as usual by running for example: + ```bash + ./build.sh --dev-build + ``` + or + ```bash + ./gradlew assembleOssProdDebug + ``` + ## Configure signing key 1. Create a directory to store the signing key, keystore and its configuration: ``` diff --git a/android/flake.lock b/android/flake.lock new file mode 100644 index 0000000000..a9ee199ccc --- /dev/null +++ b/android/flake.lock @@ -0,0 +1,193 @@ +{ + "nodes": { + "android-nixpkgs": { + "inputs": { + "devshell": "devshell", + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1752524595, + "narHash": "sha256-BQw78e4yNYtzn0+CIvNCyWuh6Q1FHY8hebn+jv4kC6E=", + "owner": "tadfisher", + "repo": "android-nixpkgs", + "rev": "5b4a9a71371280b3d95263bf0fc8dcffedec0df8", + "type": "github" + }, + "original": { + "owner": "tadfisher", + "repo": "android-nixpkgs", + "type": "github" + } + }, + "devshell": { + "inputs": { + "nixpkgs": [ + "android-nixpkgs", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1741473158, + "narHash": "sha256-kWNaq6wQUbUMlPgw8Y+9/9wP0F8SHkjy24/mN3UAppg=", + "owner": "numtide", + "repo": "devshell", + "rev": "7c9e793ebe66bcba8292989a68c0419b737a22a0", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, + "devshell_2": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1741473158, + "narHash": "sha256-kWNaq6wQUbUMlPgw8Y+9/9wP0F8SHkjy24/mN3UAppg=", + "owner": "numtide", + "repo": "devshell", + "rev": "7c9e793ebe66bcba8292989a68c0419b737a22a0", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1722073938, + "narHash": "sha256-OpX0StkL8vpXyWOGUD6G+MA26wAXK6SpT94kLJXo6B4=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e36e9f57337d0ff0cf77aceb58af4c805472bfae", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1752480373, + "narHash": "sha256-JHQbm+OcGp32wAsXTE/FLYGNpb+4GLi5oTvCxwSoBOA=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "62e0f05ede1da0d54515d4ea8ce9c733f12d9f08", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-unstable", + "type": "indirect" + } + }, + "root": { + "inputs": { + "android-nixpkgs": "android-nixpkgs", + "devshell": "devshell_2", + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_2", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1752547600, + "narHash": "sha256-0vUE42ji4mcCvQO8CI0Oy8LmC6u2G4qpYldZbZ26MLc=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "9127ca1f5a785b23a2fc1c74551a27d3e8b9a28b", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/android/flake.nix b/android/flake.nix new file mode 100644 index 0000000000..0d75da2038 --- /dev/null +++ b/android/flake.nix @@ -0,0 +1,104 @@ +{ + description = "Mullvad Android app build flake"; + + inputs = { + # Unstable is currently needed for protoc-gen-grpc-java. + # We should switch to a stable channel once it's avaiable on those. + nixpkgs.url = "nixpkgs/nixos-unstable"; + devshell.url = "github:numtide/devshell"; + flake-utils.url = "github:numtide/flake-utils"; + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + android-nixpkgs = { + url = "github:tadfisher/android-nixpkgs"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = { + self, + nixpkgs, + android-nixpkgs, + rust-overlay, + flake-utils, + devshell, + }: + flake-utils.lib.eachDefaultSystem (system: let + pkgs = import nixpkgs { + inherit system; + overlays = [ + (import rust-overlay) + devshell.overlays.default + ]; + }; + + rust-toolchain = (pkgs.buildPackages.rust-bin.fromRustupToolchainFile + ../rust-toolchain.toml).override { + extensions = ["rust-analyzer"]; + targets = [ + "aarch64-linux-android" + "armv7-linux-androideabi" + "x86_64-linux-android" + "i686-linux-android" + ]; + }; + + patchedGo_1_21_3 = + (import (fetchTarball { + url = "https://github.com/NixOS/nixpkgs/archive/b392079f5fd051926a834c878d27ceec4f139dce.tar.gz"; + sha256 = "16dkk98fs9pw2amz0vpjsc7ks85cw3hc5rlpbp27llq6x7lwpjaz"; + }) {inherit system;}).go_1_21.overrideAttrs (oldAttrs: { + patches = (oldAttrs.patches or []) ++ [./docker/goruntime-boottime-over-monotonic.diff]; + }); + + versions = + (builtins.fromTOML ( + builtins.concatStringsSep "\n" ( + builtins.filter (line: !(builtins.match "^[[:space:]]*#" line != null)) + (nixpkgs.lib.splitString "\n" (builtins.readFile ./gradle/libs.versions.toml)) + ) + )).versions; + + compileSdkVersion = versions."compile-sdk"; + buildToolsVersion = versions."build-tools"; + minSdkVersion = versions."min-sdk"; + ndkVersion = versions.ndk; + + android-sdk = android-nixpkgs.sdk.${system} (sdkPkgs: + with sdkPkgs; [ + (builtins.getAttr "platforms-android-${compileSdkVersion}" sdkPkgs) + (builtins.getAttr "build-tools-${builtins.replaceStrings ["."] ["-"] buildToolsVersion}" sdkPkgs) + (builtins.getAttr "ndk-${builtins.replaceStrings ["."] ["-"] ndkVersion}" sdkPkgs) + cmdline-tools-latest + platform-tools + ]); + in { + overlay = final: prev: { + inherit (self.packages.${system}) android-sdk; + }; + + packages = { + inherit android-sdk; + }; + + devShells.default = pkgs.devshell.mkShell { + name = "mullvad-android-devshell"; + packages = [ + android-sdk + rust-toolchain + patchedGo_1_21_3 + pkgs.protoc-gen-grpc-java + pkgs.gcc + pkgs.gnumake + pkgs.protobuf + pkgs.jdk17 + pkgs.python3Full + ]; + env = import ./nix/env-vars.nix { + inherit pkgs android-sdk buildToolsVersion ndkVersion minSdkVersion; + }; + }; + }); +} diff --git a/android/lib/daemon-grpc/build.gradle.kts b/android/lib/daemon-grpc/build.gradle.kts index d4a6d0e7a2..cadd126830 100644 --- a/android/lib/daemon-grpc/build.gradle.kts +++ b/android/lib/daemon-grpc/build.gradle.kts @@ -44,8 +44,21 @@ android { protobuf { protoc { artifact = libs.plugins.protobuf.protoc.get().toString() } plugins { - create("java") { artifact = libs.plugins.grpc.protoc.gen.grpc.java.get().toString() } - create("grpc") { artifact = libs.plugins.grpc.protoc.gen.grpc.java.get().toString() } + val grpcPluginPath = System.getenv("PROTOC_GEN_GRPC_JAVA_PLUGIN") + create("java") { + if (grpcPluginPath != null) { + path = grpcPluginPath + } else { + artifact = libs.plugins.grpc.protoc.gen.grpc.java.get().toString() + } + } + create("grpc") { + if (grpcPluginPath != null) { + path = grpcPluginPath + } else { + artifact = libs.plugins.grpc.protoc.gen.grpc.java.get().toString() + } + } create("grpckt") { artifact = libs.plugins.grpc.protoc.gen.grpc.kotlin.get().toString() } } generateProtoTasks { diff --git a/android/nix/env-vars.nix b/android/nix/env-vars.nix new file mode 100644 index 0000000000..e9f5d6aa62 --- /dev/null +++ b/android/nix/env-vars.nix @@ -0,0 +1,84 @@ +{ + pkgs, + android-sdk, + buildToolsVersion, + ndkVersion, + minSdkVersion, +}: [ + { + name = "JAVA_HOME"; + value = "${pkgs.jdk17}"; + } + { + name = "PROTOC_GEN_GRPC_JAVA_PLUGIN"; + prefix = "${pkgs.protoc-gen-grpc-java}/bin/protoc-gen-grpc-java"; + } + { + name = "GRADLE_OPTS"; + value = "-Dorg.gradle.project.android.aapt2FromMavenOverride=${android-sdk}/share/android-sdk/build-tools/${buildToolsVersion}/aapt2"; + } + { + name = "ANDROID_HOME"; + value = "${android-sdk}/share/android-sdk"; + } + { + name = "ANDROID_SDK_ROOT"; + value = "${android-sdk}/share/android-sdk"; + } + { + name = "ANDROID_NDK_ROOT"; + value = "${android-sdk}/share/android-sdk/ndk/${ndkVersion}"; + } + { + name = "NDK_TOOLCHAIN_DIR"; + value = "${android-sdk}/share/android-sdk/ndk/${ndkVersion}/toolchains/llvm/prebuilt/linux-x86_64/bin"; + } + { + name = "AR_aarch64_linux_android"; + value = "$NDK_TOOLCHAIN_DIR/llvm-ar"; + } + { + name = "CC_aarch64_linux_android"; + value = "$NDK_TOOLCHAIN_DIR/aarch64-linux-android${minSdkVersion}-clang"; + } + { + name = "CARGO_TARGET_aarch64_LINUX_ANDROID_LINKER"; + value = "$NDK_TOOLCHAIN_DIR/aarch64-linux-android${minSdkVersion}-clang"; + } + { + name = "AR_armv7_linux_androideabi"; + value = "$NDK_TOOLCHAIN_DIR/llvm-ar"; + } + { + name = "CC_armv7_linux_androideabi"; + value = "$NDK_TOOLCHAIN_DIR/armv7-linux-androideabi${minSdkVersion}-clang"; + } + { + name = "CARGO_TARGET_armv7_LINUX_ANDROID_LINKER"; + value = "$NDK_TOOLCHAIN_DIR/armv7-linux-androideabi${minSdkVersion}-clang"; + } + { + name = "AR_x86_64_linux_android"; + value = "$NDK_TOOLCHAIN_DIR/llvm-ar"; + } + { + name = "CC_x86_64_linux_android"; + value = "$NDK_TOOLCHAIN_DIR/x86_64-linux-android${minSdkVersion}-clang"; + } + { + name = "CARGO_TARGET_x86_64_LINUX_ANDROID_LINKER"; + value = "$NDK_TOOLCHAIN_DIR/x86_64-linux-android${minSdkVersion}-clang"; + } + { + name = "AR_i686_linux_android"; + value = "$NDK_TOOLCHAIN_DIR/llvm-ar"; + } + { + name = "CC_i686_linux_android"; + value = "$NDK_TOOLCHAIN_DIR/i686-linux-android${minSdkVersion}-clang"; + } + { + name = "CARGO_TARGET_i686_LINUX_ANDROID_LINKER"; + value = "$NDK_TOOLCHAIN_DIR/i686-linux-android${minSdkVersion}-clang"; + } +] |
