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 ];
}
1 Like

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
  
  
1 Like
Hosted by Flying Circus.