NixOS / nixpkgs

Nix Packages collection & NixOS
MIT License
18.08k stars 14.06k forks source link

Unable to build flutter app with flutter 3.19 new Gradle structure #289936

Closed hatch01 closed 2 days ago

hatch01 commented 8 months ago

Describe the bug

Now building the apk of a brand new created, flutter apps try to write in read only nix folders.

Steps To Reproduce

Steps to reproduce the behavior:

  1. Set up a flake like this : ( this one is pretty complete because my app has a lot of deps

    {
    inputs = {
    nixpkgs.url = "nixpkgs/nixpkgs-unstable";
    
    flake-parts = {
      url = "github:hercules-ci/flake-parts";
      inputs.nixpkgs-lib.follows = "nixpkgs";
    };
    };
    
    outputs = {
    self,
    nixpkgs,
    flake-parts,
    ...
    } @ inputs:
    flake-parts.lib.mkFlake {inherit inputs;} {
      systems = ["x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin"];
      perSystem = {
        pkgs,
        system,
        lib,
        ...
      }: {
        devShells.default = let
          pkgs = import nixpkgs {
            inherit system;
            config = {
              allowUnfree = true;
              android_sdk.accept_license = true;
            };
          };
          melos = pkgs.callPackage ./nix/melos { };
          buildToolsVersionForAapt2 = "34.0.0-rc4";
          androidComposition = pkgs.androidenv.composeAndroidPackages {
            # Installing both version for aapt2 and version that flutter wants
            buildToolsVersions = [buildToolsVersionForAapt2 "30.0.3"];
            platformVersions = ["34" "33" "31" "30"];
            abiVersions = ["armeabi-v7a" "arm64-v8a" "x86" "x86_64"];
            includeEmulator = true;
            emulatorVersion = "34.1.9";
            toolsVersion = "26.1.1";
            platformToolsVersion = "33.0.3";
            includeSources = false;
            includeSystemImages = false;
            systemImageTypes = ["google_apis_playstore"];
            # cmakeVersions = [ "3.10.2" ];
            includeNDK = true;
            # ndkVersions = [ "22.0.7026061" ];
            useGoogleAPIs = false;
            useGoogleTVAddOns = false;
            extraLicenses = [
              "android-googletv-license"
              "android-sdk-arm-dbt-license"
              "android-sdk-license"
              "android-sdk-preview-license"
              "google-gdk-license"
              "intel-android-extra-license"
              "intel-android-sysimage-license"
              "mips-android-sysimage-license"
            ];
          };
          androidSdk = androidComposition.androidsdk;
          PWD = builtins.getEnv "PWD";
        in
          pkgs.mkShell {
            CHROME_EXECUTABLE = lib.getExe pkgs.chromium;
            ANDROID_SDK_ROOT = "${androidSdk}/libexec/android-sdk";
            ANDROID_NDK_ROOT = "${androidSdk}/libexec/android-sdk/ndk-bundle";
            ANDROID_AVD_HOME = "${PWD}/.android/avd";
            ANDROID_HOME = "${androidSdk}/libexec/android-sdk";
            FLUTTER_SDK = "${pkgs.flutter}";
            GRADLE_OPTS = "-Dorg.gradle.project.android.aapt2FromMavenOverride=${androidSdk}/libexec/android-sdk/build-tools/${buildToolsVersionForAapt2}/aapt2";
            LD_LIBRARY_PATH = "${PWD}/apps/onyx/build/linux/x64/debug/bundle/lib/:${PWD}/apps/onyx/build/linux/x64/release/bundle/lib/:${PWD}/apps/onyx/build/linux/x64/profile/bundle/lib/";
            buildInputs = with pkgs; [
              chromium
              flutter
              melos
              jdk17
              androidSdk
              at-spi2-core
              clang
              dart
              dbus
              util-linux
              cmake
              ninja
              libsecret
              android-tools
              pkg-config
              gtk3
              glib
              pcre2
              pcre
              libselinux
              libsepol
              libthai
              libdatrie
              xorg.libXdmcp
              libxkbcommon
              xorg.libXtst
              libepoxy
              libgcrypt
              libgpg-error
              apksigner
              gnome.zenity
              ];
          };
        formatter = pkgs.alejandra;
      };
    };
    }
  2. run flutter create {name of project}

  3. run flutter build apk

Expected behavior

The build failed because flutter does not have the right to write in some folders

[user@system:~]$ flutter build apk

FAILURE: Build failed with an exception.

* Where:
Settings file '/home/eymeric/code_bidouille/projet/oloid/onyx/apps/test/android/settings.gradle' line: 21

* What went wrong:
Error resolving plugin [id: 'dev.flutter.flutter-plugin-loader', version: '1.0.0']
> A problem occurred configuring project ':gradle'.
   > Could not create service of type OutputFilesRepository using ExecutionGradleServices.createOutputFilesRepository().
      > Failed to create parent directory '/nix/store/83gcq64ghi2wvgrhlw8frafk23a8ndzc-flutter-wrapped-3.19.0-sdk-links/packages/flutter_tools/gradle/.gradle' when creating directory '/nix/store/83gcq64ghi2wvgrhlw8frafk23a8ndzc-flutter-wrapped-3.19.0-sdk-links/packages/flutter_tools/gradle/.gradle/buildOutputCleanup'

* 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 2s
Running Gradle task 'assembleRelease'...                            3,2s
Gradle task assembleRelease failed with exit code 1

Additional context

There were a previous similar issue fixable by modifying the build.gradle but because it changed, the previous modification from here is not applicable. (https://discourse.nixos.org/t/problem-building-flutter-app-for-android/35593/2)

Notify maintainers

Metadata

[user@system:~]$ nix-shell -p nix-info --run "nix-info -m"
- system: `"x86_64-linux"`
 - host os: `Linux 6.1.77, NixOS, 24.05 (Uakari), 24.05.20240216.5863c27`
 - multi-user?: `yes`
 - sandbox: `yes`
 - version: `nix-env (Nix) 2.18.1`
 - nixpkgs: `/nix/var/nix/profiles/per-user/root/channels/nixos`

Add a :+1: reaction to issues you find important.

nixos-discourse commented 8 months ago

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/problem-building-flutter-app-for-android/35593/3

nixos-discourse commented 8 months ago

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/flutter-development-in-nixos/39181/5

hatch01 commented 8 months ago

@FlafyDev no idea on how to fix this? (because you made the pr #289534 )

FlafyDev commented 8 months ago

Ah sorry I didn't know about this issue("notify maintainers" is empty)

I'll try to figure out how it works and hopefully find a fix..

jmarmstrong1207 commented 8 months ago

@FlafyDev For reference, this issue i believe is a duplicate of #260278 and I've been experiencing this issue too.

jmarmstrong1207 commented 8 months ago

@jtojnar @hedning @amaxine @bobby285271 @dasj19 (Not sure who to @ exactly, sorry if I @'d the wrong people!!)

This issue is also in NixOS 23.11 Stable. Should the flutter package version be reverted to an older one until this is fixed?

hatch01 commented 7 months ago

@FlafyDev Did you find anything to fix the problem?

keppelerj commented 7 months ago

Any updates on this?

FlafyDev commented 7 months ago

I managed to build with flutter 3.19.0 the default flutter project. I had to use the following flake: https://gist.github.com/FlafyDev/ef5e4f745f924f9980c931da588dbf9d (this is just what I used to make it work. there are probably other ways as well)

And also, since gradle has this line in <proj>/android/settings.gradle:

includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")

it tries to create a .gradle directory in Flutter's sdk, which on NixOS would be readonly. To get around this I copied the contents of the directory to a new writable directory and changed the path. This is ofc not an ideal solution and I'm currently looking to how(or if) I can change the .gradle path from Flutter's SDK. I don't know gradle very well...

EDIT 1:

just an idea without much knowledge about gradle, but maybe we can build that .gradle directory in the nix package so that it doesn't even need to create anything on when building the project at runtime?

EDIT 2:

edit 1 doesn't seem to be possible, it tries to write lock files in .gradle so making it readonly is not possible.. Unless it's possible to make gradle not care about lock files.

FlafyDev commented 7 months ago

After a lot of trial and error with gradle, I managed to find a solution. Can anybody test this patch to nixpkgs? @hatch01

diff --git a/pkgs/development/compilers/flutter/flutter.nix b/pkgs/development/compilers/flutter/flutter.nix
index 03c2968f4ab9..627a40dcb1db 100644
--- a/pkgs/development/compilers/flutter/flutter.nix
+++ b/pkgs/development/compilers/flutter/flutter.nix
@@ -82,6 +82,9 @@ let
           "dartSdkVersion": "${dart.version}"
         }
         EOF
+
+        # Suppress error now that `.gradle` location changed from our patch.
+        mkdir -p "$out/packages/flutter_tools/gradle/.gradle"
       '';

       installPhase = ''
diff --git a/pkgs/development/compilers/flutter/versions/3_19/patches/gradle-tools-wrapper.patch b/pkgs/development/compilers/flutter/versions/3_19/patches/gradle-tools-wrapper.patch
new file mode 100644
index 000000000000..e3943fb394df
--- /dev/null
+++ b/pkgs/development/compilers/flutter/versions/3_19/patches/gradle-tools-wrapper.patch
@@ -0,0 +1,28 @@
+Adds an intermediate gradle build to change flutter_tools' gradle project from
+creating `build` and `.gradle` directories in the nix store.
+This patch moves them to "$HOME/.cache/flutter/nix-flutter-tools-gradle/$engineShortRev"
+diff --git a/packages/flutter_tools/gradle/settings.gradle b/packages/flutter_tools/gradle/settings.gradle
+new file mode 100644
+index 0000000000..b2485c94b4
+--- /dev/null
++++ b/packages/flutter_tools/gradle/settings.gradle
+@@ -0,0 +1,19 @@
++rootProject.buildFileName = "/dev/null"
++
++def engineShortRev = (new File("$settingsDir/../../../bin/internal/engine.version")).text.take(10)
++def dir = new File("$System.env.HOME/.cache/flutter/nix-flutter-tools-gradle/$engineShortRev")
++dir.mkdirs()
++def file = new File(dir, "settings.gradle")
++
++file.text = """
++rootProject.projectDir = new File("$settingsDir")
++apply from: new File("$settingsDir/settings.gradle.kts")
++
++gradle.allprojects { project ->
++  project.beforeEvaluate {
++    project.layout.buildDirectory = new File("$dir/build")
++  }
++}
++"""
++
++includeBuild(dir)
MikiVanousek commented 7 months ago

Edit: I was using a different flake. The one you provided (after removing melos) works! I am impressed.

MikiVanousek commented 7 months ago

This is quite amazing. When can I expect to see this in master, and when `nixpkgs?

hatch01 commented 7 months ago

After a lot of trial and error with gradle, I managed to find a solution. Can anybody test this patch to nixpkgs? @hatch01

diff --git a/pkgs/development/compilers/flutter/flutter.nix b/pkgs/development/compilers/flutter/flutter.nix
index 03c2968f4ab9..627a40dcb1db 100644
--- a/pkgs/development/compilers/flutter/flutter.nix
+++ b/pkgs/development/compilers/flutter/flutter.nix
@@ -82,6 +82,9 @@ let
           "dartSdkVersion": "${dart.version}"
         }
         EOF
+
+        # Suppress error now that `.gradle` location changed from our patch.
+        mkdir -p "$out/packages/flutter_tools/gradle/.gradle"
       '';

       installPhase = ''
diff --git a/pkgs/development/compilers/flutter/versions/3_19/patches/gradle-tools-wrapper.patch b/pkgs/development/compilers/flutter/versions/3_19/patches/gradle-tools-wrapper.patch
new file mode 100644
index 000000000000..e3943fb394df
--- /dev/null
+++ b/pkgs/development/compilers/flutter/versions/3_19/patches/gradle-tools-wrapper.patch
@@ -0,0 +1,28 @@
+Adds an intermediate gradle build to change flutter_tools' gradle project from
+creating `build` and `.gradle` directories in the nix store.
+This patch moves them to "$HOME/.cache/flutter/nix-flutter-tools-gradle/$engineShortRev"
+diff --git a/packages/flutter_tools/gradle/settings.gradle b/packages/flutter_tools/gradle/settings.gradle
+new file mode 100644
+index 0000000000..b2485c94b4
+--- /dev/null
++++ b/packages/flutter_tools/gradle/settings.gradle
+@@ -0,0 +1,19 @@
++rootProject.buildFileName = "/dev/null"
++
++def engineShortRev = (new File("$settingsDir/../../../bin/internal/engine.version")).text.take(10)
++def dir = new File("$System.env.HOME/.cache/flutter/nix-flutter-tools-gradle/$engineShortRev")
++dir.mkdirs()
++def file = new File(dir, "settings.gradle")
++
++file.text = """
++rootProject.projectDir = new File("$settingsDir")
++apply from: new File("$settingsDir/settings.gradle.kts")
++
++gradle.allprojects { project ->
++  project.beforeEvaluate {
++    project.layout.buildDirectory = new File("$dir/build")
++  }
++}
++"""
++
++includeBuild(dir)

This works perfectly using my personal flake! Thank you very much!

FlafyDev commented 7 months ago

Good to hear it works! I'll make a PR..

When can I expect to see this in master, and when `nixpkgs?

After I make a PR and it gets merged it will be on master. Probably a few days after merging it will be on unstable

MikiVanousek commented 7 months ago

Thank you @FlafyDev. I am interested in contributing to the nixpkgs. Would it be sensible for me to create a test which creates a new Flutter app and attempts to build it in the several available modes (aar apk appbundle bundle linux web )? It sees this test would prevent breaking changes such as the one that led to this issue.

FlafyDev commented 7 months ago

Thank you @FlafyDev. I am interested in contributing to the nixpkgs. Would it be sensible for me to create a test which creates a new Flutter app and attempts to build it in the several available modes (aar apk appbundle bundle linux web)? It sees this test would prevent breaking changes such as the one that led to this issue.

Creating tests would definitely be helpful! There is an issue about it https://github.com/NixOS/nixpkgs/issues/262507. Though currently there isn't a way to build a Flutter apk in a pure Nix derivation, so the tests would most likely need to be impure and I don't know if you can do it in Nixpkgs.

hatch01 commented 2 months ago

Hi, with a recent nixpkgs update, the exact same issue came back The issue appeared between :

        'github:NixOS/nixpkgs/4877ea239f4d02410c3516101faf35a81af0c30e' (2024-08-13)
      → 'github:NixOS/nixpkgs/b833ff01a0d694b910daca6e2ff4a3f26dee478c' (2024-09-01)
FlafyDev commented 1 month ago

Is it because of 3.24?

Can you check if you're getting the error on flutter 3.22 or 3.24 (or both)

lumpsoid commented 1 month ago

@FlafyDev only on flutter 3.24 github:NixOS/nixpkgs/b833ff01a0d694b910daca6e2ff4a3f26dee478c I got the error about the flutter plugin

Running Gradle task 'assembleRelease'...                        

FAILURE: Build failed with an exception.

* Where:
Settings file '/home/<project path>/android/settings.gradle' line: 25

* What went wrong:
Error resolving plugin [id: 'dev.flutter.flutter-plugin-loader', version: '1.0.0']
> A problem occurred configuring project ':gradle'.
   > Could not create service of type OutputFilesRepository using ExecutionGradleServices.createOutputFilesRepository().
      > Failed to create directory '/nix/store/wp7165dbyc8w8ng10qaxkfsrrr9rc5hs-flutter-wrapped-3.24.1-sdk-links/packages/flutter_tools/gradle/.gradle/buildOutputCleanup'

* 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
Running Gradle task 'assembleRelease'...                            4.0s
Gradle task assembleRelease failed with exit code 1

Settings file '/home//android/settings.gradle' line: 25 contains

plugins {
    id "dev.flutter.flutter-plugin-loader" version "1.0.0" << 25th line
    id "com.android.application" version "7.3.0" apply false
}

on flutter 3.22 github:NixOS/nixpkgs/4877ea239f4d02410c3516101faf35a81af0c30e I have successfully built the project

lumpsoid commented 1 month ago

initial commit after which the error started is github:NixOS/nixpkgs/c1ce56e9c606b4cd31f0950768911b1171b8db51 when the 3.24 version update was made on 2024-08-28

I don't think this is any important information, but it confused me that the day before (2024-08-27) most commits were with version 3.22 and only on this commit github:NixOS/nixpkgs/bf4565a7fcd267f714d0377ed506a9a3ebc67f58 which only adds some checks about including unit tests, flutter was on version 3.24, but that might be something I don't understand how nix works

hatch01 commented 1 month ago

Will be fixed with #341133

rschulman commented 1 month ago

I am still getting this error on flutter v3.24.1. I can see the redirect settings.gradle in the nix store under flutter-tools, as well as the created directories under $HOME/.cache/flutter/nix-flutter-tools-gradle/ but I'm still getting Failed to create directory '/nix/store/cpgyn3rn3a117nv4s1g7j5ajgbdkplby-flutter-wrapped-3.24.1-sdk-links/packages/flutter_tools/gradle/.gradle/buildOutputCleanup' when trying to do a gradle sync in a flutter project in Android Studio.

byronogis commented 1 month ago

Is there a local cache, like .direnv or .devenv etc, that wll causes the flutter in the working folder to be not fresh

I am still getting this error on flutter v3.24.1. I can see the redirect settings.gradle in the nix store under flutter-tools, as well as the created directories under $HOME/.cache/flutter/nix-flutter-tools-gradle/ but I'm still getting Failed to create directory '/nix/store/cpgyn3rn3a117nv4s1g7j5ajgbdkplby-flutter-wrapped-3.24.1-sdk-links/packages/flutter_tools/gradle/.gradle/buildOutputCleanup' when trying to do a gradle sync in a flutter project in Android Studio.

rschulman commented 1 month ago

There is a .direnv cache, but I've removed it, both by doing nix-direnv-reload and by simply deleting the .direnv directory, but neither seem to have solved the problem.

rschulman commented 1 month ago

Hm, what is interesting is that if I look in the ~/.cache/flutter/nix-flutter-tools-gradle/ directory, it is clear that Android Studio is actually using that directory to build in. It just looks like its ALSO trying to use the nix store directory for something.

rschulman commented 3 weeks ago

So I'm still dealing with this issue, and one thing I've noticed is that it only happens in Android Studio when gradle tries to sync. Running flutter from the command line works fine, which is interesting.