From d5ea7488dc78b9a87e384289308b3409f8f01a33 Mon Sep 17 00:00:00 2001 From: Ondra-zik-SL <153621572+Ondra-Zik-SL@users.noreply.github.com> Date: Tue, 13 Jan 2026 14:56:11 +0100 Subject: [PATCH] feat(nix): centralize Android development for nix flake/shell --- .nix/android.nix | 81 ++++++++++++++++ flake.nix | 191 +++++++++++++++++++++++-------------- shell.nix | 24 ++++- suite-native/app/README.md | 14 +++ 4 files changed, 233 insertions(+), 77 deletions(-) create mode 100644 .nix/android.nix diff --git a/.nix/android.nix b/.nix/android.nix new file mode 100644 index 0000000000..b3749ff5b9 --- /dev/null +++ b/.nix/android.nix @@ -0,0 +1,81 @@ +{ pkgs }: + +let + androidComposition = pkgs.androidenv.composeAndroidPackages { + platformVersions = [ "31" "35" "36" ]; + buildToolsVersions = [ "31.0.0" "35.0.0" "36.0.0" ]; + includeEmulator = true; + includeSystemImages = true; + systemImageTypes = [ "google_apis" ]; + abiVersions = [ "x86_64" ]; + includeNDK = true; + ndkVersions = [ "27.1.12297006" "27.0.12077973" ]; + cmakeVersions = [ "3.22.1" ]; + }; +in +rec { + androidSdk = androidComposition.androidsdk; + jdk = pkgs.jdk17; + extraPackages = [ pkgs.nix-ld pkgs.aapt ]; + + nixLdHook = '' + export NIX_LD=$(nix eval --raw nixpkgs#stdenv.cc.bintools.dynamicLinker) + export NIX_LD_LIBRARY_PATH="${pkgs.lib.makeLibraryPath [ + pkgs.stdenv.cc.cc + pkgs.gcc.cc.lib + pkgs.glibc + pkgs.zlib + pkgs.icu + pkgs.openssl + pkgs.libcxx + pkgs.libxcb + pkgs.xorg.libX11 + ]}" + ''; + + shellHook = '' + # Java & Android SDK setup for React Native / Expo Android + export JAVA_HOME="${pkgs.jdk17}" + export PATH="$JAVA_HOME/bin:$PATH" + + # Set up composite Android SDK with required components + export ANDROID_SDK_ROOT="$HOME/.android/nix-sdk" + export ANDROID_HOME="$ANDROID_SDK_ROOT" + mkdir -p "$ANDROID_HOME" + + # Link SDK components from Nix store + ln -sfn "${androidComposition.androidsdk}/libexec/android-sdk/emulator" "$ANDROID_HOME/emulator" + ln -sfn "${androidComposition.androidsdk}/libexec/android-sdk/system-images" "$ANDROID_HOME/system-images" + ln -sfn "${androidComposition.androidsdk}/libexec/android-sdk/platform-tools" "$ANDROID_HOME/platform-tools" + ln -sfn "${androidComposition.androidsdk}/libexec/android-sdk/cmdline-tools" "$ANDROID_HOME/cmdline-tools" + ln -sfn "${androidComposition.androidsdk}/libexec/android-sdk/build-tools" "$ANDROID_HOME/build-tools" + ln -sfn "${androidComposition.androidsdk}/libexec/android-sdk/platforms" "$ANDROID_HOME/platforms" + ln -sfn "${androidComposition.androidsdk}/libexec/android-sdk/ndk" "$ANDROID_HOME/ndk" + ln -sfn "${androidComposition.androidsdk}/libexec/android-sdk/cmake" "$ANDROID_HOME/cmake" + ln -sfn "${androidComposition.androidsdk}/libexec/android-sdk/licenses" "$ANDROID_HOME/licenses" + + # Add Android tools to PATH + export PATH="${androidComposition.androidsdk}/bin:$PATH" + export PATH="$ANDROID_HOME/platform-tools:$PATH" + + # Using the nixpkgs aapt2 to resolve an issue with dynamically linked executables + export GRADLE_OPTS="-Dorg.gradle.project.android.aapt2FromMavenOverride=${pkgs.aapt}/bin/aapt2" + + # Setup Android emulator device if it doesn't exist + if [ ! -d "$HOME/.android/avd/Pixel_3a_API_31.avd" ]; then + avdmanager create avd -n Pixel_3a_API_31 -d pixel --package "system-images;android-31;google_apis;x86_64" + + # enable GPU acceleration, this option is not available in avdmanager + sed -i \ + -e 's/^hw\.gpu\.enabled=no$/hw.gpu.enabled=yes/' \ + -e 's/^hw\.gpu\.mode=auto$/hw.gpu.mode=host/' \ + $HOME/.android/avd/Pixel_3a_API_31.avd/config.ini + + echo "✓ Created Android emulator device: Pixel_3a_API_31" + fi + + echo "- Java $(java -version 2>&1 | head -n1)" + command -v adb >/dev/null 2>&1 && echo "- adb $(adb version | head -n1)" || echo "- adb not found (install SDK packages)" + command -v emulator >/dev/null 2>&1 && echo "- emulator $(emulator -version | head -n1)" || echo "- emulator not found" + ''; +} diff --git a/flake.nix b/flake.nix index 990757aae1..e574430c4d 100644 --- a/flake.nix +++ b/flake.nix @@ -2,22 +2,33 @@ description = "Trezor Suite development environment"; inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; flake-utils.url = "github:numtide/flake-utils"; playwright-web-flake.url = "github:pietdevries94/playwright-web-flake/1.57.0"; - old-gcc-nixpkgs.url = "github:NixOS/nixpkgs/a78ed5cbdd5427c30ca02a47ce6cccc9b7d17de4"; # For GCC 10.2.0 + old-gcc-nixpkgs.url = "github:NixOS/nixpkgs/a78ed5cbdd5427c30ca02a47ce6cccc9b7d17de4"; # For GCC 10.2.0 }; - outputs = { self, nixpkgs, flake-utils, playwright-web-flake, old-gcc-nixpkgs, ... }: - flake-utils.lib.eachDefaultSystem (system: + outputs = + { + self, + nixpkgs, + flake-utils, + playwright-web-flake, + old-gcc-nixpkgs, + ... + }: + flake-utils.lib.eachDefaultSystem ( + system: let overlay = final: prev: { # Overlay playwright packages with chromium from nixpkgs unstable - playwright-driver = (playwright-web-flake.packages.${system}.playwright-driver.override { - chromium = prev.chromium; - }); + playwright-driver = ( + playwright-web-flake.packages.${system}.playwright-driver.override { + chromium = prev.chromium; + } + ); playwright-test = playwright-web-flake.packages.${system}.playwright-test; - + # Override GCC with older version gccPkgs = import old-gcc-nixpkgs { system = prev.system; }; }; @@ -26,74 +37,110 @@ inherit system; overlays = [ overlay ]; config.allowUnfree = true; + config.android_sdk.accept_license = true; }; - in { - devShells.default = pkgs.mkShell { - buildInputs = [ - pkgs.bash - pkgs.git - pkgs.git-lfs - pkgs.gnupg - pkgs.mdbook - pkgs.xorg.xhost - pkgs.docker - pkgs.docker-compose - pkgs.nodejs_24 - (pkgs.yarn.override { nodejs = null; }) - pkgs.python3 - pkgs.python3Packages.pip - pkgs.jre - pkgs.electron_39 - pkgs.pkg-config - pkgs.pixman # build dependencies for node-canvas - pkgs.cairo # build dependencies for node-canvas - pkgs.giflib # build dependencies for node-canvas - pkgs.libjpeg # build dependencies for node-canvas - pkgs.libpng # build dependencies for node-canvas - pkgs.librsvg # build dependencies for node-canvas - pkgs.pango # build dependencies for node-canvas - pkgs.shellcheck - pkgs.playwright-test # From playwright-web-flake - pkgs.vips - ] ++ pkgs.lib.optionals pkgs.stdenv.isLinux [ - pkgs.nsis - pkgs.p7zip - pkgs.openjpeg - pkgs.osslsigncode - pkgs.squashfsTools - pkgs.gccPkgs.gcc # Older GCC - pkgs.udev # used by node_module: usb - ] ++ pkgs.lib.optionals pkgs.stdenv.isDarwin (with pkgs.darwin.apple_sdk.frameworks; [ + androidEnv = import ./.nix/android.nix { inherit pkgs; }; + + commonBuildInputs = [ + pkgs.bash + pkgs.git + pkgs.git-lfs + pkgs.gnupg + pkgs.mdbook + pkgs.xorg.xhost + pkgs.docker + pkgs.docker-compose + pkgs.nodejs_24 + (pkgs.yarn.override { nodejs = null; }) + pkgs.python3 + pkgs.python3Packages.pip + pkgs.electron_39 + pkgs.pkg-config + pkgs.pixman # build dependencies for node-canvas + pkgs.cairo # build dependencies for node-canvas + pkgs.giflib # build dependencies for node-canvas + pkgs.libjpeg # build dependencies for node-canvas + pkgs.libpng # build dependencies for node-canvas + pkgs.librsvg # build dependencies for node-canvas + pkgs.pango # build dependencies for node-canvas + pkgs.shellcheck + pkgs.playwright-test # From playwright-web-flake + pkgs.vips + ] + ++ pkgs.lib.optionals pkgs.stdenv.isLinux [ + pkgs.nsis + pkgs.p7zip + pkgs.openjpeg + pkgs.osslsigncode + pkgs.squashfsTools + pkgs.gccPkgs.gcc # Older GCC + pkgs.udev # used by node_module: usb + ] + ++ pkgs.lib.optionals pkgs.stdenv.isDarwin ( + with pkgs.darwin.apple_sdk.frameworks; + [ Cocoa CoreServices - ]); + ] + ); - NIX_PATCHELF_LIBRARY_PATH = "${pkgs.openssl.out}/lib:${pkgs.zlib}/lib:${pkgs.gcc.cc.lib}/lib"; - NIX_CC = "${pkgs.gcc}"; + commonShellHook = '' + export NODE_OPTIONS=--max_old_space_size=4096 + export CURDIR="$(pwd)" + export PATH="$PATH:$CURDIR/node_modules/.bin" + export ELECTRON_BUILDER_CACHE="$CURDIR/.cache/electron-builder" + export ELECTRON_DISABLE_SANDBOX=1 + export PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 + export PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS=true + export PLAYWRIGHT_BROWSERS_PATH="${pkgs.playwright-driver.browsers}" + '' + + pkgs.lib.optionalString pkgs.stdenv.isDarwin '' + export ELECTRON_OVERRIDE_DIST_PATH="${pkgs.electron_39}/Applications/" + '' + + pkgs.lib.optionalString pkgs.stdenv.isLinux '' + export ELECTRON_OVERRIDE_DIST_PATH="${pkgs.electron_39}/bin/" + export npm_config_build_from_source=true + ''; - shellHook = '' - export NODE_OPTIONS=--max_old_space_size=4096 - export CURDIR="$(pwd)" - export PATH="$PATH:$CURDIR/node_modules/.bin" - export ELECTRON_BUILDER_CACHE="$CURDIR/.cache/electron-builder" - export ELECTRON_DISABLE_SANDBOX=1 - export PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 - export PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS=true - export PLAYWRIGHT_BROWSERS_PATH="${pkgs.playwright-driver.browsers}" - - echo "welcome to the Trezor Suite development environment" - echo "- Node.js $(node --version)" - echo "- npm $(npm --version)" - echo "- Yarn $(yarn --version)" - echo "- Playwright $(playwright --version)" - - '' + pkgs.lib.optionalString pkgs.stdenv.isDarwin '' - export ELECTRON_OVERRIDE_DIST_PATH="${pkgs.electron_39}/Applications/" - '' + pkgs.lib.optionalString pkgs.stdenv.isLinux '' - export ELECTRON_OVERRIDE_DIST_PATH="${pkgs.electron_39}/bin/" - export npm_config_build_from_source=true - ''; - }; - }); + welcomeMessage = '' + echo "welcome to the Trezor Suite development environment" + echo "- Node.js $(node --version)" + echo "- npm $(npm --version)" + echo "- Yarn $(yarn --version)" + echo "- Playwright $(playwright --version)" + ''; + + in + { + devShells = + let + androidShell = pkgs.mkShell { + buildInputs = commonBuildInputs ++ [ + androidEnv.jdk + androidEnv.androidSdk + ] ++ androidEnv.extraPackages; + + NIX_PATCHELF_LIBRARY_PATH = "${pkgs.openssl.out}/lib:${pkgs.zlib}/lib:${pkgs.gcc.cc.lib}/lib"; + NIX_CC = "${pkgs.gcc}"; + + shellHook = commonShellHook + + androidEnv.nixLdHook + + androidEnv.shellHook + + welcomeMessage; + }; + in + { + default = pkgs.mkShell { + buildInputs = commonBuildInputs; + NIX_PATCHELF_LIBRARY_PATH = "${pkgs.openssl.out}/lib:${pkgs.zlib}/lib:${pkgs.gcc.cc.lib}/lib"; + NIX_CC = "${pkgs.gcc}"; + shellHook = commonShellHook + welcomeMessage; + }; + + android = androidShell; + use_android = androidShell; + }; + } + ); } diff --git a/shell.nix b/shell.nix index 1552cd73c5..e20b85adaf 100644 --- a/shell.nix +++ b/shell.nix @@ -1,10 +1,17 @@ # pinned to nixos-unstable on commit https://github.com/NixOS/nixpkgs/commit/5ae3b07d8d6527c42f17c876e404993199144b6a # we need to use nixos-unstable to be able to use nodejs_24, once there is a stable release with it we can change. -with import +let + pkgs = import (builtins.fetchTarball { url = "https://github.com/NixOS/nixpkgs/archive/5ae3b07d8d6527c42f17c876e404993199144b6a.tar.gz"; sha256 = "1zb5ca8jqavb19j7g06a41jg6bvpr20b9lihvham6qywhgaqprz9"; - }) { system = builtins.currentSystem; }; + }) { + system = builtins.currentSystem; + config.allowUnfree = true; + config.android_sdk.accept_license = true; + }; +in +with pkgs; let # unstable packages @@ -16,6 +23,12 @@ let url = "https://github.com/NixOS/nixpkgs/archive/a78ed5cbdd5427c30ca02a47ce6cccc9b7d17de4.tar.gz"; sha256 = "0l5b1libi46sc3ly7a5vj04098f63aj5jynxpz44sb396nncnivl"; }) {}; + + useAndroid = builtins.getEnv "USE_ANDROID" == "1"; + androidEnv = if useAndroid then import ./.nix/android.nix { inherit pkgs; } else {}; + extraBuildInputs = pkgs.lib.concatLists [ + (if useAndroid then [ androidEnv.jdk androidEnv.androidSdk ] ++ androidEnv.extraPackages else [jre]) + ]; in stdenvNoCC.mkDerivation { name = "trezor-suite-dev"; @@ -34,14 +47,14 @@ in }) python3 python3Packages.pip - jre p7zip electron pkg-config pixman cairo giflib libjpeg libpng librsvg pango # build dependencies for node-canvas shellcheck vips - ] ++ lib.optionals stdenv.isLinux [ + ] ++ extraBuildInputs + ++ lib.optionals stdenv.isLinux [ nsis openjpeg osslsigncode p7zip squashfsTools gccPkgs.gcc # binaries used by node_module: electron-builder udev # used by node_module: usb ] ++ lib.optionals stdenv.isDarwin (with darwin.apple_sdk.frameworks; [ @@ -58,7 +71,8 @@ in export CURDIR="$(pwd)" export PATH="$PATH:$CURDIR/node_modules/.bin" export ELECTRON_BUILDER_CACHE="$CURDIR/.cache/electron-builder" - '' + lib.optionalString stdenv.isDarwin '' + '' + lib.optionalString useAndroid androidEnv.shellHook + + lib.optionalString stdenv.isDarwin '' export ELECTRON_OVERRIDE_DIST_PATH="${electron}/Applications/" '' + lib.optionalString stdenv.isLinux '' export ELECTRON_OVERRIDE_DIST_PATH="${electron}/bin/" diff --git a/suite-native/app/README.md b/suite-native/app/README.md index f1de11ecf9..8c6dc62ade 100644 --- a/suite-native/app/README.md +++ b/suite-native/app/README.md @@ -11,6 +11,20 @@ Generally it's recommended to follow official [React Native environment setup](h 2. [iOS Guide](https://reactnative.dev/docs/set-up-your-environment?os=macos&platform=ios) - Make sure you have the latest version of the Xcode command line tools installed: `xcode-select --install` +### NixOS prerequisites + +shell + +``` +USE_ANDROID=1 nix-shell +``` + +flakes + +``` +nix develop .#use_android +``` + ## Before you run the app 1. Run `yarn native:prebuild:clean` to generate `ios/` and `android/` directories.