Anyone managed to install flutter >=3.0.0 on NixOS?

I recently stumbled into an issue using Flutter because the packaged version is too old:

The current Flutter SDK version is 2.10.1.

Because flutter_hbb depends on flutter_smart_dialog >=4.3.0 which requires Flutter SDK version >=3.0.0, version solving failed.
Running "flutter pub get" in flutter...                                 
pub get failed (1; Because flutter_hbb depends on flutter_smart_dialog >=4.3.0 which requires Flutter SDK version >=3.0.0, version solving failed.)

Is there an overlay or something I’m missing to get Flutter >=3.0.0 on NixOS?

1 Like

There is https://github.com/NixOS/nixpkgs/pull/173200

yeah I’m currently using that branch for work via niv. Works without issues for me

1 Like

Hi. I wonder if you could provide explicit ELI5 instructions for getting Flutter 3 up via niv? Thank you!

tbh I think nowadays it would make more sense to use nix flakes, I just didn’t get round to migrating :man_shrugging: I can post my shell.nix and associated files later. it’s based on https://github.com/babariviere/flutter-nix-hello-world
you can use a specific rev of nixpkgs by using niv update, in this case niv update --owner nanashi0x74 --branch flutter-3-0-0

I’m using it in a nix shell btw… If you’d like to install it system-wide I’d probably add a flake input pinning that nixpkgs revision and add flutter from there to environment.systemPackages, but I’d have to look into the specifics myself :sweat_smile: Without flakes I have little idea how

Hi, I wonder if you can be even more ELI5… I have tried the following:

$ git clone git@github.com:babariviere/flutter-nix-hello-world.git
$ cd flutter-nix-hello-world; nix-shell
$ flutter --version
Flutter 1.17.5 [...]
$ niv update --owner nanashi0x74 --branch flutter-3-0-0
Missing: PACKAGE
$ niv update flutter --owner nanashi0x74 --branch flutter-3-0-0
FATAL: Cannot update package flutter.
The package doesn't exist. Use niv add flutter
$ niv add flutter --owner nanashi0x74 --branch flutter-3-0-0
FATAL: One or more packages failed to update:
flutter: Update failed: Key could not be found: url_template

ah yes, I forgot something in that command- it should be niv update nixpkgs --owner nanashi0x74 --branch flutter-3-0-0

If you try that though you might run into some issues with androidenv packages not being found anymore- I’ll set a reminder to post my shell.nix today :joy:

here they are-

shell.nix
{ sources ? import ./nix/sources.nix }:

let
  pkgs = import sources.nixpkgs { config.android_sdk.accept_license = true; };
  androidSdk = pkgs.androidenv.composeAndroidPackages {
    buildToolsVersions = [ "29.0.2" ];
    platformVersions = [ "31" ];
  };
in
pkgs.mkShell {
  buildInputs = with pkgs;
    [
      flutter
      dart
      jdk11
      niv
      androidSdk.platform-tools
      go_1_18

    ];

  ANDROID_HOME = "${androidSdk.androidsdk}/libexec/android-sdk";
  JAVA_HOME = pkgs.jdk11;
  ANDROID_LOG_TAGS = "ActivityManager:I flutter:I *:W";
  # ANDROID_AVD_HOME = (toString ./.) + "/.android/avd";
}
nix/sources.nix
# This file has been generated by Niv.

let

  #
  # The fetchers. fetch_<type> fetches specs of type <type>.
  #

  fetch_file = pkgs: name: spec:
    let
      name' = sanitizeName name + "-src";
    in
      if spec.builtin or true then
        builtins_fetchurl { inherit (spec) url sha256; name = name'; }
      else
        pkgs.fetchurl { inherit (spec) url sha256; name = name'; };

  fetch_tarball = pkgs: name: spec:
    let
      name' = sanitizeName name + "-src";
    in
      if spec.builtin or true then
        builtins_fetchTarball { name = name'; inherit (spec) url sha256; }
      else
        pkgs.fetchzip { name = name'; inherit (spec) url sha256; };

  fetch_git = name: spec:
    let
      ref =
        if spec ? ref then spec.ref else
          if spec ? branch then "refs/heads/${spec.branch}" else
            if spec ? tag then "refs/tags/${spec.tag}" else
              abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!";
      submodules = if spec ? submodules then spec.submodules else false;
      submoduleArg =
        let
          nixSupportsSubmodules = builtins.compareVersions builtins.nixVersion "2.4" >= 0;
          emptyArgWithWarning =
            if submodules == true
            then
              builtins.trace
                (
                  "The niv input \"${name}\" uses submodules "
                  + "but your nix's (${builtins.nixVersion}) builtins.fetchGit "
                  + "does not support them"
                )
                {}
            else {};
        in
          if nixSupportsSubmodules
          then { inherit submodules; }
          else emptyArgWithWarning;
    in
      builtins.fetchGit
        ({ url = spec.repo; inherit (spec) rev; inherit ref; } // submoduleArg);

  fetch_local = spec: spec.path;

  fetch_builtin-tarball = name: throw
    ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
        $ niv modify ${name} -a type=tarball -a builtin=true'';

  fetch_builtin-url = name: throw
    ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
        $ niv modify ${name} -a type=file -a builtin=true'';

  #
  # Various helpers
  #

  # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695
  sanitizeName = name:
    (
      concatMapStrings (s: if builtins.isList s then "-" else s)
        (
          builtins.split "[^[:alnum:]+._?=-]+"
            ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name)
        )
    );

  # The set of packages used when specs are fetched using non-builtins.
  mkPkgs = sources: system:
    let
      sourcesNixpkgs =
        import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; };
      hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
      hasThisAsNixpkgsPath = <nixpkgs> == ./.;
    in
      if builtins.hasAttr "nixpkgs" sources
      then sourcesNixpkgs
      else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then
        import <nixpkgs> {}
      else
        abort
          ''
            Please specify either <nixpkgs> (through -I or NIX_PATH=nixpkgs=...) or
            add a package called "nixpkgs" to your sources.json.
          '';

  # The actual fetching function.
  fetch = pkgs: name: spec:

    if ! builtins.hasAttr "type" spec then
      abort "ERROR: niv spec ${name} does not have a 'type' attribute"
    else if spec.type == "file" then fetch_file pkgs name spec
    else if spec.type == "tarball" then fetch_tarball pkgs name spec
    else if spec.type == "git" then fetch_git name spec
    else if spec.type == "local" then fetch_local spec
    else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
    else if spec.type == "builtin-url" then fetch_builtin-url name
    else
      abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";

  # If the environment variable NIV_OVERRIDE_${name} is set, then use
  # the path directly as opposed to the fetched source.
  replace = name: drv:
    let
      saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name;
      ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}";
    in
      if ersatz == "" then drv else
        # this turns the string into an actual Nix path (for both absolute and
        # relative paths)
        if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}";

  # Ports of functions for older nix versions

  # a Nix version of mapAttrs if the built-in doesn't exist
  mapAttrs = builtins.mapAttrs or (
    f: set: with builtins;
    listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
  );

  # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
  range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1);

  # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
  stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));

  # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
  stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
  concatMapStrings = f: list: concatStrings (map f list);
  concatStrings = builtins.concatStringsSep "";

  # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331
  optionalAttrs = cond: as: if cond then as else {};

  # fetchTarball version that is compatible between all the versions of Nix
  builtins_fetchTarball = { url, name ? null, sha256 }@attrs:
    let
      inherit (builtins) lessThan nixVersion fetchTarball;
    in
      if lessThan nixVersion "1.12" then
        fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
      else
        fetchTarball attrs;

  # fetchurl version that is compatible between all the versions of Nix
  builtins_fetchurl = { url, name ? null, sha256 }@attrs:
    let
      inherit (builtins) lessThan nixVersion fetchurl;
    in
      if lessThan nixVersion "1.12" then
        fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
      else
        fetchurl attrs;

  # Create the final "sources" from the config
  mkSources = config:
    mapAttrs (
      name: spec:
        if builtins.hasAttr "outPath" spec
        then abort
          "The values in sources.json should not have an 'outPath' attribute"
        else
          spec // { outPath = replace name (fetch config.pkgs name spec); }
    ) config.sources;

  # The "config" used by the fetchers
  mkConfig =
    { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null
    , sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile)
    , system ? builtins.currentSystem
    , pkgs ? mkPkgs sources system
    }: rec {
      # The sources, i.e. the attribute set of spec name to spec
      inherit sources;

      # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
      inherit pkgs;
    };

in
mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }
nix/sources.json
{
    "nixpkgs": {
        "branch": "flutter-3-0-0",
        "description": "Nix Packages collection",
        "homepage": "",
        "owner": "nanashi0x74",
        "repo": "nixpkgs",
        "rev": "043de04db8a6b0391b3fefaaade160514d866946",
        "sha256": "1x53ic89pv5hdi7f0nrgfwr7csy9gx2yci0hqc6l20mdalw9n4ca",
        "type": "tarball",
        "url": "https://github.com/nanashi0x74/nixpkgs/archive/043de04db8a6b0391b3fefaaade160514d866946.tar.gz",
        "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
    }
}

Here’s a bare minimum shell.nix that has flutter-3.0.4:

{ pkgs ? import (fetchTarball "https://github.com/knarkzel/nixpkgs/archive/043de04db8a6b0391b3fefaaade160514d866946.tar.gz") {} }:
pkgs.mkShell {
    buildInputs = with pkgs.buildPackages; [ flutter ];
}
2 Likes

Got it working also in a flake (flutter-3.0.4)

flake.nix
  
  {
  description = "Flutter 3.0.4";
  inputs = {
    nixpkgs.url = "github:nanashi0x74/nixpkgs/flutter-3-0-0";
    flake-utils.url = "github:numtide/flake-utils";
  };
  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = import nixpkgs {
          inherit system;
          config = {
            android_sdk.accept_license = true;
            allowUnfree = true;
          };
        };
        buildToolsVersion = "30.0.3";
        androidComposition = pkgs.androidenv.composeAndroidPackages {
          buildToolsVersions = [ buildToolsVersion "28.0.3" ];
          platformVersions = [ "31" "28" ];
          abiVersions = [ "armeabi-v7a" "arm64-v8a" ];
        };
        androidSdk = androidComposition.androidsdk;
      in
      {
        devShell =
          with pkgs; mkShell rec {
            ANDROID_SDK_ROOT = "${androidSdk}/libexec/android-sdk";
            buildInputs = [
              flutter
              androidSdk
              jdk11
            ];
          };
      });
  } 
  
  
flake.lock
  
  {
    "nodes": {
      "flake-utils": {
        "locked": {
          "lastModified": 1656928814,
          "narHash": "sha256-RIFfgBuKz6Hp89yRr7+NR5tzIAbn52h8vT6vXkYjZoM=",
          "owner": "numtide",
          "repo": "flake-utils",
          "rev": "7e2a3b3dfd9af950a856d66b0a7d01e3c18aa249",
          "type": "github"
        },
        "original": {
          "owner": "numtide",
          "repo": "flake-utils",
          "type": "github"
        }
      },
      "nixpkgs": {
        "locked": {
          "lastModified": 1657540956,
          "narHash": "sha256-ihGbOFWtAkENwxBE5kV/yWt2MncvW+BObLDsmxCLo/Q=",
          "owner": "nanashi0x74",
          "repo": "nixpkgs",
          "rev": "043de04db8a6b0391b3fefaaade160514d866946",
          "type": "github"
        },
        "original": {
          "owner": "nanashi0x74",
          "ref": "flutter-3-0-0",
          "repo": "nixpkgs",
          "type": "github"
        }
      },
      "root": {
        "inputs": {
          "flake-utils": "flake-utils",
          "nixpkgs": "nixpkgs"
        }
      }
    },
    "root": "root",
    "version": 7
  }
  
  
.envrc (for direnv)
  
  use flake
  
  
2 Likes

This does not have M1/M2 support right? What kind of changes do I need to make to make it work on M2?

I ran your shell.nix and this is what I got:

error: Package ‘flutter-3.0.4’ in /nix/store/abhnrd57akqms4f06w50vzm3qnqr9zb3-source/pkgs/development/compilers/flutter/flutter.nix:170 is not supported on ‘aarch64-darwin’, refusing to evaluate.

       a) To temporarily allow packages that are unsupported for this system, you can use an environment variable
          for a single invocation of the nix tools.

            $ export NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1

        Note: For `nix shell`, `nix build`, `nix develop` or any other Nix 2.4+
        (Flake) command, `--impure` must be passed in order to read this
        environment variable.

       b) For `nixos-rebuild` you can set
         { nixpkgs.config.allowUnsupportedSystem = true; }
       in configuration.nix to override this.

       c) For `nix-env`, `nix-build`, `nix-shell` or any other Nix command you can add
         { allowUnsupportedSystem = true; }
       to ~/.config/nixpkgs/config.nix.

EDIT: If I’m reading it correctly, I need to wait for https://github.com/NixOS/nixpkgs/pull/173200 to add support?

https://github.com/NixOS/nixpkgs/pull/173200 won’t add support for mac- I don’t know what exactly would need to be done for that and I also don’t have any mac to test. I’d recommend opening an issue about it and pinging the flutter maintainers in it and asking what needs to be done- perhaps you could give it a go yourself ^^

I appreciate the work done to get flutter 3 in nixpkgs. I’ve been trying to use an overlay to install flutter v3.0.3 since v3.0.4 seems to be incompatible with one of my projects. However, the overlay doesn’t seem to be working. If anyone has any insight on why this doesn’t work and/or alternatives, I’d appreciate it.

As a workaround, I’ve resorted to forking nixpkgs, and modifying the values in the default.nix file directly which works, but seems clunky.

(final: prev:
        {
          flutter = prev.flutter.overrideAttrs (finalAttrs: previousAttrs: {
              src = pkgs.buildPackages.fetchurl
                {
                  url = "https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.0.3-stable.tar.xz";
                  sha256 = "sha256-84Bnh/Ovw3l2kCT0+bIMJDgRiBpyvJxuYr/C/VBnbEg=";
                };
            });
        })