diff --git a/pkgs/development/mobile/androidenv/compose-android-packages.nix b/pkgs/development/mobile/androidenv/compose-android-packages.nix index 33332ea8386d..cce2f31a2797 100644 --- a/pkgs/development/mobile/androidenv/compose-android-packages.nix +++ b/pkgs/development/mobile/androidenv/compose-android-packages.nix @@ -14,7 +14,7 @@ let # Coerces a string to an int. coerceInt = val: if lib.isInt val then val else lib.toIntBase10 val; - coerceIntVersion = v: coerceInt (lib.versions.major v); + coerceIntVersion = v: coerceInt (lib.versions.major (toString v)); # Parses a single version, substituting "latest" with the latest version. parseVersion = @@ -144,7 +144,7 @@ in let # Resolve all the platform versions. - platformVersions' = map coerceInt (parseVersions repo "platforms" platformVersions); + platformVersions' = map coerceIntVersion (parseVersions repo "platforms" platformVersions); # Determine the Android os identifier from Nix's system identifier os = @@ -220,6 +220,28 @@ let extras = fetchArchives repo.extras; }; + # Latest packages that are typically keyed by the API level. + archivesByApiLevel = + let + # Transforms the given attrset mapping API levels (with possible suffixes and minor versions) + # into the latest API level for each major version. + mkLatestByApiLevel = + packages: + lib.filterAttrs (_: value: value != null) ( + lib.mapAttrs ( + _: value: + (lib.findFirst (x: x.name == lib.versions.majorMinor x.name) { value = null; } ( + lib.lists.sort (x: y: lib.strings.versionOlder y.name x.name) value + )).value + ) (lib.groupBy (x: lib.versions.major x.name) (lib.attrsToList packages)) + ); + in + { + platforms = mkLatestByApiLevel allArchives.packages.platforms; + sources = mkLatestByApiLevel allArchives.packages.sources; + system-images = mkLatestByApiLevel allArchives.system-images; + }; + # Lift the archives to the package level for easy search, # and add recurseIntoAttrs to all of them. allPackages = @@ -284,17 +306,28 @@ let lib.hasAttrByPath [ package (toString version) ] packages; # Displays a nice error message that includes the available options if a version doesn't exist. + # Note that allPackages can be a list of package sets, or a single package set. Pass a list if + # you want to prioritize elements to the left (e.g. for passing a platform major version). checkVersion = - packages: package: version: - if hasVersion packages package version then - packages.${package}.${toString version} - else + allPackages: package: version: + let + # Convert the package sets to a list. + allPackages' = if lib.isList allPackages then allPackages else lib.singleton allPackages; + + # Pick the first package set where we have the version. + packageSet = lib.findFirst (packages: hasVersion packages package version) null allPackages'; + in + if packageSet == null then throw '' The version ${toString version} is missing in package ${package}. The only available versions are ${ - builtins.concatStringsSep ", " (builtins.attrNames packages.${package}) + lib.concatStringsSep ", " ( + lib.attrNames (lib.foldl (s: x: s // (x.${package} or { })) { } allPackages') + ) }. - ''; + '' + else + packageSet.${package}.${toString version}; # Returns true if we should link the specified plugins. shouldLink = @@ -508,19 +541,23 @@ lib.recurseIntoAttrs rec { ''; }; + # This is a list of the chosen API levels, as integers. platformVersions = platformVersions'; platforms = map ( version: deployAndroidPackage { - package = checkVersion allArchives.packages "platforms" version; + package = checkVersion [ archivesByApiLevel allArchives.packages ] "platforms" version; } ) platformVersions'; + # This exposes the version strings (e.g. "36.1" for API 36). + platformVersionStrings = map (platform: platform.version) platforms; + sources = map ( version: deployAndroidPackage { - package = checkVersion allArchives.packages "sources" version; + package = checkVersion [ archivesByApiLevel allArchives.packages ] "sources" version; } ) platformVersions'; @@ -539,14 +576,19 @@ lib.recurseIntoAttrs rec { # ``` let availablePackages = - map (abiVersion: allArchives.system-images.${toString apiVersion}.${type}.${abiVersion}) + map + ( + abiVersion: + archivesByApiLevel.system-images.${toString apiVersion}.${type}.${abiVersion} + or allArchives.system-images.${toString apiVersion}.${type}.${abiVersion} + ) ( builtins.filter ( abiVersion: lib.hasAttrByPath [ (toString apiVersion) type abiVersion ] allArchives.system-images ) abiVersions ); - instructions = builtins.listToAttrs ( + instructions = lib.listToAttrs ( map (package: { name = package.name; value = lib.optionalString (lib.hasPrefix "google_apis" type) '' diff --git a/pkgs/development/mobile/androidenv/examples/shell-with-emulator.nix b/pkgs/development/mobile/androidenv/examples/shell-with-emulator.nix index fbb52d65a23b..9c6d9ec60902 100644 --- a/pkgs/development/mobile/androidenv/examples/shell-with-emulator.nix +++ b/pkgs/development/mobile/androidenv/examples/shell-with-emulator.nix @@ -78,6 +78,9 @@ let androidSdk = androidComposition.androidsdk; platformTools = androidComposition.platform-tools; latestSdk = pkgs.lib.foldl' pkgs.lib.max 0 androidComposition.platformVersions; + latestSdkVersion = pkgs.lib.foldl' ( + s: x: if pkgs.lib.strings.compareVersions x s > 0 then x else s + ) "0" androidComposition.platformVersionStrings; jdk = pkgs.jdk; in pkgs.mkShell rec { @@ -123,8 +126,8 @@ pkgs.mkShell rec { packages=( "build-tools" "cmdline-tools" \ - "platform-tools" "platforms;android-${toString latestSdk}" \ - "system-images;android-${toString latestSdk};google_apis;x86_64" + "platform-tools" "platforms;android-${toString latestSdkVersion}" \ + "system-images;android-${toString latestSdkVersion};google_apis;x86_64" ) ${pkgs.lib.optionalString emulatorSupported ''packages+=("emulator")''} @@ -184,7 +187,7 @@ pkgs.mkShell rec { mkdir -p $ANDROID_USER_HOME avdmanager delete avd -n testAVD || true - echo "" | avdmanager create avd --force --name testAVD --package 'system-images;android-${toString latestSdk};google_apis;x86_64' + echo "" | avdmanager create avd --force --name testAVD --package 'system-images;android-${toString latestSdkVersion};google_apis;x86_64' result=$(avdmanager list avd) if [[ ! $result =~ "Name: testAVD" ]]; then diff --git a/pkgs/development/mobile/androidenv/examples/shell-without-emulator.nix b/pkgs/development/mobile/androidenv/examples/shell-without-emulator.nix index ead2c48aaf26..58e7879dc3ee 100644 --- a/pkgs/development/mobile/androidenv/examples/shell-without-emulator.nix +++ b/pkgs/development/mobile/androidenv/examples/shell-without-emulator.nix @@ -48,6 +48,8 @@ let includeSystemImages = false; includeEmulator = false; + platformVersions = [ "latest" ]; + # Accepting more licenses declaratively: extraLicenses = [ # Already accepted for you with the global accept_license = true or