Building expo react native android app on nixos

Hi everyone,

I am trying to build a react native android application using the expo build tool

I am able to upload my app to my android device using the Expo go app, But I cannot build the apk outright as gradle attempts to write some files to a location in the nix store (which it can’t since the nix store is readonly)

here is my repo where I am trying to accomplish this

to reproduce the issue you can run the following commands after connecting an android device to your machine

nix develop
npm ci
npm run android

and here is the console output of running these commands

 npm run android

> nix-expo-attempt@1.0.0 android
> expo run:android

› Building app...
Configuration on demand is an incubating feature.
> Task :gradle-plugin:compileKotlin UP-TO-DATE
> Task :gradle-plugin:compileJava NO-SOURCE
> Task :gradle-plugin:pluginDescriptors UP-TO-DATE
> Task :gradle-plugin:processResources UP-TO-DATE
> Task :gradle-plugin:classes UP-TO-DATE
> Task :gradle-plugin:jar UP-TO-DATE
> Task :gradle-plugin:inspectClassesForKotlinIC UP-TO-DATE
Checking the license for package Android SDK Build-Tools 30.0.3 in /nix/store/vhpffskv3h1skfaa4vx2lak07fypjrpz-androidsdk/libexec/android-sdk/licenses
License for package Android SDK Build-Tools 30.0.3 accepted.
Preparing "Install Android SDK Build-Tools 30.0.3 (revision: 30.0.3)".
Warning: Failed to read or create install properties file.
Checking the license for package Android SDK Platform 33 in /nix/store/vhpffskv3h1skfaa4vx2lak07fypjrpz-androidsdk/libexec/android-sdk/licenses
License for package Android SDK Platform 33 accepted.
Preparing "Install Android SDK Platform 33 (revision: 3)".
Warning: Failed to read or create install properties file.

FAILURE: Build failed with an exception.

* What went wrong:
Could not determine the dependencies of task ':app:compileDebugJavaWithJavac'.
> Could not determine the dependencies of null.
   > Failed to install the following SDK components:
         platforms;android-33 Android SDK Platform 33
         build-tools;30.0.3 Android SDK Build-Tools 30.0.3
     The SDK directory is not writable (/nix/store/vhpffskv3h1skfaa4vx2lak07fypjrpz-androidsdk/libexec/android-sdk)


* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 3s
5 actionable tasks: 5 up-to-date
Error: /home/jenkin/workspace/nix-expo-attempt/android/gradlew exited with non-zero code: 1
Error: /home/jenkin/workspace/nix-expo-attempt/android/gradlew exited with non-zero code: 1
    at ChildProcess.completionListener (/home/jenkin/workspace/nix-expo-attempt/node_modules/@expo/spawn-async/build/spawnAsync.js:52:23)
    at Object.onceWrapper (node:events:629:26)
    at ChildProcess.emit (node:events:514:28)
    at maybeClose (node:internal/child_process:1105:16)
    at ChildProcess._handle.onexit (node:internal/child_process:305:5)
    ...
    at Object.spawnAsync [as default] (/home/jenkin/workspace/nix-expo-attempt/node_modules/@expo/spawn-async/build/spawnAsync.js:17:21)
    at spawnGradleAsync (/home/jenkin/workspace/nix-expo-attempt/node_modules/@expo/cli/build/src/start/platforms/android/gradle.js:72:46)
    at Object.assembleAsync (/home/jenkin/workspace/nix-expo-attempt/node_modules/@expo/cli/build/src/start/platforms/android/gradle.js:52:18)
    at runAndroidAsync (/home/jenkin/workspace/nix-expo-attempt/node_modules/@expo/cli/build/src/run/android/runAndroidAsync.js:36:24)

any help solving this issue would be much appreciated

1 Like

Welll it seems Gradle is trying to download the and install the Android SDK and failing to do so, since the SDK is located on the read-only Nix store.

I guess there should be a way to tell Gradle not to install the SDK, and where to find it.

Hello there,

First, I would like to thank you for pointing me in the right direction. I was trying to figure out how to build a react native app in NixOS and didn’t even think about using flakes.

I copied your flake and ran into the same problem, but I was able to solve it by defining my own android composition with the required versions.

Here is the flake that worked for me

{
  description = "ecommerce";
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    android-nixpkgs.url = "github:tadfisher/android-nixpkgs";
  };

  outputs = { self, nixpkgs, flake-utils, android-nixpkgs }: flake-utils.lib.eachDefaultSystem (system:
    let
      pkgs = import nixpkgs {
        inherit system;
        config = {
          android_sdk.accept_license = true;
          allowUnfree = true;
        };
      };

      pinnedJDK = pkgs.jdk17;
      buildToolsVersion = "34.0.0";
      ndkVersion = "25.1.8937393";
      androidComposition = pkgs.androidenv.composeAndroidPackages {
        cmdLineToolsVersion = "8.0";
        toolsVersion = "26.1.1";
        platformToolsVersion = "34.0.4";
        buildToolsVersions = [ buildToolsVersion "33.0.1" ];
        includeEmulator = false;
        emulatorVersion = "30.3.4";
        platformVersions = [ "34" ];
        includeSources = false;
        includeSystemImages = false;
        systemImageTypes = [ "google_apis_playstore" ];
        abiVersions = [ "armeabi-v7a" "arm64-v8a" ];
        cmakeVersions = [ "3.10.2" "3.22.1" ];
        includeNDK = true;
        ndkVersions = [ ndkVersion ];
        useGoogleAPIs = false;
        useGoogleTVAddOns = false;
        includeExtras = [
          "extras;google;gcm"
        ];
      };
      sdk = androidComposition.androidsdk;
    in
    {
      devShell = pkgs.mkShell rec {
        buildInputs = with pkgs; [
          # Android
          pinnedJDK
          sdk
          pkg-config
        ];

        JAVA_HOME = pinnedJDK;
        ANDROID_SDK_ROOT = "${androidComposition.androidsdk}/libexec/android-sdk";
        ANDROID_NDK_ROOT = "${ANDROID_SDK_ROOT}/ndk-bundle";

        GRADLE_OPTS = "-Dorg.gradle.project.android.aapt2FromMavenOverride=${ANDROID_SDK_ROOT}/build-tools/${buildToolsVersion}/aapt2";
      };
    });
}

This flake got me the closest to working from anything else I’ve read online, but now I’m encountering this error trying to build my react-native app with expo:

      /nix/store/psvyy0kbz423j2apxlzrkwn2zj6iw347-androidsdk/libexec/android-sdk/ndk/26.1.10909125/toolchains/llvm/prebuilt/linux-x86_64/bin/ld.lld: error while loading shared libraries: libxml2.so.2: cannot open shared object file: No such file or directory
      clang: error: unable to execute command: No such file or directory
      clang: error: linker command failed due to signal (use -v to see invocation)
      ninja: build stopped: subcommand failed.

I’ve tried explicitly adding libxml2.dev to the buildInputs, and setting LD_LIBRARY_PATH = "${pkgs.libxml2.dev}/include" but those don’t work.

Running pkg-config --cflags libxml-2.0 outputs -I/nix/store/37979sqc7yw9ps0c4xl9jjkhq0w1hw8b-libxml2-2.12.7-dev/include/libxml2 from my shell, so I’m not sure what’s going wrong.

Any ideas on how to get around this?

I got past this by adding libxml2 to the LD_LIBRARY_PATH.

shellHook = ''
  export LD_LIBRARY_PATH="${pkgs.libxml2.out}/lib:$LD_LIBRARY_PATH"
'';

Also, for reference, I have a working set up using this android composition:

        androidBuildToolsVersion = "34.0.0";
        androidNdkVersion="26.1.10909125";
        androidComposition = pkgs.androidenv.composeAndroidPackages {
          buildToolsVersions = [ androidBuildToolsVersion];
          platformVersions = [ "34" ];
          cmakeVersions = [ "3.10.2" "3.22.1" ];
          includeNDK = true;
          ndkVersions = [ androidNdkVersion ];
        };
        androidSdk = androidComposition.androidsdk;

After hours of trying I’ve finally managed to successfully build locally with expo on NixOS through distrobox
I used the Arch image (distrobox-create --name arch --image archlinux:latest), ran sudo pacman -Syu and didn’t do much else apart from the obvious npx expo run:android
I think the build ran successfully on the first try!