Revert "Speed up first asset load by encoding asset manifest in binary rather than JSON (#113637)" (#116662) (#116672)

This reverts commit 56cad89b1e8d79b75b88116a5db9cb70f91c4986.

Co-authored-by: Casey Hillers <chillers@google.com>
diff --git a/dev/benchmarks/microbenchmarks/lib/foundation/decode_and_parse_asset_manifest.dart b/dev/benchmarks/microbenchmarks/lib/foundation/decode_and_parse_asset_manifest.dart
index d6b0f7c..b64c153 100644
--- a/dev/benchmarks/microbenchmarks/lib/foundation/decode_and_parse_asset_manifest.dart
+++ b/dev/benchmarks/microbenchmarks/lib/foundation/decode_and_parse_asset_manifest.dart
@@ -3,9 +3,9 @@
 // found in the LICENSE file.
 
 import 'dart:convert';
-import 'dart:typed_data';
 
-import 'package:flutter/services.dart' show PlatformAssetBundle, StandardMessageCodec;
+import 'package:flutter/foundation.dart';
+import 'package:flutter/services.dart' show PlatformAssetBundle;
 import 'package:flutter/widgets.dart';
 
 import '../common.dart';
@@ -18,14 +18,16 @@
   final BenchmarkResultPrinter printer = BenchmarkResultPrinter();
   WidgetsFlutterBinding.ensureInitialized();
   final Stopwatch watch = Stopwatch();
+  final PlatformAssetBundle bundle = PlatformAssetBundle();
 
-  final ByteData assetManifest = await loadAssetManifest();
-
+  final ByteData assetManifestBytes = await bundle.load('money_asset_manifest.json');
   watch.start();
   for (int i = 0; i < _kNumIterations; i++) {
-    // This is effectively a test.
+    bundle.clear();
+    final String json = utf8.decode(assetManifestBytes.buffer.asUint8List());
+    // This is a test, so we don't need to worry about this rule.
     // ignore: invalid_use_of_visible_for_testing_member
-    AssetImage.parseAssetManifest(assetManifest);
+    await AssetImage.manifestParser(json);
   }
   watch.stop();
 
@@ -38,49 +40,3 @@
 
   printer.printToStdout();
 }
-
-final RegExp _extractRatioRegExp = RegExp(r'/?(\d+(\.\d*)?)x$');
-
-Future<ByteData> loadAssetManifest() async {
-  double parseScale(String key) {
-    final Uri assetUri = Uri.parse(key);
-    String directoryPath = '';
-    if (assetUri.pathSegments.length > 1) {
-      directoryPath = assetUri.pathSegments[assetUri.pathSegments.length - 2];
-    }
-    final Match? match = _extractRatioRegExp.firstMatch(directoryPath);
-    if (match != null && match.groupCount > 0) {
-      return double.parse(match.group(1)!);
-    }
-    return 1.0;
-  }
-
-  final Map<String, dynamic> result = <String, dynamic>{};
-  final PlatformAssetBundle bundle = PlatformAssetBundle();
-
-  // For the benchmark, we use the older JSON format and then convert it to the modern binary format.
-  final ByteData jsonAssetManifestBytes = await bundle.load('money_asset_manifest.json');
-  final String jsonAssetManifest = utf8.decode(jsonAssetManifestBytes.buffer.asUint8List());
-
-  final Map<String, dynamic> assetManifest = json.decode(jsonAssetManifest) as Map<String, dynamic>;
-
-  for (final MapEntry<String, dynamic> manifestEntry in assetManifest.entries) {
-    final List<dynamic> resultVariants = <dynamic>[];
-    final List<String> entries = (manifestEntry.value as List<dynamic>).cast<String>();
-    for (final String variant in entries) {
-      if (variant == manifestEntry.key) {
-        // With the newer binary format, don't include the main asset in it's
-        // list of variants. This reduces parsing time at runtime.
-        continue;
-      }
-      final Map<String, dynamic> resultVariant = <String, dynamic>{};
-      final double variantDevicePixelRatio = parseScale(variant);
-      resultVariant['asset'] = variant;
-      resultVariant['dpr'] = variantDevicePixelRatio;
-      resultVariants.add(resultVariant);
-    }
-    result[manifestEntry.key] = resultVariants;
-  }
-
-  return const StandardMessageCodec().encodeMessage(result)!;
-}
diff --git a/dev/integration_tests/flutter_gallery/test/example_code_parser_test.dart b/dev/integration_tests/flutter_gallery/test/example_code_parser_test.dart
index a1baa46..94276fb 100644
--- a/dev/integration_tests/flutter_gallery/test/example_code_parser_test.dart
+++ b/dev/integration_tests/flutter_gallery/test/example_code_parser_test.dart
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:async';
-
 import 'package:flutter/services.dart';
 import 'package:flutter_gallery/gallery/example_code_parser.dart';
 import 'package:flutter_test/flutter_test.dart';
@@ -60,9 +58,4 @@
 
   @override
   String toString() => '$runtimeType@$hashCode()';
-
-  @override
-  Future<T> loadStructuredBinaryData<T>(String key, FutureOr<T> Function(ByteData data) parser) async {
-    return parser(await load(key));
-  }
 }
diff --git a/packages/flutter/lib/src/painting/image_resolution.dart b/packages/flutter/lib/src/painting/image_resolution.dart
index f978dff..1e42774 100644
--- a/packages/flutter/lib/src/painting/image_resolution.dart
+++ b/packages/flutter/lib/src/painting/image_resolution.dart
@@ -11,8 +11,7 @@
 
 import 'image_provider.dart';
 
-const String _kLegacyAssetManifestFilename = 'AssetManifest.json';
-const String _kAssetManifestFilename = 'AssetManifest.bin';
+const String _kAssetManifestFileName = 'AssetManifest.json';
 
 /// A screen with a device-pixel ratio strictly less than this value is
 /// considered a low-resolution screen (typically entry-level to mid-range
@@ -285,45 +284,18 @@
     Completer<AssetBundleImageKey>? completer;
     Future<AssetBundleImageKey>? result;
 
-    Future<_AssetManifest> loadJsonAssetManifest() {
-      Future<_AssetManifest> parseJson(String data) {
-        final _AssetManifest parsed = _LegacyAssetManifest.fromJsonString(data);
-        return SynchronousFuture<_AssetManifest>(parsed);
-      }
-      return chosenBundle.loadStructuredData(_kLegacyAssetManifestFilename, parseJson);
-    }
-
-    // TODO(andrewkolos): Once google3 and google-fonts-flutter are migrated
-    // away from using AssetManifest.json, remove all references to it.
-    // See https://github.com/flutter/flutter/issues/114913.
-    Future<_AssetManifest>? manifest;
-
-    // Since AssetBundle load calls can be synchronous (e.g. in the case of tests),
-    // it is not sufficient to only use catchError/onError or the onError parameter
-    // of Future.then--we also have to use a synchronous try/catch. Once google3
-    // tooling starts producing AssetManifest.bin, this block can be removed.
-    try {
-      manifest = chosenBundle.loadStructuredBinaryData(_kAssetManifestFilename, _AssetManifestBin.fromStandardMessageCodecMessage);
-    } catch (error) {
-      manifest = loadJsonAssetManifest();
-    }
-
-    manifest
-      // To understand why we use this no-op `then` instead of `catchError`/`onError`,
-      // see https://github.com/flutter/flutter/issues/115601
-      .then((_AssetManifest manifest) => manifest,
-          onError: (Object? error, StackTrace? stack) => loadJsonAssetManifest())
-      .then((_AssetManifest manifest) {
-        final List<_AssetVariant> candidateVariants = manifest.getVariants(keyName);
-        final _AssetVariant chosenVariant = _chooseVariant(
+    chosenBundle.loadStructuredData<Map<String, List<String>>?>(_kAssetManifestFileName, manifestParser).then<void>(
+      (Map<String, List<String>>? manifest) {
+        final String chosenName = _chooseVariant(
           keyName,
           configuration,
-          candidateVariants,
-        );
+          manifest == null ? null : manifest[keyName],
+        )!;
+        final double chosenScale = _parseScale(chosenName);
         final AssetBundleImageKey key = AssetBundleImageKey(
           bundle: chosenBundle,
-          name: chosenVariant.asset,
-          scale: chosenVariant.devicePixelRatio,
+          name: chosenName,
+          scale: chosenScale,
         );
         if (completer != null) {
           // We already returned from this function, which means we are in the
@@ -337,15 +309,14 @@
           // ourselves.
           result = SynchronousFuture<AssetBundleImageKey>(key);
         }
-      })
-      .onError((Object error, StackTrace stack) {
-        // We had an error. (This guarantees we weren't called synchronously.)
-        // Forward the error to the caller.
-        assert(completer != null);
-        assert(result == null);
-        completer!.completeError(error, stack);
-      });
-
+      },
+    ).catchError((Object error, StackTrace stack) {
+      // We had an error. (This guarantees we weren't called synchronously.)
+      // Forward the error to the caller.
+      assert(completer != null);
+      assert(result == null);
+      completer!.completeError(error, stack);
+    });
     if (result != null) {
       // The code above ran synchronously, and came up with an answer.
       // Return the SynchronousFuture that we created above.
@@ -357,29 +328,35 @@
     return completer.future;
   }
 
-  /// Parses the asset manifest's file contents into it's Dart representation.
+  /// Parses the asset manifest string into a strongly-typed map.
   @visibleForTesting
-  // Return type is set to Object?, because the specific type is private.
-  static Object? parseAssetManifest(ByteData bytes) {
-    return _AssetManifestBin.fromStandardMessageCodecMessage(bytes);
+  static Future<Map<String, List<String>>?> manifestParser(String? jsonData) {
+    if (jsonData == null) {
+      return SynchronousFuture<Map<String, List<String>>?>(null);
+    }
+    // TODO(ianh): JSON decoding really shouldn't be on the main thread.
+    final Map<String, dynamic> parsedJson = json.decode(jsonData) as Map<String, dynamic>;
+    final Iterable<String> keys = parsedJson.keys;
+    final Map<String, List<String>> parsedManifest = <String, List<String>> {
+      for (final String key in keys) key: List<String>.from(parsedJson[key] as List<dynamic>),
+    };
+    // TODO(ianh): convert that data structure to the right types.
+    return SynchronousFuture<Map<String, List<String>>?>(parsedManifest);
   }
 
-  _AssetVariant _chooseVariant(String mainAssetKey, ImageConfiguration config, List<_AssetVariant> candidateVariants) {
-    final _AssetVariant mainAsset = _AssetVariant(asset: mainAssetKey,
-      devicePixelRatio: _naturalResolution);
-    if (config.devicePixelRatio == null || candidateVariants.isEmpty) {
-      return mainAsset;
+  String? _chooseVariant(String main, ImageConfiguration config, List<String>? candidates) {
+    if (config.devicePixelRatio == null || candidates == null || candidates.isEmpty) {
+      return main;
     }
-    final SplayTreeMap<double, _AssetVariant> candidatesByDevicePixelRatio =
-      SplayTreeMap<double, _AssetVariant>();
-    for (final _AssetVariant candidate in candidateVariants) {
-      candidatesByDevicePixelRatio[candidate.devicePixelRatio] = candidate;
+    // TODO(ianh): Consider moving this parsing logic into _manifestParser.
+    final SplayTreeMap<double, String> mapping = SplayTreeMap<double, String>();
+    for (final String candidate in candidates) {
+      mapping[_parseScale(candidate)] = candidate;
     }
-    candidatesByDevicePixelRatio.putIfAbsent(_naturalResolution, () => mainAsset);
     // TODO(ianh): implement support for config.locale, config.textDirection,
     // config.size, config.platform (then document this over in the Image.asset
     // docs)
-    return _findBestVariant(candidatesByDevicePixelRatio, config.devicePixelRatio!);
+    return _findBestVariant(mapping, config.devicePixelRatio!);
   }
 
   // Returns the "best" asset variant amongst the available `candidates`.
@@ -394,17 +371,17 @@
   //   lowest key higher than `value`.
   // - If the screen has high device pixel ratio, choose the variant with the
   //   key nearest to `value`.
-  _AssetVariant _findBestVariant(SplayTreeMap<double, _AssetVariant> candidatesByDpr, double value) {
-    if (candidatesByDpr.containsKey(value)) {
-      return candidatesByDpr[value]!;
+  String? _findBestVariant(SplayTreeMap<double, String> candidates, double value) {
+    if (candidates.containsKey(value)) {
+      return candidates[value]!;
     }
-    final double? lower = candidatesByDpr.lastKeyBefore(value);
-    final double? upper = candidatesByDpr.firstKeyAfter(value);
+    final double? lower = candidates.lastKeyBefore(value);
+    final double? upper = candidates.firstKeyAfter(value);
     if (lower == null) {
-      return candidatesByDpr[upper]!;
+      return candidates[upper];
     }
     if (upper == null) {
-      return candidatesByDpr[lower]!;
+      return candidates[lower];
     }
 
     // On screens with low device-pixel ratios the artifacts from upscaling
@@ -412,12 +389,32 @@
     // ratios because the physical pixels are larger. Choose the higher
     // resolution image in that case instead of the nearest one.
     if (value < _kLowDprLimit || value > (lower + upper) / 2) {
-      return candidatesByDpr[upper]!;
+      return candidates[upper];
     } else {
-      return candidatesByDpr[lower]!;
+      return candidates[lower];
     }
   }
 
+  static final RegExp _extractRatioRegExp = RegExp(r'/?(\d+(\.\d*)?)x$');
+
+  double _parseScale(String key) {
+    if (key == assetName) {
+      return _naturalResolution;
+    }
+
+    final Uri assetUri = Uri.parse(key);
+    String directoryPath = '';
+    if (assetUri.pathSegments.length > 1) {
+      directoryPath = assetUri.pathSegments[assetUri.pathSegments.length - 2];
+    }
+
+    final Match? match = _extractRatioRegExp.firstMatch(directoryPath);
+    if (match != null && match.groupCount > 0) {
+      return double.parse(match.group(1)!);
+    }
+    return _naturalResolution; // i.e. default to 1.0x
+  }
+
   @override
   bool operator ==(Object other) {
     if (other.runtimeType != runtimeType) {
@@ -434,120 +431,3 @@
   @override
   String toString() => '${objectRuntimeType(this, 'AssetImage')}(bundle: $bundle, name: "$keyName")';
 }
-
-/// Centralizes parsing and typecasting of the contents of the asset manifest file,
-/// which is generated by the flutter tool at build time.
-abstract class _AssetManifest {
-  List<_AssetVariant> getVariants(String key);
-}
-
-/// Parses the binary asset manifest into a data structure that's easier to work with.
-///
-/// The asset manifest is a map of asset files to a list of objects containing
-/// information about variants of that asset.
-///
-/// The entries with each variant object are:
-///  - "asset": the location of this variant to load it from.
-///  - "dpr": The device-pixel-ratio that the asset is best-suited for.
-///
-/// New fields could be added to this object schema to support new asset variation
-/// features, such as themes, locale/region support, reading directions, and so on.
-class _AssetManifestBin implements _AssetManifest {
-  _AssetManifestBin(Map<Object?, Object?> standardMessageData): _data = standardMessageData;
-
-  factory _AssetManifestBin.fromStandardMessageCodecMessage(ByteData message) {
-    final Object? data = const StandardMessageCodec().decodeMessage(message);
-    return _AssetManifestBin(data! as Map<Object?, Object?>);
-  }
-
-  final Map<Object?, Object?> _data;
-  final Map<String, List<_AssetVariant>> _typeCastedData = <String, List<_AssetVariant>>{};
-
-  @override
-  List<_AssetVariant> getVariants(String key) {
-    // We lazily delay typecasting to prevent a performance hiccup when parsing
-    // large asset manifests.
-    if (!_typeCastedData.containsKey(key)) {
-      _typeCastedData[key] = ((_data[key] ?? <Object?>[]) as List<Object?>)
-        .cast<Map<Object?, Object?>>()
-        .map(_AssetVariant.fromManifestData)
-        .toList();
-    }
-    return _typeCastedData[key]!;
-  }
-}
-
-class _LegacyAssetManifest implements _AssetManifest {
-  _LegacyAssetManifest({
-    required this.manifest,
-  });
-
-  factory _LegacyAssetManifest.fromJsonString(String jsonString) {
-    List<_AssetVariant> adaptLegacyVariantList(String mainAsset, List<String> variants) {
-      return variants
-        .map((String variant) =>
-          _AssetVariant(asset: variant, devicePixelRatio: _parseScale(mainAsset, variant)))
-        .toList();
-    }
-
-    if (jsonString == null) {
-      return _LegacyAssetManifest(manifest: <String, List<_AssetVariant>>{});
-    }
-    final Map<String, Object?> parsedJson = json.decode(jsonString) as Map<String, dynamic>;
-    final Iterable<String> keys = parsedJson.keys;
-    final Map<String, List<String>> parsedManifest = <String, List<String>> {
-      for (final String key in keys) key: List<String>.from(parsedJson[key]! as List<dynamic>),
-    };
-    final Map<String, List<_AssetVariant>> manifestWithParsedVariants =
-      parsedManifest.map((String asset, List<String> variants) =>
-        MapEntry<String, List<_AssetVariant>>(asset, adaptLegacyVariantList(asset, variants)));
-
-    return _LegacyAssetManifest(manifest: manifestWithParsedVariants);
-  }
-
-  final Map<String, List<_AssetVariant>> manifest;
-
-  static final RegExp _extractRatioRegExp = RegExp(r'/?(\d+(\.\d*)?)x$');
-  static const double _naturalResolution = 1.0;
-
-  @override
-  List<_AssetVariant> getVariants(String key) {
-    return manifest[key] ?? const <_AssetVariant>[];
-  }
-
-  static double _parseScale(String mainAsset, String variant) {
-    // The legacy asset manifest includes the main asset within its variant list.
-    if (mainAsset == variant) {
-      return _naturalResolution;
-    }
-
-    final Uri assetUri = Uri.parse(variant);
-    String directoryPath = '';
-    if (assetUri.pathSegments.length > 1) {
-      directoryPath = assetUri.pathSegments[assetUri.pathSegments.length - 2];
-    }
-
-    final Match? match = _extractRatioRegExp.firstMatch(directoryPath);
-    if (match != null && match.groupCount > 0) {
-      return double.parse(match.group(1)!);
-    }
-
-    return _naturalResolution; // i.e. default to 1.0x
-  }
-}
-
-class _AssetVariant {
-  _AssetVariant({
-    required this.asset,
-    required this.devicePixelRatio,
-  });
-
-  factory _AssetVariant.fromManifestData(Object data) {
-    final Map<Object?, Object?> asStructuredData = data as Map<Object?, Object?>;
-    return _AssetVariant(asset: asStructuredData['asset']! as String,
-      devicePixelRatio: asStructuredData['dpr']! as double);
-  }
-
-  final double devicePixelRatio;
-  final String asset;
-}
diff --git a/packages/flutter/lib/src/services/asset_bundle.dart b/packages/flutter/lib/src/services/asset_bundle.dart
index ba971e2..776035a 100644
--- a/packages/flutter/lib/src/services/asset_bundle.dart
+++ b/packages/flutter/lib/src/services/asset_bundle.dart
@@ -96,25 +96,12 @@
   }
 
   /// Retrieve a string from the asset bundle, parse it with the given function,
-  /// and return that function's result.
+  /// and return the function's result.
   ///
   /// Implementations may cache the result, so a particular key should only be
   /// used with one parser for the lifetime of the asset bundle.
   Future<T> loadStructuredData<T>(String key, Future<T> Function(String value) parser);
 
-  /// Retrieve [ByteData] from the asset bundle, parse it with the given function,
-  /// and return that function's result.
-  ///
-  /// Implementations may cache the result, so a particular key should only be
-  /// used with one parser for the lifetime of the asset bundle.
-  Future<T> loadStructuredBinaryData<T>(String key, FutureOr<T> Function(ByteData data) parser) async {
-    final ByteData data = await load(key);
-    if (data == null) {
-      throw FlutterError('Unable to load asset: $key');
-    }
-    return parser(data);
-  }
-
   /// If this is a caching asset bundle, and the given key describes a cached
   /// asset, then evict the asset from the cache so that the next time it is
   /// loaded, the cache will be reread from the asset bundle.
@@ -169,18 +156,6 @@
     return parser(await loadString(key));
   }
 
-  /// Retrieve [ByteData] from the asset bundle, parse it with the given function,
-  /// and return the function's result.
-  ///
-  /// The result is not cached. The parser is run each time the resource is
-  /// fetched.
-  @override
-  Future<T> loadStructuredBinaryData<T>(String key, FutureOr<T> Function(ByteData data) parser) async {
-    assert(key != null);
-    assert(parser != null);
-    return parser(await load(key));
-  }
-
   // TODO(ianh): Once the underlying network logic learns about caching, we
   // should implement evict().
 
@@ -200,7 +175,6 @@
   // TODO(ianh): Replace this with an intelligent cache, see https://github.com/flutter/flutter/issues/3568
   final Map<String, Future<String>> _stringCache = <String, Future<String>>{};
   final Map<String, Future<dynamic>> _structuredDataCache = <String, Future<dynamic>>{};
-  final Map<String, Future<dynamic>> _structuredBinaryDataCache = <String, Future<dynamic>>{};
 
   @override
   Future<String> loadString(String key, { bool cache = true }) {
@@ -251,69 +225,16 @@
     return completer.future;
   }
 
-  /// Retrieve bytedata from the asset bundle, parse it with the given function,
-  /// and return the function's result.
-  ///
-  /// The result of parsing the bytedata is cached (the bytedata itself is not).
-  /// For any given `key`, the `parser` is only run the first time.
-  ///
-  /// Once the value has been parsed, the future returned by this function for
-  /// subsequent calls will be a [SynchronousFuture], which resolves its
-  /// callback synchronously.
-  @override
-  Future<T> loadStructuredBinaryData<T>(String key, FutureOr<T> Function(ByteData data) parser) {
-    assert(key != null);
-    assert(parser != null);
-
-    if (_structuredBinaryDataCache.containsKey(key)) {
-      return _structuredBinaryDataCache[key]! as Future<T>;
-    }
-
-    // load can return a SynchronousFuture in certain cases, like in the
-    // flutter_test framework. So, we need to support both async and sync flows.
-    Completer<T>? completer; // For async flow.
-    SynchronousFuture<T>? result; // For sync flow.
-
-    load(key)
-      .then<T>(parser)
-      .then<void>((T value) {
-        result = SynchronousFuture<T>(value);
-        if (completer != null) {
-          // The load and parse operation ran asynchronously. We already returned
-          // from the loadStructuredBinaryData function and therefore the caller
-          // was given the future of the completer.
-          completer.complete(value);
-        }
-      }, onError: (Object err, StackTrace? stack) {
-        completer!.completeError(err, stack);
-      });
-
-    if (result != null) {
-      // The above code ran synchronously. We can synchronously return the result.
-      _structuredBinaryDataCache[key] = result!;
-      return result!;
-    }
-
-    // Since the above code is being run asynchronously and thus hasn't run its
-    // `then` handler yet, we'll return a completer that will be completed
-    // when the handler does run.
-    completer = Completer<T>();
-    _structuredBinaryDataCache[key] = completer.future;
-    return completer.future;
-  }
-
   @override
   void evict(String key) {
     _stringCache.remove(key);
     _structuredDataCache.remove(key);
-    _structuredBinaryDataCache.remove(key);
   }
 
   @override
   void clear() {
     _stringCache.clear();
     _structuredDataCache.clear();
-    _structuredBinaryDataCache.clear();
   }
 
   @override
@@ -355,7 +276,7 @@
     bool debugUsePlatformChannel = false;
     assert(() {
       // dart:io is safe to use here since we early return for web
-      // above. If that code is changed, this needs to be guarded on
+      // above. If that code is changed, this needs to be gaurded on
       // web presence. Override how assets are loaded in tests so that
       // the old loader behavior that allows tests to load assets from
       // the current package using the package prefix.
diff --git a/packages/flutter/test/painting/image_resolution_test.dart b/packages/flutter/test/painting/image_resolution_test.dart
index 962cf9d..8e04f2a 100644
--- a/packages/flutter/test/painting/image_resolution_test.dart
+++ b/packages/flutter/test/painting/image_resolution_test.dart
@@ -13,14 +13,18 @@
 class TestAssetBundle extends CachingAssetBundle {
   TestAssetBundle(this._assetBundleMap);
 
-  final Map<String, List<Map<dynamic, dynamic>>> _assetBundleMap;
+  final Map<String, List<String>> _assetBundleMap;
 
   Map<String, int> loadCallCount = <String, int>{};
 
+  String get _assetBundleContents {
+    return json.encode(_assetBundleMap);
+  }
+
   @override
   Future<ByteData> load(String key) async {
-    if (key == 'AssetManifest.bin') {
-      return const StandardMessageCodec().encodeMessage(_assetBundleMap)!;
+    if (key == 'AssetManifest.json') {
+      return ByteData.view(Uint8List.fromList(const Utf8Encoder().convert(_assetBundleContents)).buffer);
     }
 
     loadCallCount[key] = loadCallCount[key] ?? 0 + 1;
@@ -38,71 +42,12 @@
   }
 }
 
-class BundleWithoutAssetManifestBin extends CachingAssetBundle {
-  BundleWithoutAssetManifestBin(this._legacyAssetBundleMap);
-
-  final Map<dynamic, List<String>> _legacyAssetBundleMap;
-
-  Map<String, int> loadCallCount = <String, int>{};
-
-  @override
-  Future<ByteData> load(String key) async {
-    ByteData testByteData(double scale) => ByteData(8)..setFloat64(0, scale);
-
-    if (key == 'AssetManifest.bin') {
-      throw FlutterError('AssetManifest.bin was not found.');
-    }
-    if (key == 'AssetManifest.json') {
-      return ByteData.view(Uint8List.fromList(const Utf8Encoder().convert(json.encode(_legacyAssetBundleMap))).buffer);
-    }
-    switch (key) {
-      case 'assets/image.png':
-        return testByteData(1.0); // see "...with a main asset and a 1.0x asset"
-      case 'assets/2.0x/image.png':
-        return testByteData(1.5);
-    }
-
-    throw FlutterError('Unexpected key: $key');
-  }
-
-  @override
-  Future<ui.ImmutableBuffer> loadBuffer(String key) async {
-    final ByteData data = await load(key);
-    return ui.ImmutableBuffer.fromUint8List(data.buffer.asUint8List());
-  }
-}
-
 void main() {
-
-  // TODO(andrewkolos): Once google3 is migrated away from using AssetManifest.json,
-  // remove all references to it. See https://github.com/flutter/flutter/issues/114913.
-  test('AssetBundle falls back to using AssetManifest.json if AssetManifest.bin cannot be found.', () async {
-    const String assetPath = 'assets/image.png';
-    final Map<dynamic, List<String>> assetBundleMap = <dynamic, List<String>>{};
-    assetBundleMap[assetPath] = <String>[];
-    final AssetImage assetImage = AssetImage(assetPath, bundle: BundleWithoutAssetManifestBin(assetBundleMap));
-    final AssetBundleImageKey key = await assetImage.obtainKey(ImageConfiguration.empty);
-    expect(key.name, assetPath);
-    expect(key.scale, 1.0);
-  });
-
-  test('When using AssetManifest.json, on a high DPR device, a high dpr variant is selected.', () async {
-    const String assetPath = 'assets/image.png';
-    const String asset2xPath = 'assets/2.0x/image.png';
-    final Map<dynamic, List<String>> assetBundleMap = <dynamic, List<String>>{};
-    assetBundleMap[assetPath] = <String>[asset2xPath];
-    final AssetImage assetImage = AssetImage(assetPath, bundle: BundleWithoutAssetManifestBin(assetBundleMap));
-    final AssetBundleImageKey key = await assetImage.obtainKey(const ImageConfiguration(devicePixelRatio: 2.0));
-    expect(key.name, asset2xPath);
-    expect(key.scale, 2.0);
-  });
-
   group('1.0 scale device tests', () {
     void buildAndTestWithOneAsset(String mainAssetPath) {
-      final Map<String, List<Map<dynamic, dynamic>>> assetBundleMap =
-        <String, List<Map<dynamic, dynamic>>>{};
+      final Map<String, List<String>> assetBundleMap = <String, List<String>>{};
 
-      assetBundleMap[mainAssetPath] = <Map<dynamic,dynamic>>[];
+      assetBundleMap[mainAssetPath] = <String>[];
 
       final AssetImage assetImage = AssetImage(
         mainAssetPath,
@@ -148,13 +93,10 @@
       const String mainAssetPath = 'assets/normalFolder/normalFile.png';
       const String variantPath = 'assets/normalFolder/3.0x/normalFile.png';
 
-      final Map<String, List<Map<dynamic, dynamic>>> assetBundleMap =
-        <String, List<Map<dynamic, dynamic>>>{};
+      final Map<String, List<String>> assetBundleMap =
+      <String, List<String>>{};
 
-      final Map<dynamic, dynamic> mainAssetVariantManifestEntry = <dynamic, dynamic>{};
-      mainAssetVariantManifestEntry['asset'] = variantPath;
-      mainAssetVariantManifestEntry['dpr'] = 3.0;
-      assetBundleMap[mainAssetPath] = <Map<dynamic, dynamic>>[mainAssetVariantManifestEntry];
+      assetBundleMap[mainAssetPath] = <String>[mainAssetPath, variantPath];
 
       final TestAssetBundle testAssetBundle = TestAssetBundle(assetBundleMap);
 
@@ -181,10 +123,10 @@
     test('When high-res device and high-res asset not present in bundle then return main variant', () {
       const String mainAssetPath = 'assets/normalFolder/normalFile.png';
 
-      final Map<String, List<Map<dynamic, dynamic>>> assetBundleMap =
-        <String, List<Map<dynamic, dynamic>>>{};
+      final Map<String, List<String>> assetBundleMap =
+      <String, List<String>>{};
 
-      assetBundleMap[mainAssetPath] = <Map<dynamic, dynamic>>[];
+      assetBundleMap[mainAssetPath] = <String>[mainAssetPath];
 
       final TestAssetBundle testAssetBundle = TestAssetBundle(assetBundleMap);
 
@@ -214,18 +156,16 @@
     const String mainAssetPath = 'assets/normalFolder/normalFile.png';
     const String variantPath = 'assets/normalFolder/3.0x/normalFile.png';
 
+
     void buildBundleAndTestVariantLogic(
       double deviceRatio,
       double chosenAssetRatio,
       String expectedAssetPath,
     ) {
-      final Map<String, List<Map<dynamic, dynamic>>> assetBundleMap =
-        <String, List<Map<dynamic, dynamic>>>{};
+      final Map<String, List<String>> assetBundleMap =
+      <String, List<String>>{};
 
-      final Map<dynamic, dynamic> mainAssetVariantManifestEntry = <dynamic, dynamic>{};
-      mainAssetVariantManifestEntry['asset'] = variantPath;
-      mainAssetVariantManifestEntry['dpr'] = 3.0;
-      assetBundleMap[mainAssetPath] = <Map<dynamic, dynamic>>[mainAssetVariantManifestEntry];
+      assetBundleMap[mainAssetPath] = <String>[mainAssetPath, variantPath];
 
       final TestAssetBundle testAssetBundle = TestAssetBundle(assetBundleMap);
 
diff --git a/packages/flutter/test/services/asset_bundle_test.dart b/packages/flutter/test/services/asset_bundle_test.dart
index 4beac89..8a97df3 100644
--- a/packages/flutter/test/services/asset_bundle_test.dart
+++ b/packages/flutter/test/services/asset_bundle_test.dart
@@ -9,14 +9,14 @@
 import 'package:flutter/services.dart';
 import 'package:flutter_test/flutter_test.dart';
 
-class _TestAssetBundle extends CachingAssetBundle {
+class TestAssetBundle extends CachingAssetBundle {
   Map<String, int> loadCallCount = <String, int>{};
 
   @override
   Future<ByteData> load(String key) async {
     loadCallCount[key] = loadCallCount[key] ?? 0 + 1;
-    if (key == 'AssetManifest.bin') {
-      return const StandardMessageCodec().encodeMessage(json.decode('{"one":[]}'))!;
+    if (key == 'AssetManifest.json') {
+      return ByteData.view(Uint8List.fromList(const Utf8Encoder().convert('{"one": ["one"]}')).buffer);
     }
 
     if (key == 'one') {
@@ -30,7 +30,7 @@
   TestWidgetsFlutterBinding.ensureInitialized();
 
   test('Caching asset bundle test', () async {
-    final _TestAssetBundle bundle = _TestAssetBundle();
+    final TestAssetBundle bundle = TestAssetBundle();
 
     final ByteData assetData = await bundle.load('one');
     expect(assetData.getInt8(0), equals(49));
@@ -53,7 +53,7 @@
 
   test('AssetImage.obtainKey succeeds with ImageConfiguration.empty', () async {
     // This is a regression test for https://github.com/flutter/flutter/issues/12392
-    final AssetImage assetImage = AssetImage('one', bundle: _TestAssetBundle());
+    final AssetImage assetImage = AssetImage('one', bundle: TestAssetBundle());
     final AssetBundleImageKey key = await assetImage.obtainKey(ImageConfiguration.empty);
     expect(key.name, 'one');
     expect(key.scale, 1.0);
diff --git a/packages/flutter/test/widgets/image_resolution_test.dart b/packages/flutter/test/widgets/image_resolution_test.dart
index da6ac35..644f2c4 100644
--- a/packages/flutter/test/widgets/image_resolution_test.dart
+++ b/packages/flutter/test/widgets/image_resolution_test.dart
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 @TestOn('!chrome')
-import 'dart:convert';
 import 'dart:ui' as ui show Image;
 
 import 'package:flutter/foundation.dart';
@@ -17,32 +16,27 @@
 ByteData testByteData(double scale) => ByteData(8)..setFloat64(0, scale);
 double scaleOf(ByteData data) => data.getFloat64(0);
 
-final Map<dynamic, dynamic> testManifest = json.decode('''
+const String testManifest = '''
 {
   "assets/image.png" : [
-    {"asset": "assets/1.5x/image.png", "dpr": 1.5},
-    {"asset": "assets/2.0x/image.png", "dpr": 2.0},
-    {"asset": "assets/3.0x/image.png", "dpr": 3.0},
-    {"asset": "assets/4.0x/image.png", "dpr": 4.0}
+    "assets/image.png",
+    "assets/1.5x/image.png",
+    "assets/2.0x/image.png",
+    "assets/3.0x/image.png",
+    "assets/4.0x/image.png"
   ]
 }
-''') as Map<dynamic, dynamic>;
+''';
 
 class TestAssetBundle extends CachingAssetBundle {
+  TestAssetBundle({ this.manifest = testManifest });
 
-  TestAssetBundle({ required Map<dynamic, dynamic> manifest }) {
-    this.manifest = const StandardMessageCodec().encodeMessage(manifest)!;
-  }
-
-  late final ByteData manifest;
+  final String manifest;
 
   @override
   Future<ByteData> load(String key) {
     late ByteData data;
     switch (key) {
-      case 'AssetManifest.bin':
-        data = manifest;
-        break;
       case 'assets/image.png':
         data = testByteData(1.0);
         break;
@@ -66,6 +60,14 @@
   }
 
   @override
+  Future<String> loadString(String key, { bool cache = true }) {
+    if (key == 'AssetManifest.json') {
+      return SynchronousFuture<String>(manifest);
+    }
+    return SynchronousFuture<String>('');
+  }
+
+  @override
   String toString() => '${describeIdentity(this)}()';
 }
 
@@ -104,7 +106,7 @@
       devicePixelRatio: ratio,
     ),
     child: DefaultAssetBundle(
-      bundle: bundle ?? TestAssetBundle(manifest: testManifest),
+      bundle: bundle ?? TestAssetBundle(),
       child: Center(
         child: inferSize ?
           Image(
@@ -257,21 +259,46 @@
     expect(getRenderImage(tester, key).scale, 4.0);
   });
 
+  testWidgets('Image for device pixel ratio 1.0, with no main asset', (WidgetTester tester) async {
+    const String manifest = '''
+    {
+      "assets/image.png" : [
+        "assets/1.5x/image.png",
+        "assets/2.0x/image.png",
+        "assets/3.0x/image.png",
+        "assets/4.0x/image.png"
+      ]
+    }
+    ''';
+    final AssetBundle bundle = TestAssetBundle(manifest: manifest);
+
+    const double ratio = 1.0;
+    Key key = GlobalKey();
+    await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, images, bundle));
+    expect(getRenderImage(tester, key).size, const Size(200.0, 200.0));
+    expect(getRenderImage(tester, key).scale, 1.5);
+    key = GlobalKey();
+    await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true, images, bundle));
+    expect(getRenderImage(tester, key).size, const Size(48.0, 48.0));
+    expect(getRenderImage(tester, key).scale, 1.5);
+  });
+
   testWidgets('Image for device pixel ratio 1.0, with a main asset and a 1.0x asset', (WidgetTester tester) async {
     // If both a main asset and a 1.0x asset are specified, then prefer
     // the 1.0x asset.
 
-    final Map<dynamic, dynamic> manifest = json.decode('''
+    const String manifest = '''
     {
       "assets/image.png" : [
-        {"asset": "assets/1.0x/image.png", "dpr":1.0},
-        {"asset": "assets/1.5x/image.png", "dpr":1.5},
-        {"asset": "assets/2.0x/image.png", "dpr":2.0},
-        {"asset": "assets/3.0x/image.png", "dpr":3.0},
-        {"asset": "assets/4.0x/image.png", "dpr":4.0}
+        "assets/image.png",
+        "assets/1.0x/image.png",
+        "assets/1.5x/image.png",
+        "assets/2.0x/image.png",
+        "assets/3.0x/image.png",
+        "assets/4.0x/image.png"
       ]
     }
-    ''') as Map<dynamic, dynamic>;
+    ''';
     final AssetBundle bundle = TestAssetBundle(manifest: manifest);
 
     const double ratio = 1.0;
@@ -310,13 +337,14 @@
   // if higher resolution assets are not available we will pick the best
   // available.
   testWidgets('Low-resolution assets', (WidgetTester tester) async {
-    final AssetBundle bundle = TestAssetBundle(manifest: json.decode('''
+    final AssetBundle bundle = TestAssetBundle(manifest: '''
       {
         "assets/image.png" : [
-          {"asset": "assets/1.5x/image.png", "dpr": 1.5}
+          "assets/image.png",
+          "assets/1.5x/image.png"
         ]
       }
-    ''') as Map<dynamic, dynamic>);
+    ''');
 
     Future<void> testRatio({required double ratio, required double expectedScale}) async {
       Key key = GlobalKey();
diff --git a/packages/flutter_tools/lib/src/asset.dart b/packages/flutter_tools/lib/src/asset.dart
index 0aed9af..ea0104f 100644
--- a/packages/flutter_tools/lib/src/asset.dart
+++ b/packages/flutter_tools/lib/src/asset.dart
@@ -2,11 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:typed_data';
-
 import 'package:meta/meta.dart';
 import 'package:package_config/package_config.dart';
-import 'package:standard_message_codec/standard_message_codec.dart';
 
 import 'base/context.dart';
 import 'base/deferred_component.dart';
@@ -139,9 +136,6 @@
        _splitDeferredAssets = splitDeferredAssets,
        _licenseCollector = LicenseCollector(fileSystem: fileSystem);
 
-  // We assume the main asset is designed for a device pixel ratio of 1.0
-  static const double _defaultResolution = 1.0;
-
   final Logger _logger;
   final FileSystem _fileSystem;
   final LicenseCollector _licenseCollector;
@@ -167,8 +161,7 @@
 
   DateTime? _lastBuildTimestamp;
 
-  static const String _kAssetManifestBinFileName = 'AssetManifest.bin';
-  static const String _kAssetManifestJsonFileName = 'AssetManifest.json';
+  static const String _kAssetManifestJson = 'AssetManifest.json';
   static const String _kNoticeFile = 'NOTICES';
   // Comically, this can't be name with the more common .gz file extension
   // because when it's part of an AAR and brought into another APK via gradle,
@@ -236,13 +229,8 @@
     // device.
     _lastBuildTimestamp = DateTime.now();
     if (flutterManifest.isEmpty) {
-      entries[_kAssetManifestJsonFileName] = DevFSStringContent('{}');
-      entryKinds[_kAssetManifestJsonFileName] = AssetKind.regular;
-      final ByteData emptyAssetManifest =
-        const StandardMessageCodec().encodeMessage(<dynamic, dynamic>{})!;
-      entries[_kAssetManifestBinFileName] =
-        DevFSByteContent(emptyAssetManifest.buffer.asUint8List(0, emptyAssetManifest.lengthInBytes));
-      entryKinds[_kAssetManifestBinFileName] = AssetKind.regular;
+      entries[_kAssetManifestJson] = DevFSStringContent('{}');
+      entryKinds[_kAssetManifestJson] = AssetKind.regular;
       return 0;
     }
 
@@ -439,11 +427,7 @@
       _wildcardDirectories[uri] ??= _fileSystem.directory(uri);
     }
 
-    final Map<String, List<String>> assetManifest =
-      _createAssetManifest(assetVariants, deferredComponentsAssetVariants);
-    final DevFSStringContent assetManifestJson = DevFSStringContent(json.encode(assetManifest));
-    final DevFSByteContent assetManifestBinary = _createAssetManifestBinary(assetManifest);
-
+    final DevFSStringContent assetManifest  = _createAssetManifest(assetVariants, deferredComponentsAssetVariants);
     final DevFSStringContent fontManifest = DevFSStringContent(json.encode(fonts));
     final LicenseResult licenseResult = _licenseCollector.obtainLicenses(packageConfig, additionalLicenseFiles);
     if (licenseResult.errorMessages.isNotEmpty) {
@@ -467,8 +451,7 @@
         _fileSystem.file('DOES_NOT_EXIST_RERUN_FOR_WILDCARD$suffix').absolute);
     }
 
-    _setIfChanged(_kAssetManifestJsonFileName, assetManifestJson, AssetKind.regular);
-    _setIfChanged(_kAssetManifestBinFileName, assetManifestBinary, AssetKind.regular);
+    _setIfChanged(_kAssetManifestJson, assetManifest, AssetKind.regular);
     _setIfChanged(kFontManifestJson, fontManifest, AssetKind.regular);
     _setLicenseIfChanged(licenseResult.combinedLicenses, targetPlatform);
     return 0;
@@ -477,31 +460,17 @@
   @override
   List<File> additionalDependencies = <File>[];
 
-  void _setIfChanged(String key, DevFSContent content, AssetKind assetKind) {
-    bool areEqual(List<int> o1, List<int> o2) {
-      if (o1.length != o2.length) {
-        return false;
-      }
-
-      for (int index = 0; index < o1.length; index++) {
-        if (o1[index] != o2[index]) {
-          return false;
-        }
-      }
-
-      return true;
-    }
-
-    final DevFSContent? oldContent = entries[key];
-    // In the case that the content is unchanged, we want to avoid an overwrite
-    // as the isModified property may be reset to true,
-    if (oldContent is DevFSByteContent && content is DevFSByteContent &&
-        areEqual(oldContent.bytes, content.bytes)) {
+  void _setIfChanged(String key, DevFSStringContent content, AssetKind assetKind) {
+    if (!entries.containsKey(key)) {
+      entries[key] = content;
+      entryKinds[key] = assetKind;
       return;
     }
-
-    entries[key] = content;
-    entryKinds[key] = assetKind;
+    final DevFSStringContent? oldContent = entries[key] as DevFSStringContent?;
+    if (oldContent?.string != content.string) {
+      entries[key] = content;
+      entryKinds[key] = assetKind;
+    }
   }
 
   void _setLicenseIfChanged(
@@ -653,14 +622,14 @@
     return deferredComponentsAssetVariants;
   }
 
-  Map<String, List<String>> _createAssetManifest(
+  DevFSStringContent _createAssetManifest(
     Map<_Asset, List<_Asset>> assetVariants,
     Map<String, Map<_Asset, List<_Asset>>> deferredComponentsAssetVariants
   ) {
-    final Map<String, List<String>> manifest = <String, List<String>>{};
-    final Map<_Asset, List<String>> entries = <_Asset, List<String>>{};
+    final Map<String, List<String>> jsonObject = <String, List<String>>{};
+    final Map<_Asset, List<String>> jsonEntries = <_Asset, List<String>>{};
     assetVariants.forEach((_Asset main, List<_Asset> variants) {
-      entries[main] = <String>[
+      jsonEntries[main] = <String>[
         for (final _Asset variant in variants)
           variant.entryUri.path,
       ];
@@ -668,69 +637,26 @@
     if (deferredComponentsAssetVariants != null) {
       for (final Map<_Asset, List<_Asset>> componentAssets in deferredComponentsAssetVariants.values) {
         componentAssets.forEach((_Asset main, List<_Asset> variants) {
-          entries[main] = <String>[
+          jsonEntries[main] = <String>[
             for (final _Asset variant in variants)
               variant.entryUri.path,
           ];
         });
       }
     }
-    final List<_Asset> sortedKeys = entries.keys.toList()
+    final List<_Asset> sortedKeys = jsonEntries.keys.toList()
         ..sort((_Asset left, _Asset right) => left.entryUri.path.compareTo(right.entryUri.path));
     for (final _Asset main in sortedKeys) {
       final String decodedEntryPath = Uri.decodeFull(main.entryUri.path);
-      final List<String> rawEntryVariantsPaths = entries[main]!;
+      final List<String> rawEntryVariantsPaths = jsonEntries[main]!;
       final List<String> decodedEntryVariantPaths = rawEntryVariantsPaths
         .map((String value) => Uri.decodeFull(value))
         .toList();
-      manifest[decodedEntryPath] = decodedEntryVariantPaths;
+      jsonObject[decodedEntryPath] = decodedEntryVariantPaths;
     }
-    return manifest;
+    return DevFSStringContent(json.encode(jsonObject));
   }
 
-  DevFSByteContent _createAssetManifestBinary(
-    Map<String, List<String>> assetManifest
-  ) {
-    double parseScale(String key) {
-      final Uri assetUri = Uri.parse(key);
-      String directoryPath = '';
-      if (assetUri.pathSegments.length > 1) {
-        directoryPath = assetUri.pathSegments[assetUri.pathSegments.length - 2];
-      }
-
-      final Match? match = _extractRatioRegExp.firstMatch(directoryPath);
-      if (match != null && match.groupCount > 0) {
-        return double.parse(match.group(1)!);
-      }
-      return _defaultResolution;
-    }
-
-    final Map<String, dynamic> result = <String, dynamic>{};
-
-    for (final MapEntry<String, dynamic> manifestEntry in assetManifest.entries) {
-      final List<dynamic> resultVariants = <dynamic>[];
-      final List<String> entries = (manifestEntry.value as List<dynamic>).cast<String>();
-      for (final String variant in entries) {
-        if (variant == manifestEntry.key) {
-          // With the newer binary format, don't include the main asset in it's
-          // list of variants. This reduces parsing time at runtime.
-          continue;
-        }
-        final Map<String, dynamic> resultVariant = <String, dynamic>{};
-        final double variantDevicePixelRatio = parseScale(variant);
-        resultVariant['asset'] = variant;
-        resultVariant['dpr'] = variantDevicePixelRatio;
-        resultVariants.add(resultVariant);
-      }
-      result[manifestEntry.key] = resultVariants;
-    }
-
-    final ByteData message = const StandardMessageCodec().encodeMessage(result)!;
-    return DevFSByteContent(message.buffer.asUint8List(0, message.lengthInBytes));
-  }
-
-  static final RegExp _extractRatioRegExp = RegExp(r'/?(\d+(\.\d*)?)x$');
-
   /// Prefixes family names and asset paths of fonts included from packages with
   /// 'packages/<package_name>'
   List<Font> _parsePackageFonts(
diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml
index aa69dcc..91dafbe 100644
--- a/packages/flutter_tools/pubspec.yaml
+++ b/packages/flutter_tools/pubspec.yaml
@@ -57,8 +57,6 @@
 
   vm_service: 9.4.0
 
-  standard_message_codec: 0.0.1+3
-
   _fe_analyzer_shared: 50.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
   analyzer: 5.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
   boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -90,6 +88,7 @@
   watcher: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
 
 dev_dependencies:
+  collection: 1.17.0
   file_testing: 3.0.0
   pubspec_parse: 1.2.1
 
@@ -98,10 +97,9 @@
   json_annotation: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
   node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
   test: 1.22.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
-  collection: 1.17.0
 
 dartdoc:
   # Exclude this package from the hosted API docs.
   nodoc: true
 
-# PUBSPEC CHECKSUM: 408d
+# PUBSPEC CHECKSUM: 65eb
diff --git a/packages/flutter_tools/test/general.shard/android/deferred_components_gen_snapshot_validator_test.dart b/packages/flutter_tools/test/general.shard/android/deferred_components_gen_snapshot_validator_test.dart
index 9366653..6962b50 100644
--- a/packages/flutter_tools/test/general.shard/android/deferred_components_gen_snapshot_validator_test.dart
+++ b/packages/flutter_tools/test/general.shard/android/deferred_components_gen_snapshot_validator_test.dart
@@ -220,7 +220,7 @@
     expect(logger.statusText, contains('Errors checking the following files:'));
     expect(logger.statusText, contains("Invalid loading units yaml file, 'loading-units' entry did not exist."));
 
-    expect(logger.statusText, isNot(contains('Previously existing loading units no longer exist:\n\n  LoadingUnit 2\n    Libraries:\n    - lib1\n')));
+    expect(logger.statusText.contains('Previously existing loading units no longer exist:\n\n  LoadingUnit 2\n    Libraries:\n    - lib1\n'), false);
   });
 
   testWithoutContext('loadingUnitCache validator detects malformed file: not a list', () async {
@@ -382,7 +382,7 @@
     validator.displayResults();
     validator.attemptToolExit();
 
-    expect(logger.statusText, isNot(contains('Errors checking the following files:')));
+    expect(logger.statusText.contains('Errors checking the following files:'), false);
   });
 
   testWithoutContext('androidStringMapping modifies strings file', () async {
@@ -448,10 +448,9 @@
       .childDirectory('main')
       .childFile('AndroidManifest.xml');
     expect(manifestOutput.existsSync(), true);
-    final String manifestOutputString = manifestOutput.readAsStringSync();
-    expect(manifestOutputString, contains('<meta-data android:name="io.flutter.embedding.engine.deferredcomponents.DeferredComponentManager.loadingUnitMapping" android:value="3:component1,2:component2,4:component2"/>'));
-    expect(manifestOutputString, isNot(contains('android:value="invalidmapping"')));
-    expect(manifestOutputString, contains("<!-- Don't delete the meta-data below."));
+    expect(manifestOutput.readAsStringSync().contains('<meta-data android:name="io.flutter.embedding.engine.deferredcomponents.DeferredComponentManager.loadingUnitMapping" android:value="3:component1,2:component2,4:component2"/>'), true);
+    expect(manifestOutput.readAsStringSync().contains('android:value="invalidmapping"'), false);
+    expect(manifestOutput.readAsStringSync().contains("<!-- Don't delete the meta-data below."), true);
   });
 
   testWithoutContext('androidStringMapping adds mapping when no existing mapping', () async {
@@ -696,8 +695,8 @@
       .childDirectory('main')
       .childFile('AndroidManifest.xml');
     expect(manifestOutput.existsSync(), true);
-    expect(manifestOutput.readAsStringSync(), contains('<meta-data android:name="io.flutter.embedding.engine.deferredcomponents.DeferredComponentManager.loadingUnitMapping" android:value="3:component1,2:component2,4:component2"/>'));
-    expect(manifestOutput.readAsStringSync(), isNot(contains(RegExp(r'android:value[\s\n]*=[\s\n]*"invalidmapping"'))));
-    expect(manifestOutput.readAsStringSync(), contains("<!-- Don't delete the meta-data below."));
+    expect(manifestOutput.readAsStringSync().contains('<meta-data android:name="io.flutter.embedding.engine.deferredcomponents.DeferredComponentManager.loadingUnitMapping" android:value="3:component1,2:component2,4:component2"/>'), true);
+    expect(manifestOutput.readAsStringSync().contains(RegExp(r'android:value[\s\n]*=[\s\n]*"invalidmapping"')), false);
+    expect(manifestOutput.readAsStringSync().contains("<!-- Don't delete the meta-data below."), true);
   });
 }
diff --git a/packages/flutter_tools/test/general.shard/asset_bundle_package_fonts_test.dart b/packages/flutter_tools/test/general.shard/asset_bundle_package_fonts_test.dart
index 4676d68..f44cd20 100644
--- a/packages/flutter_tools/test/general.shard/asset_bundle_package_fonts_test.dart
+++ b/packages/flutter_tools/test/general.shard/asset_bundle_package_fonts_test.dart
@@ -111,9 +111,8 @@
 
       final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
       await bundle.build(packagesPath: '.packages');
-      expect(bundle.entries.keys, containsAll(
-        <String>['AssetManifest.bin', 'AssetManifest.json', 'FontManifest.json', 'NOTICES.Z']
-      ));
+      expect(bundle.entries.length, 3); // LICENSE, AssetManifest, FontManifest
+      expect(bundle.entries.containsKey('FontManifest.json'), isTrue);
     }, overrides: <Type, Generator>{
       FileSystem: () => testFileSystem,
       ProcessManager: () => FakeProcessManager.any(),
diff --git a/packages/flutter_tools/test/general.shard/asset_bundle_package_test.dart b/packages/flutter_tools/test/general.shard/asset_bundle_package_test.dart
index 2070a75..5c2ef1d 100644
--- a/packages/flutter_tools/test/general.shard/asset_bundle_package_test.dart
+++ b/packages/flutter_tools/test/general.shard/asset_bundle_package_test.dart
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 import 'dart:convert';
-import 'dart:typed_data';
 
 import 'package:file/file.dart';
 import 'package:file/memory.dart';
@@ -12,7 +11,6 @@
 import 'package:flutter_tools/src/base/file_system.dart';
 
 import 'package:flutter_tools/src/globals.dart' as globals;
-import 'package:standard_message_codec/standard_message_codec.dart';
 
 import '../src/common.dart';
 import '../src/context.dart';
@@ -26,7 +24,6 @@
     // rolls into Flutter.
     return path.replaceAll('/', globals.fs.path.separator);
   }
-
   void writePubspecFile(String path, String name, { List<String>? assets }) {
     String assetsSection;
     if (assets == null) {
@@ -63,6 +60,37 @@
       ..writeAsStringSync(packages);
   }
 
+  Future<void> buildAndVerifyAssets(
+    List<String> assets,
+    List<String> packages,
+    String? expectedAssetManifest, {
+    bool expectExists = true,
+  }) async {
+    final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
+    await bundle.build(packagesPath: '.packages');
+
+    for (final String packageName in packages) {
+      for (final String asset in assets) {
+        final String entryKey = Uri.encodeFull('packages/$packageName/$asset');
+        expect(bundle.entries.containsKey(entryKey), expectExists,
+          reason: 'Cannot find key on bundle: $entryKey');
+        if (expectExists) {
+          expect(
+            utf8.decode(await bundle.entries[entryKey]!.contentsAsBytes()),
+            asset,
+          );
+        }
+      }
+    }
+
+    if (expectExists) {
+      expect(
+        utf8.decode(await bundle.entries['AssetManifest.json']!.contentsAsBytes()),
+        expectedAssetManifest,
+      );
+    }
+  }
+
   void writeAssets(String path, List<String> assets) {
     for (final String asset in assets) {
       final String fullPath = fixPath(globals.fs.path.join(path, asset));
@@ -73,391 +101,71 @@
     }
   }
 
-  // TODO(andrewkolos): Delete this group once we stop producing AssetManifest.json
-  // as part of build.
-  group('Legacy asset manifest (AssetManifest.json)', () {
-    Future<void> buildAndVerifyAssets(
-      List<String> assets,
-      List<String> packages,
-      String? expectedAssetManifest, {
-      bool expectExists = true,
-    }) async {
+  late FileSystem testFileSystem;
+
+  setUp(() async {
+    testFileSystem = MemoryFileSystem(
+      style: globals.platform.isWindows
+        ? FileSystemStyle.windows
+        : FileSystemStyle.posix,
+    );
+    testFileSystem.currentDirectory = testFileSystem.systemTempDirectory.createTempSync('flutter_asset_bundle_test.');
+  });
+
+  group('AssetBundle assets from packages', () {
+    testUsingContext('No assets are bundled when the package has no assets', () async {
+      writePubspecFile('pubspec.yaml', 'test');
+      writePackagesFile('test_package:p/p/lib/');
+      writePubspecFile('p/p/pubspec.yaml', 'test_package');
+
       final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
       await bundle.build(packagesPath: '.packages');
-
-      for (final String packageName in packages) {
-        for (final String asset in assets) {
-          final String entryKey = Uri.encodeFull('packages/$packageName/$asset');
-          expect(bundle.entries.containsKey(entryKey), expectExists,
-            reason: 'Cannot find key on bundle: $entryKey');
-          if (expectExists) {
-            expect(
-              utf8.decode(await bundle.entries[entryKey]!.contentsAsBytes()),
-              asset,
-            );
-          }
-        }
-      }
-
-      if (expectExists) {
-        expect(
-          utf8.decode(await bundle.entries['AssetManifest.json']!.contentsAsBytes()),
-          expectedAssetManifest,
-        );
-      }
-    }
-
-    late FileSystem testFileSystem;
-
-    setUp(() async {
-      testFileSystem = MemoryFileSystem(
-        style: globals.platform.isWindows
-          ? FileSystemStyle.windows
-          : FileSystemStyle.posix,
+      expect(bundle.entries.length, 3); // LICENSE, AssetManifest, FontManifest
+      const String expectedAssetManifest = '{}';
+      expect(
+        utf8.decode(await bundle.entries['AssetManifest.json']!.contentsAsBytes()),
+        expectedAssetManifest,
       );
-      testFileSystem.currentDirectory = testFileSystem.systemTempDirectory.createTempSync('flutter_asset_bundle_test.');
+      expect(
+        utf8.decode(await bundle.entries['FontManifest.json']!.contentsAsBytes()),
+        '[]',
+      );
+    }, overrides: <Type, Generator>{
+      FileSystem: () => testFileSystem,
+      ProcessManager: () => FakeProcessManager.any(),
     });
 
-    group('AssetBundle assets from packages', () {
-      testUsingContext('No assets are bundled when the package has no assets', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
-        writePubspecFile('p/p/pubspec.yaml', 'test_package');
+    testUsingContext('No assets are bundled when the package has an asset that is not listed', () async {
+      writePubspecFile('pubspec.yaml', 'test');
+      writePackagesFile('test_package:p/p/lib/');
+      writePubspecFile('p/p/pubspec.yaml', 'test_package');
 
-        final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
-        await bundle.build(packagesPath: '.packages');
-        expect(bundle.entries.keys, unorderedEquals(
-          <String>['AssetManifest.bin', 'AssetManifest.json', 'FontManifest.json', 'NOTICES.Z']
-        ));
-        const String expectedAssetManifest = '{}';
-        expect(
-          utf8.decode(await bundle.entries['AssetManifest.json']!.contentsAsBytes()),
-          expectedAssetManifest,
-        );
-        expect(
-          utf8.decode(await bundle.entries['FontManifest.json']!.contentsAsBytes()),
-          '[]',
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
+      final List<String> assets = <String>['a/foo'];
+      writeAssets('p/p/', assets);
 
-      testUsingContext('No assets are bundled when the package has an asset that is not listed', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
-        writePubspecFile('p/p/pubspec.yaml', 'test_package');
-
-        final List<String> assets = <String>['a/foo'];
-        writeAssets('p/p/', assets);
-
-        final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
-        await bundle.build(packagesPath: '.packages');
-        expect(bundle.entries.keys, unorderedEquals(
-          <String>['AssetManifest.bin', 'AssetManifest.json', 'FontManifest.json', 'NOTICES.Z']
-        ));
-        const String expectedAssetManifest = '{}';
-        expect(
-          utf8.decode(await bundle.entries['AssetManifest.json']!.contentsAsBytes()),
-          expectedAssetManifest,
-        );
-        expect(
-          utf8.decode(await bundle.entries['FontManifest.json']!.contentsAsBytes()),
-          '[]',
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('One asset is bundled when the package has and lists one '
-        'asset its pubspec', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
-
-        final List<String> assets = <String>['a/foo'];
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: assets,
-        );
-
-        writeAssets('p/p/', assets);
-
-        const String expectedAssetManifest = '{"packages/test_package/a/foo":'
-            '["packages/test_package/a/foo"]}';
-        await buildAndVerifyAssets(
-          assets,
-          <String>['test_package'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('One asset is bundled when the package has one asset, '
-        "listed in the app's pubspec", () async {
-        final List<String> assetEntries = <String>['packages/test_package/a/foo'];
-        writePubspecFile(
-          'pubspec.yaml',
-          'test',
-          assets: assetEntries,
-        );
-        writePackagesFile('test_package:p/p/lib/');
-        writePubspecFile('p/p/pubspec.yaml', 'test_package');
-
-        final List<String> assets = <String>['a/foo'];
-        writeAssets('p/p/lib/', assets);
-
-        const String expectedAssetManifest = '{"packages/test_package/a/foo":'
-            '["packages/test_package/a/foo"]}';
-        await buildAndVerifyAssets(
-          assets,
-          <String>['test_package'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('One asset and its variant are bundled when the package '
-        'has an asset and a variant, and lists the asset in its pubspec', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: <String>['a/foo', 'a/bar'],
-        );
-
-        final List<String> assets = <String>['a/foo', 'a/2x/foo', 'a/bar'];
-        writeAssets('p/p/', assets);
-
-        const String expectedManifest = '{'
-            '"packages/test_package/a/bar":'
-            '["packages/test_package/a/bar"],'
-            '"packages/test_package/a/foo":'
-            '["packages/test_package/a/foo","packages/test_package/a/2x/foo"]'
-            '}';
-
-        await buildAndVerifyAssets(
-          assets,
-          <String>['test_package'],
-          expectedManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('One asset and its variant are bundled when the package '
-        'has an asset and a variant, and the app lists the asset in its pubspec', () async {
-        writePubspecFile(
-          'pubspec.yaml',
-          'test',
-          assets: <String>['packages/test_package/a/foo'],
-        );
-        writePackagesFile('test_package:p/p/lib/');
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-        );
-
-        final List<String> assets = <String>['a/foo', 'a/2x/foo'];
-        writeAssets('p/p/lib/', assets);
-
-        const String expectedManifest = '{"packages/test_package/a/foo":'
-            '["packages/test_package/a/foo","packages/test_package/a/2x/foo"]}';
-
-        await buildAndVerifyAssets(
-          assets,
-          <String>['test_package'],
-          expectedManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('Two assets are bundled when the package has and lists '
-        'two assets in its pubspec', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
-
-        final List<String> assets = <String>['a/foo', 'a/bar'];
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: assets,
-        );
-
-        writeAssets('p/p/', assets);
-        const String expectedAssetManifest =
-            '{"packages/test_package/a/bar":["packages/test_package/a/bar"],'
-            '"packages/test_package/a/foo":["packages/test_package/a/foo"]}';
-
-        await buildAndVerifyAssets(
-          assets,
-          <String>['test_package'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext("Two assets are bundled when the package has two assets, listed in the app's pubspec", () async {
-        final List<String> assetEntries = <String>[
-          'packages/test_package/a/foo',
-          'packages/test_package/a/bar',
-        ];
-        writePubspecFile(
-          'pubspec.yaml',
-          'test',
-          assets: assetEntries,
-        );
-        writePackagesFile('test_package:p/p/lib/');
-
-        final List<String> assets = <String>['a/foo', 'a/bar'];
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-        );
-
-        writeAssets('p/p/lib/', assets);
-        const String expectedAssetManifest =
-            '{"packages/test_package/a/bar":["packages/test_package/a/bar"],'
-            '"packages/test_package/a/foo":["packages/test_package/a/foo"]}';
-
-        await buildAndVerifyAssets(
-          assets,
-          <String>['test_package'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('Two assets are bundled when two packages each have and list an asset their pubspec', () async {
-        writePubspecFile(
-          'pubspec.yaml',
-          'test',
-        );
-        writePackagesFile('test_package:p/p/lib/\ntest_package2:p2/p/lib/');
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: <String>['a/foo'],
-        );
-        writePubspecFile(
-          'p2/p/pubspec.yaml',
-          'test_package2',
-          assets: <String>['a/foo'],
-        );
-
-        final List<String> assets = <String>['a/foo', 'a/2x/foo'];
-        writeAssets('p/p/', assets);
-        writeAssets('p2/p/', assets);
-
-        const String expectedAssetManifest =
-            '{"packages/test_package/a/foo":'
-            '["packages/test_package/a/foo","packages/test_package/a/2x/foo"],'
-            '"packages/test_package2/a/foo":'
-            '["packages/test_package2/a/foo","packages/test_package2/a/2x/foo"]}';
-
-        await buildAndVerifyAssets(
-          assets,
-          <String>['test_package', 'test_package2'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext("Two assets are bundled when two packages each have an asset, listed in the app's pubspec", () async {
-        final List<String> assetEntries = <String>[
-          'packages/test_package/a/foo',
-          'packages/test_package2/a/foo',
-        ];
-        writePubspecFile(
-          'pubspec.yaml',
-          'test',
-          assets: assetEntries,
-        );
-        writePackagesFile('test_package:p/p/lib/\ntest_package2:p2/p/lib/');
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-        );
-        writePubspecFile(
-          'p2/p/pubspec.yaml',
-          'test_package2',
-        );
-
-        final List<String> assets = <String>['a/foo', 'a/2x/foo'];
-        writeAssets('p/p/lib/', assets);
-        writeAssets('p2/p/lib/', assets);
-
-        const String expectedAssetManifest =
-            '{"packages/test_package/a/foo":'
-            '["packages/test_package/a/foo","packages/test_package/a/2x/foo"],'
-            '"packages/test_package2/a/foo":'
-            '["packages/test_package2/a/foo","packages/test_package2/a/2x/foo"]}';
-
-        await buildAndVerifyAssets(
-          assets,
-          <String>['test_package', 'test_package2'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('One asset is bundled when the app depends on a package, '
-        'listing in its pubspec an asset from another package', () async {
-        writePubspecFile(
-          'pubspec.yaml',
-          'test',
-        );
-        writePackagesFile('test_package:p/p/lib/\ntest_package2:p2/p/lib/');
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: <String>['packages/test_package2/a/foo'],
-        );
-        writePubspecFile(
-          'p2/p/pubspec.yaml',
-          'test_package2',
-        );
-
-        final List<String> assets = <String>['a/foo', 'a/2x/foo'];
-        writeAssets('p2/p/lib/', assets);
-
-        const String expectedAssetManifest =
-            '{"packages/test_package2/a/foo":'
-            '["packages/test_package2/a/foo","packages/test_package2/a/2x/foo"]}';
-
-        await buildAndVerifyAssets(
-          assets,
-          <String>['test_package2'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
+      final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
+      await bundle.build(packagesPath: '.packages');
+      expect(bundle.entries.length, 3); // LICENSE, AssetManifest, FontManifest
+      const String expectedAssetManifest = '{}';
+      expect(
+        utf8.decode(await bundle.entries['AssetManifest.json']!.contentsAsBytes()),
+        expectedAssetManifest,
+      );
+      expect(
+        utf8.decode(await bundle.entries['FontManifest.json']!.contentsAsBytes()),
+        '[]',
+      );
+    }, overrides: <Type, Generator>{
+      FileSystem: () => testFileSystem,
+      ProcessManager: () => FakeProcessManager.any(),
     });
 
-    testUsingContext('Asset paths can contain URL reserved characters', () async {
+    testUsingContext('One asset is bundled when the package has and lists one '
+      'asset its pubspec', () async {
       writePubspecFile('pubspec.yaml', 'test');
       writePackagesFile('test_package:p/p/lib/');
 
-      final List<String> assets = <String>['a/foo', 'a/foo [x]'];
+      final List<String> assets = <String>['a/foo'];
       writePubspecFile(
         'p/p/pubspec.yaml',
         'test_package',
@@ -465,10 +173,9 @@
       );
 
       writeAssets('p/p/', assets);
-      const String expectedAssetManifest =
-          '{"packages/test_package/a/foo":["packages/test_package/a/foo"],'
-          '"packages/test_package/a/foo [x]":["packages/test_package/a/foo [x]"]}';
 
+      const String expectedAssetManifest = '{"packages/test_package/a/foo":'
+          '["packages/test_package/a/foo"]}';
       await buildAndVerifyAssets(
         assets,
         <String>['test_package'],
@@ -476,571 +183,100 @@
       );
     }, overrides: <Type, Generator>{
       FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
+      ProcessManager: () => FakeProcessManager.any(),
     });
 
-    group('AssetBundle assets from scanned paths', () {
-      testUsingContext('Two assets are bundled when scanning their directory', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
-
-        final List<String> assetsOnDisk = <String>['a/foo', 'a/bar'];
-        final List<String> assetsOnManifest = <String>['a/'];
-
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: assetsOnManifest,
-        );
-
-        writeAssets('p/p/', assetsOnDisk);
-        const String expectedAssetManifest =
-            '{"packages/test_package/a/bar":["packages/test_package/a/bar"],'
-            '"packages/test_package/a/foo":["packages/test_package/a/foo"]}';
-
-        await buildAndVerifyAssets(
-          assetsOnDisk,
-          <String>['test_package'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('Two assets are bundled when listing one and scanning second directory', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
-
-        final List<String> assetsOnDisk = <String>['a/foo', 'abc/bar'];
-        final List<String> assetOnManifest = <String>['a/foo', 'abc/'];
-
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: assetOnManifest,
-        );
-
-        writeAssets('p/p/', assetsOnDisk);
-        const String expectedAssetManifest =
-            '{"packages/test_package/a/foo":["packages/test_package/a/foo"],'
-            '"packages/test_package/abc/bar":["packages/test_package/abc/bar"]}';
-
-        await buildAndVerifyAssets(
-          assetsOnDisk,
-          <String>['test_package'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('One asset is bundled with variant, scanning wrong directory', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
-
-        final List<String> assetsOnDisk = <String>['a/foo','a/b/foo','a/bar'];
-        final List<String> assetOnManifest = <String>['a','a/bar']; // can't list 'a' as asset, should be 'a/'
-
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: assetOnManifest,
-        );
-
-        writeAssets('p/p/', assetsOnDisk);
-
-        final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
-        await bundle.build(packagesPath: '.packages');
-
-        expect(bundle.entries['AssetManifest.bin'], isNull,
-          reason: 'Invalid pubspec.yaml should not generate AssetManifest.bin'  );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-    });
-
-    group('AssetBundle assets from scanned paths with MemoryFileSystem', () {
-      testUsingContext('One asset is bundled with variant, scanning directory', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
-
-        final List<String> assetsOnDisk = <String>['a/foo','a/2x/foo'];
-        final List<String> assetOnManifest = <String>['a/',];
-
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: assetOnManifest,
-        );
-
-        writeAssets('p/p/', assetsOnDisk);
-        const String expectedAssetManifest =
-            '{"packages/test_package/a/foo":["packages/test_package/a/foo","packages/test_package/a/2x/foo"]}';
-
-        await buildAndVerifyAssets(
-          assetsOnDisk,
-          <String>['test_package'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('No asset is bundled with variant, no assets or directories are listed', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
-
-        final List<String> assetsOnDisk = <String>['a/foo', 'a/2x/foo'];
-        final List<String> assetOnManifest = <String>[];
-
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: assetOnManifest,
-        );
-
-        writeAssets('p/p/', assetsOnDisk);
-        const String expectedAssetManifest = '{}';
-
-        await buildAndVerifyAssets(
-          assetOnManifest,
-          <String>['test_package'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('Expect error generating manifest, wrong non-existing directory is listed', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
-
-        final List<String> assetOnManifest = <String>['c/'];
-
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: assetOnManifest,
-        );
-
-        await buildAndVerifyAssets(
-          assetOnManifest,
-          <String>['test_package'],
-          null,
-          expectExists: false,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-    });
-  });
-  group('Current asset manifest (AssetManifest.bin)', () {
-    Future<String> extractAssetManifestFromBundleAsJson(AssetBundle bundle) async {
-      final List<int> manifestBytes = await bundle.entries['AssetManifest.bin']!.contentsAsBytes();
-      return json.encode(const StandardMessageCodec().decodeMessage(
-        ByteData.sublistView(Uint8List.fromList(manifestBytes))
-      ));
-    }
-
-    Future<void> buildAndVerifyAssets(
-      List<String> assets,
-      List<String> packages,
-      String? expectedAssetManifest, {
-      bool expectExists = true,
-    }) async {
-      final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
-      await bundle.build(packagesPath: '.packages');
-
-      for (final String packageName in packages) {
-        for (final String asset in assets) {
-          final String entryKey = Uri.encodeFull('packages/$packageName/$asset');
-          expect(bundle.entries.containsKey(entryKey), expectExists,
-            reason: 'Cannot find key on bundle: $entryKey');
-          if (expectExists) {
-            expect(
-              utf8.decode(await bundle.entries[entryKey]!.contentsAsBytes()),
-              asset,
-            );
-          }
-        }
-      }
-
-      if (expectExists) {
-        final String actualAssetManifest = await extractAssetManifestFromBundleAsJson(bundle);
-        expect(
-          actualAssetManifest,
-          expectedAssetManifest,
-        );
-      }
-    }
-
-    void writeAssets(String path, List<String> assets) {
-      for (final String asset in assets) {
-        final String fullPath = fixPath(globals.fs.path.join(path, asset));
-
-        globals.fs.file(fullPath)
-          ..createSync(recursive: true)
-          ..writeAsStringSync(asset);
-      }
-    }
-
-    late FileSystem testFileSystem;
-
-    setUp(() async {
-      testFileSystem = MemoryFileSystem(
-        style: globals.platform.isWindows
-          ? FileSystemStyle.windows
-          : FileSystemStyle.posix,
+    testUsingContext('One asset is bundled when the package has one asset, '
+      "listed in the app's pubspec", () async {
+      final List<String> assetEntries = <String>['packages/test_package/a/foo'];
+      writePubspecFile(
+        'pubspec.yaml',
+        'test',
+        assets: assetEntries,
       );
-      testFileSystem.currentDirectory = testFileSystem.systemTempDirectory.createTempSync('flutter_asset_bundle_test.');
+      writePackagesFile('test_package:p/p/lib/');
+      writePubspecFile('p/p/pubspec.yaml', 'test_package');
+
+      final List<String> assets = <String>['a/foo'];
+      writeAssets('p/p/lib/', assets);
+
+      const String expectedAssetManifest = '{"packages/test_package/a/foo":'
+          '["packages/test_package/a/foo"]}';
+      await buildAndVerifyAssets(
+        assets,
+        <String>['test_package'],
+        expectedAssetManifest,
+      );
+    }, overrides: <Type, Generator>{
+      FileSystem: () => testFileSystem,
+      ProcessManager: () => FakeProcessManager.any(),
     });
 
-    group('AssetBundle assets from packages', () {
-      testUsingContext('No assets are bundled when the package has no assets', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
-        writePubspecFile('p/p/pubspec.yaml', 'test_package');
+    testUsingContext('One asset and its variant are bundled when the package '
+      'has an asset and a variant, and lists the asset in its pubspec', () async {
+      writePubspecFile('pubspec.yaml', 'test');
+      writePackagesFile('test_package:p/p/lib/');
+      writePubspecFile(
+        'p/p/pubspec.yaml',
+        'test_package',
+        assets: <String>['a/foo', 'a/bar'],
+      );
 
-        final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
-        await bundle.build(packagesPath: '.packages');
-        expect(bundle.entries.keys, unorderedEquals(
-          <String>['AssetManifest.bin', 'AssetManifest.json', 'FontManifest.json', 'NOTICES.Z']
-        ));
-        final String actualAssetManifest = await extractAssetManifestFromBundleAsJson(bundle);
-        const String expectedAssetManifest = '{}';
-        expect(
-          actualAssetManifest,
-          expectedAssetManifest,
-        );
-        expect(
-          utf8.decode(await bundle.entries['FontManifest.json']!.contentsAsBytes()),
-          '[]',
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
+      final List<String> assets = <String>['a/foo', 'a/2x/foo', 'a/bar'];
+      writeAssets('p/p/', assets);
 
-      testUsingContext('No assets are bundled when the package has an asset that is not listed', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
-        writePubspecFile('p/p/pubspec.yaml', 'test_package');
+      const String expectedManifest = '{'
+          '"packages/test_package/a/bar":'
+          '["packages/test_package/a/bar"],'
+          '"packages/test_package/a/foo":'
+          '["packages/test_package/a/foo","packages/test_package/a/2x/foo"]'
+          '}';
 
-        final List<String> assets = <String>['a/foo'];
-        writeAssets('p/p/', assets);
-
-        final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
-        await bundle.build(packagesPath: '.packages');
-        expect(bundle.entries.keys, unorderedEquals(
-          <String>['AssetManifest.bin', 'AssetManifest.json', 'FontManifest.json', 'NOTICES.Z']
-        ));
-        final String actualAssetManifest = await extractAssetManifestFromBundleAsJson(bundle);
-        const String expectedAssetManifest = '{}';
-        expect(
-          actualAssetManifest,
-          expectedAssetManifest,
-        );
-        expect(
-          utf8.decode(await bundle.entries['FontManifest.json']!.contentsAsBytes()),
-          '[]',
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('One asset is bundled when the package has and lists one '
-        'asset its pubspec', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
-
-        final List<String> assets = <String>['a/foo'];
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: assets,
-        );
-
-        writeAssets('p/p/', assets);
-
-        const String expectedAssetManifest = '{"packages/test_package/a/foo":'
-            '[]}';
-        await buildAndVerifyAssets(
-          assets,
-          <String>['test_package'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('One asset is bundled when the package has one asset, '
-        "listed in the app's pubspec", () async {
-        final List<String> assetEntries = <String>['packages/test_package/a/foo'];
-        writePubspecFile(
-          'pubspec.yaml',
-          'test',
-          assets: assetEntries,
-        );
-        writePackagesFile('test_package:p/p/lib/');
-        writePubspecFile('p/p/pubspec.yaml', 'test_package');
-
-        final List<String> assets = <String>['a/foo'];
-        writeAssets('p/p/lib/', assets);
-
-        const String expectedAssetManifest = '{"packages/test_package/a/foo":[]}';
-        await buildAndVerifyAssets(
-          assets,
-          <String>['test_package'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('One asset and its variant are bundled when the package '
-        'has an asset and a variant, and lists the asset in its pubspec', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: <String>['a/foo', 'a/bar'],
-        );
-
-        final List<String> assets = <String>['a/foo', 'a/2x/foo', 'a/bar'];
-        writeAssets('p/p/', assets);
-
-        const String expectedManifest = '{'
-            '"packages/test_package/a/bar":[],'
-            '"packages/test_package/a/foo":['
-              '{"asset":"packages/test_package/a/2x/foo","dpr":2.0}]'
-            '}';
-
-        await buildAndVerifyAssets(
-          assets,
-          <String>['test_package'],
-          expectedManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('One asset and its variant are bundled when the package '
-        'has an asset and a variant, and the app lists the asset in its pubspec', () async {
-        writePubspecFile(
-          'pubspec.yaml',
-          'test',
-          assets: <String>['packages/test_package/a/foo'],
-        );
-        writePackagesFile('test_package:p/p/lib/');
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-        );
-
-        final List<String> assets = <String>['a/foo', 'a/2x/foo'];
-        writeAssets('p/p/lib/', assets);
-
-        const String expectedManifest = '{"packages/test_package/a/foo":'
-            '[{"asset":"packages/test_package/a/2x/foo","dpr":2.0}]}';
-
-        await buildAndVerifyAssets(
-          assets,
-          <String>['test_package'],
-          expectedManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('Two assets are bundled when the package has and lists '
-        'two assets in its pubspec', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
-
-        final List<String> assets = <String>['a/foo', 'a/bar'];
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: assets,
-        );
-
-        writeAssets('p/p/', assets);
-        const String expectedAssetManifest =
-            '{"packages/test_package/a/bar":[],'
-            '"packages/test_package/a/foo":[]}';
-
-        await buildAndVerifyAssets(
-          assets,
-          <String>['test_package'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext("Two assets are bundled when the package has two assets, listed in the app's pubspec", () async {
-        final List<String> assetEntries = <String>[
-          'packages/test_package/a/foo',
-          'packages/test_package/a/bar',
-        ];
-        writePubspecFile(
-          'pubspec.yaml',
-          'test',
-          assets: assetEntries,
-        );
-        writePackagesFile('test_package:p/p/lib/');
-
-        final List<String> assets = <String>['a/foo', 'a/bar'];
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-        );
-
-        writeAssets('p/p/lib/', assets);
-        const String expectedAssetManifest =
-            '{"packages/test_package/a/bar":[],'
-            '"packages/test_package/a/foo":[]}';
-
-        await buildAndVerifyAssets(
-          assets,
-          <String>['test_package'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('Two assets are bundled when two packages each have and list an asset their pubspec', () async {
-        writePubspecFile(
-          'pubspec.yaml',
-          'test',
-        );
-        writePackagesFile('test_package:p/p/lib/\ntest_package2:p2/p/lib/');
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: <String>['a/foo'],
-        );
-        writePubspecFile(
-          'p2/p/pubspec.yaml',
-          'test_package2',
-          assets: <String>['a/foo'],
-        );
-
-        final List<String> assets = <String>['a/foo', 'a/2x/foo'];
-        writeAssets('p/p/', assets);
-        writeAssets('p2/p/', assets);
-
-        const String expectedAssetManifest =
-            '{"packages/test_package/a/foo":'
-            '[{"asset":"packages/test_package/a/2x/foo","dpr":2.0}],'
-            '"packages/test_package2/a/foo":'
-            '[{"asset":"packages/test_package2/a/2x/foo","dpr":2.0}]}';
-
-        await buildAndVerifyAssets(
-          assets,
-          <String>['test_package', 'test_package2'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext("Two assets are bundled when two packages each have an asset, listed in the app's pubspec", () async {
-        final List<String> assetEntries = <String>[
-          'packages/test_package/a/foo',
-          'packages/test_package2/a/foo',
-        ];
-        writePubspecFile(
-          'pubspec.yaml',
-          'test',
-          assets: assetEntries,
-        );
-        writePackagesFile('test_package:p/p/lib/\ntest_package2:p2/p/lib/');
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-        );
-        writePubspecFile(
-          'p2/p/pubspec.yaml',
-          'test_package2',
-        );
-
-        final List<String> assets = <String>['a/foo', 'a/2x/foo'];
-        writeAssets('p/p/lib/', assets);
-        writeAssets('p2/p/lib/', assets);
-
-        const String expectedAssetManifest =
-            '{"packages/test_package/a/foo":'
-            '[{"asset":"packages/test_package/a/2x/foo","dpr":2.0}],'
-            '"packages/test_package2/a/foo":'
-            '[{"asset":"packages/test_package2/a/2x/foo","dpr":2.0}]}';
-
-        await buildAndVerifyAssets(
-          assets,
-          <String>['test_package', 'test_package2'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('One asset is bundled when the app depends on a package, '
-        'listing in its pubspec an asset from another package', () async {
-        writePubspecFile(
-          'pubspec.yaml',
-          'test',
-        );
-        writePackagesFile('test_package:p/p/lib/\ntest_package2:p2/p/lib/');
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: <String>['packages/test_package2/a/foo'],
-        );
-        writePubspecFile(
-          'p2/p/pubspec.yaml',
-          'test_package2',
-        );
-
-        final List<String> assets = <String>['a/foo', 'a/2x/foo'];
-        writeAssets('p2/p/lib/', assets);
-
-        const String expectedAssetManifest =
-            '{"packages/test_package2/a/foo":'
-            '[{"asset":"packages/test_package2/a/2x/foo","dpr":2.0}]}';
-
-        await buildAndVerifyAssets(
-          assets,
-          <String>['test_package2'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
+      await buildAndVerifyAssets(
+        assets,
+        <String>['test_package'],
+        expectedManifest,
+      );
+    }, overrides: <Type, Generator>{
+      FileSystem: () => testFileSystem,
+      ProcessManager: () => FakeProcessManager.any(),
     });
 
-    testUsingContext('Asset paths can contain URL reserved characters', () async {
+    testUsingContext('One asset and its variant are bundled when the package '
+      'has an asset and a variant, and the app lists the asset in its pubspec', () async {
+      writePubspecFile(
+        'pubspec.yaml',
+        'test',
+        assets: <String>['packages/test_package/a/foo'],
+      );
+      writePackagesFile('test_package:p/p/lib/');
+      writePubspecFile(
+        'p/p/pubspec.yaml',
+        'test_package',
+      );
+
+      final List<String> assets = <String>['a/foo', 'a/2x/foo'];
+      writeAssets('p/p/lib/', assets);
+
+      const String expectedManifest = '{"packages/test_package/a/foo":'
+          '["packages/test_package/a/foo","packages/test_package/a/2x/foo"]}';
+
+      await buildAndVerifyAssets(
+        assets,
+        <String>['test_package'],
+        expectedManifest,
+      );
+    }, overrides: <Type, Generator>{
+      FileSystem: () => testFileSystem,
+      ProcessManager: () => FakeProcessManager.any(),
+    });
+
+    testUsingContext('Two assets are bundled when the package has and lists '
+      'two assets in its pubspec', () async {
       writePubspecFile('pubspec.yaml', 'test');
       writePackagesFile('test_package:p/p/lib/');
 
-      final List<String> assets = <String>['a/foo', 'a/foo [x]'];
+      final List<String> assets = <String>['a/foo', 'a/bar'];
       writePubspecFile(
         'p/p/pubspec.yaml',
         'test_package',
@@ -1049,8 +285,8 @@
 
       writeAssets('p/p/', assets);
       const String expectedAssetManifest =
-          '{"packages/test_package/a/foo":[],'
-          '"packages/test_package/a/foo [x]":[]}';
+          '{"packages/test_package/a/bar":["packages/test_package/a/bar"],'
+          '"packages/test_package/a/foo":["packages/test_package/a/foo"]}';
 
       await buildAndVerifyAssets(
         assets,
@@ -1062,165 +298,335 @@
       ProcessManager: () => FakeProcessManager.any(),
     });
 
-    group('AssetBundle assets from scanned paths', () {
-      testUsingContext('Two assets are bundled when scanning their directory', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
+    testUsingContext("Two assets are bundled when the package has two assets, listed in the app's pubspec", () async {
+      final List<String> assetEntries = <String>[
+        'packages/test_package/a/foo',
+        'packages/test_package/a/bar',
+      ];
+      writePubspecFile(
+        'pubspec.yaml',
+        'test',
+         assets: assetEntries,
+      );
+      writePackagesFile('test_package:p/p/lib/');
 
-        final List<String> assetsOnDisk = <String>['a/foo', 'a/bar'];
-        final List<String> assetsOnManifest = <String>['a/'];
+      final List<String> assets = <String>['a/foo', 'a/bar'];
+      writePubspecFile(
+        'p/p/pubspec.yaml',
+        'test_package',
+      );
 
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: assetsOnManifest,
-        );
+      writeAssets('p/p/lib/', assets);
+      const String expectedAssetManifest =
+          '{"packages/test_package/a/bar":["packages/test_package/a/bar"],'
+          '"packages/test_package/a/foo":["packages/test_package/a/foo"]}';
 
-        writeAssets('p/p/', assetsOnDisk);
-        const String expectedAssetManifest =
-            '{"packages/test_package/a/bar":[],'
-            '"packages/test_package/a/foo":[]}';
-
-        await buildAndVerifyAssets(
-          assetsOnDisk,
-          <String>['test_package'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('Two assets are bundled when listing one and scanning second directory', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
-
-        final List<String> assetsOnDisk = <String>['a/foo', 'abc/bar'];
-        final List<String> assetOnManifest = <String>['a/foo', 'abc/'];
-
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: assetOnManifest,
-        );
-
-        writeAssets('p/p/', assetsOnDisk);
-        const String expectedAssetManifest =
-            '{"packages/test_package/a/foo":[],'
-            '"packages/test_package/abc/bar":[]}';
-
-        await buildAndVerifyAssets(
-          assetsOnDisk,
-          <String>['test_package'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
-
-      testUsingContext('One asset is bundled with variant, scanning wrong directory', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
-
-        final List<String> assetsOnDisk = <String>['a/foo','a/b/foo','a/bar'];
-        final List<String> assetOnManifest = <String>['a','a/bar']; // can't list 'a' as asset, should be 'a/'
-
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: assetOnManifest,
-        );
-
-        writeAssets('p/p/', assetsOnDisk);
-
-        final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
-        await bundle.build(packagesPath: '.packages');
-
-        expect(bundle.entries['AssetManifest.bin'], isNull,
-          reason: 'Invalid pubspec.yaml should not generate AssetManifest.bin'  );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
+      await buildAndVerifyAssets(
+        assets,
+        <String>['test_package'],
+        expectedAssetManifest,
+      );
+    }, overrides: <Type, Generator>{
+      FileSystem: () => testFileSystem,
+      ProcessManager: () => FakeProcessManager.any(),
     });
 
-    group('AssetBundle assets from scanned paths with MemoryFileSystem', () {
-      testUsingContext('One asset is bundled with variant, scanning directory', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
+    testUsingContext('Two assets are bundled when two packages each have and list an asset their pubspec', () async {
+      writePubspecFile(
+        'pubspec.yaml',
+        'test',
+      );
+      writePackagesFile('test_package:p/p/lib/\ntest_package2:p2/p/lib/');
+      writePubspecFile(
+        'p/p/pubspec.yaml',
+        'test_package',
+        assets: <String>['a/foo'],
+      );
+      writePubspecFile(
+        'p2/p/pubspec.yaml',
+        'test_package2',
+        assets: <String>['a/foo'],
+      );
 
-        final List<String> assetsOnDisk = <String>['a/foo','a/2x/foo'];
-        final List<String> assetOnManifest = <String>['a/',];
+      final List<String> assets = <String>['a/foo', 'a/2x/foo'];
+      writeAssets('p/p/', assets);
+      writeAssets('p2/p/', assets);
 
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: assetOnManifest,
-        );
+      const String expectedAssetManifest =
+          '{"packages/test_package/a/foo":'
+          '["packages/test_package/a/foo","packages/test_package/a/2x/foo"],'
+          '"packages/test_package2/a/foo":'
+          '["packages/test_package2/a/foo","packages/test_package2/a/2x/foo"]}';
 
-        writeAssets('p/p/', assetsOnDisk);
-        const String expectedAssetManifest =
-            '{"packages/test_package/a/foo":[{"asset":"packages/test_package/a/2x/foo","dpr":2.0}]}';
+      await buildAndVerifyAssets(
+        assets,
+        <String>['test_package', 'test_package2'],
+        expectedAssetManifest,
+      );
+    }, overrides: <Type, Generator>{
+      FileSystem: () => testFileSystem,
+      ProcessManager: () => FakeProcessManager.any(),
+    });
 
-        await buildAndVerifyAssets(
-          assetsOnDisk,
-          <String>['test_package'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
+    testUsingContext("Two assets are bundled when two packages each have an asset, listed in the app's pubspec", () async {
+      final List<String> assetEntries = <String>[
+        'packages/test_package/a/foo',
+        'packages/test_package2/a/foo',
+      ];
+      writePubspecFile(
+        'pubspec.yaml',
+        'test',
+        assets: assetEntries,
+      );
+      writePackagesFile('test_package:p/p/lib/\ntest_package2:p2/p/lib/');
+      writePubspecFile(
+        'p/p/pubspec.yaml',
+        'test_package',
+      );
+      writePubspecFile(
+        'p2/p/pubspec.yaml',
+        'test_package2',
+      );
 
-      testUsingContext('No asset is bundled with variant, no assets or directories are listed', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
+      final List<String> assets = <String>['a/foo', 'a/2x/foo'];
+      writeAssets('p/p/lib/', assets);
+      writeAssets('p2/p/lib/', assets);
 
-        final List<String> assetsOnDisk = <String>['a/foo', 'a/2x/foo'];
-        final List<String> assetOnManifest = <String>[];
+      const String expectedAssetManifest =
+          '{"packages/test_package/a/foo":'
+          '["packages/test_package/a/foo","packages/test_package/a/2x/foo"],'
+          '"packages/test_package2/a/foo":'
+          '["packages/test_package2/a/foo","packages/test_package2/a/2x/foo"]}';
 
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: assetOnManifest,
-        );
+      await buildAndVerifyAssets(
+        assets,
+        <String>['test_package', 'test_package2'],
+        expectedAssetManifest,
+      );
+    }, overrides: <Type, Generator>{
+      FileSystem: () => testFileSystem,
+      ProcessManager: () => FakeProcessManager.any(),
+    });
 
-        writeAssets('p/p/', assetsOnDisk);
-        const String expectedAssetManifest = '{}';
+    testUsingContext('One asset is bundled when the app depends on a package, '
+      'listing in its pubspec an asset from another package', () async {
+      writePubspecFile(
+        'pubspec.yaml',
+        'test',
+      );
+      writePackagesFile('test_package:p/p/lib/\ntest_package2:p2/p/lib/');
+      writePubspecFile(
+        'p/p/pubspec.yaml',
+        'test_package',
+        assets: <String>['packages/test_package2/a/foo'],
+      );
+      writePubspecFile(
+        'p2/p/pubspec.yaml',
+        'test_package2',
+      );
 
-        await buildAndVerifyAssets(
-          assetOnManifest,
-          <String>['test_package'],
-          expectedAssetManifest,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
+      final List<String> assets = <String>['a/foo', 'a/2x/foo'];
+      writeAssets('p2/p/lib/', assets);
 
-      testUsingContext('Expect error generating manifest, wrong non-existing directory is listed', () async {
-        writePubspecFile('pubspec.yaml', 'test');
-        writePackagesFile('test_package:p/p/lib/');
+      const String expectedAssetManifest =
+          '{"packages/test_package2/a/foo":'
+          '["packages/test_package2/a/foo","packages/test_package2/a/2x/foo"]}';
 
-        final List<String> assetOnManifest = <String>['c/'];
+      await buildAndVerifyAssets(
+        assets,
+        <String>['test_package2'],
+        expectedAssetManifest,
+      );
+    }, overrides: <Type, Generator>{
+      FileSystem: () => testFileSystem,
+      ProcessManager: () => FakeProcessManager.any(),
+    });
+  });
 
-        writePubspecFile(
-          'p/p/pubspec.yaml',
-          'test_package',
-          assets: assetOnManifest,
-        );
+  testUsingContext('Asset paths can contain URL reserved characters', () async {
+    writePubspecFile('pubspec.yaml', 'test');
+    writePackagesFile('test_package:p/p/lib/');
 
-        await buildAndVerifyAssets(
-          assetOnManifest,
-          <String>['test_package'],
-          null,
-          expectExists: false,
-        );
-      }, overrides: <Type, Generator>{
-        FileSystem: () => testFileSystem,
-        ProcessManager: () => FakeProcessManager.any(),
-      });
+    final List<String> assets = <String>['a/foo', 'a/foo [x]'];
+    writePubspecFile(
+      'p/p/pubspec.yaml',
+      'test_package',
+      assets: assets,
+    );
+
+    writeAssets('p/p/', assets);
+    const String expectedAssetManifest =
+        '{"packages/test_package/a/foo":["packages/test_package/a/foo"],'
+        '"packages/test_package/a/foo [x]":["packages/test_package/a/foo [x]"]}';
+
+    await buildAndVerifyAssets(
+      assets,
+      <String>['test_package'],
+      expectedAssetManifest,
+    );
+  }, overrides: <Type, Generator>{
+    FileSystem: () => testFileSystem,
+      ProcessManager: () => FakeProcessManager.any(),
+  });
+
+  group('AssetBundle assets from scanned paths', () {
+    testUsingContext('Two assets are bundled when scanning their directory', () async {
+      writePubspecFile('pubspec.yaml', 'test');
+      writePackagesFile('test_package:p/p/lib/');
+
+      final List<String> assetsOnDisk = <String>['a/foo', 'a/bar'];
+      final List<String> assetsOnManifest = <String>['a/'];
+
+      writePubspecFile(
+        'p/p/pubspec.yaml',
+        'test_package',
+        assets: assetsOnManifest,
+      );
+
+      writeAssets('p/p/', assetsOnDisk);
+      const String expectedAssetManifest =
+          '{"packages/test_package/a/bar":["packages/test_package/a/bar"],'
+          '"packages/test_package/a/foo":["packages/test_package/a/foo"]}';
+
+      await buildAndVerifyAssets(
+        assetsOnDisk,
+        <String>['test_package'],
+        expectedAssetManifest,
+      );
+    }, overrides: <Type, Generator>{
+      FileSystem: () => testFileSystem,
+      ProcessManager: () => FakeProcessManager.any(),
+    });
+
+    testUsingContext('Two assets are bundled when listing one and scanning second directory', () async {
+      writePubspecFile('pubspec.yaml', 'test');
+      writePackagesFile('test_package:p/p/lib/');
+
+      final List<String> assetsOnDisk = <String>['a/foo', 'abc/bar'];
+      final List<String> assetOnManifest = <String>['a/foo', 'abc/'];
+
+      writePubspecFile(
+        'p/p/pubspec.yaml',
+        'test_package',
+        assets: assetOnManifest,
+      );
+
+      writeAssets('p/p/', assetsOnDisk);
+      const String expectedAssetManifest =
+          '{"packages/test_package/a/foo":["packages/test_package/a/foo"],'
+          '"packages/test_package/abc/bar":["packages/test_package/abc/bar"]}';
+
+      await buildAndVerifyAssets(
+        assetsOnDisk,
+        <String>['test_package'],
+        expectedAssetManifest,
+      );
+    }, overrides: <Type, Generator>{
+      FileSystem: () => testFileSystem,
+      ProcessManager: () => FakeProcessManager.any(),
+    });
+
+    testUsingContext('One asset is bundled with variant, scanning wrong directory', () async {
+      writePubspecFile('pubspec.yaml', 'test');
+      writePackagesFile('test_package:p/p/lib/');
+
+      final List<String> assetsOnDisk = <String>['a/foo','a/b/foo','a/bar'];
+      final List<String> assetOnManifest = <String>['a','a/bar']; // can't list 'a' as asset, should be 'a/'
+
+      writePubspecFile(
+        'p/p/pubspec.yaml',
+        'test_package',
+        assets: assetOnManifest,
+      );
+
+      writeAssets('p/p/', assetsOnDisk);
+
+      final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
+      await bundle.build(packagesPath: '.packages');
+
+      expect(bundle.entries['AssetManifest.json'], isNull,
+        reason: 'Invalid pubspec.yaml should not generate AssetManifest.json'  );
+    }, overrides: <Type, Generator>{
+      FileSystem: () => testFileSystem,
+      ProcessManager: () => FakeProcessManager.any(),
+    });
+  });
+
+  group('AssetBundle assets from scanned paths with MemoryFileSystem', () {
+    testUsingContext('One asset is bundled with variant, scanning directory', () async {
+      writePubspecFile('pubspec.yaml', 'test');
+      writePackagesFile('test_package:p/p/lib/');
+
+      final List<String> assetsOnDisk = <String>['a/foo','a/2x/foo'];
+      final List<String> assetOnManifest = <String>['a/',];
+
+      writePubspecFile(
+        'p/p/pubspec.yaml',
+        'test_package',
+        assets: assetOnManifest,
+      );
+
+      writeAssets('p/p/', assetsOnDisk);
+      const String expectedAssetManifest =
+          '{"packages/test_package/a/foo":["packages/test_package/a/foo","packages/test_package/a/2x/foo"]}';
+
+      await buildAndVerifyAssets(
+        assetsOnDisk,
+        <String>['test_package'],
+        expectedAssetManifest,
+      );
+    }, overrides: <Type, Generator>{
+      FileSystem: () => testFileSystem,
+      ProcessManager: () => FakeProcessManager.any(),
+    });
+
+    testUsingContext('No asset is bundled with variant, no assets or directories are listed', () async {
+      writePubspecFile('pubspec.yaml', 'test');
+      writePackagesFile('test_package:p/p/lib/');
+
+      final List<String> assetsOnDisk = <String>['a/foo', 'a/2x/foo'];
+      final List<String> assetOnManifest = <String>[];
+
+      writePubspecFile(
+        'p/p/pubspec.yaml',
+        'test_package',
+        assets: assetOnManifest,
+      );
+
+      writeAssets('p/p/', assetsOnDisk);
+      const String expectedAssetManifest = '{}';
+
+      await buildAndVerifyAssets(
+        assetOnManifest,
+        <String>['test_package'],
+        expectedAssetManifest,
+      );
+    }, overrides: <Type, Generator>{
+      FileSystem: () => testFileSystem,
+      ProcessManager: () => FakeProcessManager.any(),
+    });
+
+    testUsingContext('Expect error generating manifest, wrong non-existing directory is listed', () async {
+      writePubspecFile('pubspec.yaml', 'test');
+      writePackagesFile('test_package:p/p/lib/');
+
+      final List<String> assetOnManifest = <String>['c/'];
+
+      writePubspecFile(
+        'p/p/pubspec.yaml',
+        'test_package',
+        assets: assetOnManifest,
+      );
+
+      await buildAndVerifyAssets(
+        assetOnManifest,
+        <String>['test_package'],
+        null,
+        expectExists: false,
+      );
+    }, overrides: <Type, Generator>{
+      FileSystem: () => testFileSystem,
+      ProcessManager: () => FakeProcessManager.any(),
     });
   });
 }
diff --git a/packages/flutter_tools/test/general.shard/asset_bundle_test.dart b/packages/flutter_tools/test/general.shard/asset_bundle_test.dart
index 47f47b7..bd272f8 100644
--- a/packages/flutter_tools/test/general.shard/asset_bundle_test.dart
+++ b/packages/flutter_tools/test/general.shard/asset_bundle_test.dart
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 import 'dart:convert';
-import 'dart:typed_data';
 
 import 'package:file/memory.dart';
 import 'package:flutter_tools/src/artifacts.dart';
@@ -14,7 +13,6 @@
 import 'package:flutter_tools/src/bundle_builder.dart';
 import 'package:flutter_tools/src/devfs.dart';
 import 'package:flutter_tools/src/globals.dart' as globals;
-import 'package:standard_message_codec/standard_message_codec.dart';
 
 import '../src/common.dart';
 import '../src/context.dart';
@@ -50,16 +48,11 @@
 
       final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
       await bundle.build(packagesPath: '.packages');
-      expect(bundle.entries.keys, unorderedEquals(<String>['AssetManifest.json', 'AssetManifest.bin']));
-      const String expectedJsonAssetManifest = '{}';
+      expect(bundle.entries.length, 1);
+      const String expectedAssetManifest = '{}';
       expect(
         utf8.decode(await bundle.entries['AssetManifest.json']!.contentsAsBytes()),
-        expectedJsonAssetManifest,
-      );
-      const String expectedBinAssetManifest = '{}';
-      expect(
-        await _extractBinAssetManifestFromBundleAsJson(bundle),
-        expectedBinAssetManifest
+        expectedAssetManifest,
       );
     }, overrides: <Type, Generator>{
       FileSystem: () => testFileSystem,
@@ -79,8 +72,12 @@
 ''');
       final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
       await bundle.build(packagesPath: '.packages');
-      expect(bundle.entries.keys, unorderedEquals(<String>['AssetManifest.json',
-        'AssetManifest.bin', 'FontManifest.json', 'NOTICES.Z', 'assets/foo/bar.txt']));
+      // Expected assets:
+      //  - asset manifest
+      //  - font manifest
+      //  - license file
+      //  - assets/foo/bar.txt
+      expect(bundle.entries.length, 4);
       expect(bundle.needsBuild(), false);
 
       // Simulate modifying the files by updating the filestat time manually.
@@ -90,9 +87,13 @@
 
       expect(bundle.needsBuild(), true);
       await bundle.build(packagesPath: '.packages');
-      expect(bundle.entries.keys, unorderedEquals(<String>['AssetManifest.json',
-        'AssetManifest.bin', 'FontManifest.json', 'NOTICES.Z', 'assets/foo/bar.txt',
-        'assets/foo/fizz.txt']));
+      // Expected assets:
+      //  - asset manifest
+      //  - font manifest
+      //  - license file
+      //  - assets/foo/bar.txt
+      //  - assets/foo/fizz.txt
+      expect(bundle.entries.length, 5);
     }, overrides: <Type, Generator>{
       FileSystem: () => testFileSystem,
       ProcessManager: () => FakeProcessManager.any(),
@@ -111,8 +112,12 @@
       globals.fs.file('.packages').createSync();
       final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
       await bundle.build(packagesPath: '.packages');
-      expect(bundle.entries.keys, unorderedEquals(<String>['AssetManifest.json',
-        'AssetManifest.bin', 'FontManifest.json', 'NOTICES.Z', 'assets/foo/bar.txt']));
+      // Expected assets:
+      //  - asset manifest
+      //  - font manifest
+      //  - license file
+      //  - assets/foo/bar.txt
+      expect(bundle.entries.length, 4);
       expect(bundle.needsBuild(), false);
 
       // Delete the wildcard directory and update pubspec file.
@@ -133,8 +138,12 @@
       // supporting file deletion.
       expect(bundle.needsBuild(), true);
       await bundle.build(packagesPath: '.packages');
-      expect(bundle.entries.keys, unorderedEquals(<String>['AssetManifest.json',
-        'AssetManifest.bin', 'FontManifest.json', 'NOTICES.Z', 'assets/foo/bar.txt']));
+      // Expected assets:
+      //  - asset manifest
+      //  - font manifest
+      //  - license file
+      //  - assets/foo/bar.txt
+      expect(bundle.entries.length, 4);
     }, overrides: <Type, Generator>{
       FileSystem: () => testFileSystem,
       ProcessManager: () => FakeProcessManager.any(),
@@ -157,8 +166,12 @@
       globals.fs.file('.packages').createSync();
       final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
       await bundle.build(packagesPath: '.packages');
-      expect(bundle.entries.keys, unorderedEquals(<String>['AssetManifest.json',
-        'AssetManifest.bin', 'FontManifest.json', 'NOTICES.Z', 'assets/foo/bar.txt']));
+      // Expected assets:
+      //  - asset manifest
+      //  - font manifest
+      //  - license file
+      //  - assets/foo/bar.txt
+      expect(bundle.entries.length, 4);
       expect(bundle.needsBuild(), false);
     }, overrides: <Type, Generator>{
       FileSystem: () => testFileSystem,
@@ -190,8 +203,12 @@
         splitDeferredAssets: true,
       ).createBundle();
       await bundle.build(packagesPath: '.packages', deferredComponentsEnabled: true);
-      expect(bundle.entries.keys, unorderedEquals(<String>['AssetManifest.json',
-        'AssetManifest.bin', 'FontManifest.json', 'NOTICES.Z', 'assets/foo/bar.txt']));
+      // Expected assets:
+      //  - asset manifest
+      //  - font manifest
+      //  - license file
+      //  - assets/foo/bar.txt
+      expect(bundle.entries.length, 4);
       expect(bundle.deferredComponentsEntries.length, 1);
       expect(bundle.deferredComponentsEntries['component1']!.length, 2);
       expect(bundle.needsBuild(), false);
@@ -220,9 +237,12 @@
 ''');
       final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
       await bundle.build(packagesPath: '.packages');
-      expect(bundle.entries.keys, unorderedEquals(<String>['assets/foo/bar.txt',
-        'assets/bar/barbie.txt', 'assets/wild/dash.txt', 'AssetManifest.json',
-        'AssetManifest.bin', 'FontManifest.json', 'NOTICES.Z']));
+      // Expected assets:
+      //  - asset manifest
+      //  - font manifest
+      //  - license file
+      //  - assets/foo/bar.txt
+      expect(bundle.entries.length, 6);
       expect(bundle.deferredComponentsEntries.isEmpty, true);
       expect(bundle.needsBuild(), false);
     }, overrides: <Type, Generator>{
@@ -255,11 +275,14 @@
         splitDeferredAssets: true,
       ).createBundle();
       await bundle.build(packagesPath: '.packages', deferredComponentsEnabled: true);
-      expect(bundle.entries.keys, unorderedEquals(<String>['assets/foo/bar.txt',
-        'AssetManifest.json', 'AssetManifest.bin', 'FontManifest.json', 'NOTICES.Z']));
-      expect(bundle.deferredComponentsEntries.keys, unorderedEquals(<String>['component1']));
-      expect(bundle.deferredComponentsEntries['component1']!.keys,
-        unorderedEquals(<String>['assets/bar/barbie.txt', 'assets/wild/dash.txt']));
+      // Expected assets:
+      //  - asset manifest
+      //  - font manifest
+      //  - license file
+      //  - assets/foo/bar.txt
+      expect(bundle.entries.length, 4);
+      expect(bundle.deferredComponentsEntries.length, 1);
+      expect(bundle.deferredComponentsEntries['component1']!.length, 2);
       expect(bundle.needsBuild(), false);
 
       // Simulate modifying the files by updating the filestat time manually.
@@ -270,13 +293,9 @@
       expect(bundle.needsBuild(), true);
       await bundle.build(packagesPath: '.packages', deferredComponentsEnabled: true);
 
-      expect(bundle.entries.keys, unorderedEquals(<String>['assets/foo/bar.txt',
-        'AssetManifest.json', 'AssetManifest.bin', 'FontManifest.json', 'NOTICES.Z']));
+      expect(bundle.entries.length, 4);
       expect(bundle.deferredComponentsEntries.length, 1);
-      expect(bundle.deferredComponentsEntries['component1']!.keys,
-        unorderedEquals(<String>['assets/bar/barbie.txt', 'assets/wild/dash.txt',
-        'assets/wild/fizz.txt']));
-
+      expect(bundle.deferredComponentsEntries['component1']!.length, 3);
     }, overrides: <Type, Generator>{
       FileSystem: () => testFileSystem,
       ProcessManager: () => FakeProcessManager.any(),
@@ -316,8 +335,7 @@
     final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
     await bundle.build(packagesPath: '.packages');
 
-    final DevFSContent? assetManifestBin = bundle.entries['AssetManifest.bin'];
-    final DevFSStringContent? assetManifestJson = bundle.entries['AssetManifest.json']
+    final DevFSStringContent? assetManifest = bundle.entries['AssetManifest.json']
       as DevFSStringContent?;
     final DevFSStringContent? fontManifest = bundle.entries['FontManifest.json']
       as DevFSStringContent?;
@@ -326,8 +344,7 @@
 
     await bundle.build(packagesPath: '.packages');
 
-    expect(assetManifestBin, bundle.entries['AssetManifest.bin']);
-    expect(assetManifestJson, bundle.entries['AssetManifest.json']);
+    expect(assetManifest, bundle.entries['AssetManifest.json']);
     expect(fontManifest, bundle.entries['FontManifest.json']);
     expect(license, bundle.entries['NOTICES']);
   }, overrides: <Type, Generator>{
@@ -622,8 +639,7 @@
 
     await bundle.build(packagesPath: '.packages');
 
-    expect(bundle.entries.keys, unorderedEquals(<String>['packages/foo/bar/fizz.txt',
-    'AssetManifest.json', 'AssetManifest.bin', 'FontManifest.json', 'NOTICES.Z']));
+    expect(bundle.entries, hasLength(4));
     expect(bundle.needsBuild(), false);
 
     // Does not track dependency's wildcard directories.
@@ -723,7 +739,6 @@
     expect(await bundle.build(packagesPath: '.packages'), 0);
     expect((bundle.entries['FontManifest.json']! as DevFSStringContent).string, '[]');
     expect((bundle.entries['AssetManifest.json']! as DevFSStringContent).string, '{}');
-    expect(await _extractBinAssetManifestFromBundleAsJson(bundle), '{}');
     expect(testLogger.errorText, contains(
       'package:foo has `uses-material-design: true` set'
     ));
@@ -759,8 +774,7 @@
     final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
 
     expect(await bundle.build(packagesPath: '.packages'), 0);
-    expect(bundle.entries.keys, unorderedEquals(<String>['assets/foo.txt',
-      'AssetManifest.json', 'AssetManifest.bin', 'FontManifest.json', 'NOTICES.Z']));
+    expect(bundle.entries.length, 4);
   }, overrides: <Type, Generator>{
     FileSystem: () => MemoryFileSystem.test(),
     ProcessManager: () => FakeProcessManager.any(),
@@ -798,17 +812,9 @@
     // The assets from deferred components and regular assets
     // are both included in alphabetical order
     expect((bundle.entries['AssetManifest.json']! as DevFSStringContent).string, '{"assets/apple.jpg":["assets/apple.jpg"],"assets/bar.jpg":["assets/bar.jpg"],"assets/foo.jpg":["assets/foo.jpg"],"assets/zebra.jpg":["assets/zebra.jpg"]}');
-    expect(await _extractBinAssetManifestFromBundleAsJson(bundle), '{"assets/apple.jpg":[],"assets/bar.jpg":[],"assets/foo.jpg":[],"assets/zebra.jpg":[]}');
   }, overrides: <Type, Generator>{
     FileSystem: () => MemoryFileSystem.test(),
     ProcessManager: () => FakeProcessManager.any(),
     Platform: () => FakePlatform(),
   });
 }
-
-Future<String> _extractBinAssetManifestFromBundleAsJson(AssetBundle bundle) async {
-  final List<int> manifestBytes = await bundle.entries['AssetManifest.bin']!.contentsAsBytes();
-  return json.encode(const StandardMessageCodec().decodeMessage(
-    ByteData.sublistView(Uint8List.fromList(manifestBytes))
-  ));
-}
diff --git a/packages/flutter_tools/test/general.shard/asset_bundle_variant_test.dart b/packages/flutter_tools/test/general.shard/asset_bundle_variant_test.dart
index 9b48bc2..9bec3b7 100644
--- a/packages/flutter_tools/test/general.shard/asset_bundle_variant_test.dart
+++ b/packages/flutter_tools/test/general.shard/asset_bundle_variant_test.dart
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 import 'dart:convert';
-import 'dart:typed_data';
 
 import 'package:file/file.dart';
 import 'package:file/memory.dart';
@@ -16,418 +15,209 @@
 import 'package:flutter_tools/src/cache.dart';
 
 import 'package:flutter_tools/src/project.dart';
-import 'package:standard_message_codec/standard_message_codec.dart';
 
 import '../src/common.dart';
 
 void main() {
 
-  // TODO(andrewkolos): Delete this group once we stop producing AssetManifest.json
-  // as part of build.
-  group('Legacy asset manifest (AssetManifest.json)', () {
-    Future<Map<String, List<String>>> extractAssetManifestFromBundle(ManifestAssetBundle bundle) async {
-      final String manifestJson = utf8.decode(await bundle.entries['AssetManifest.json']!.contentsAsBytes());
-      final Map<String, dynamic> parsedJson = json.decode(manifestJson) as Map<String, dynamic>;
-      final Iterable<String> keys = parsedJson.keys;
-      final Map<String, List<String>> parsedManifest = <String, List<String>> {
-        for (final String key in keys) key: List<String>.from(parsedJson[key] as List<dynamic>),
-      };
-      return parsedManifest;
-    }
+  Future<Map<String, List<String>>> extractAssetManifestFromBundle(ManifestAssetBundle bundle) async {
+    final String manifestJson = utf8.decode(await bundle.entries['AssetManifest.json']!.contentsAsBytes());
+    final Map<String, dynamic> parsedJson = json.decode(manifestJson) as Map<String, dynamic>;
+    final Iterable<String> keys = parsedJson.keys;
+    final Map<String, List<String>> parsedManifest = <String, List<String>> {
+      for (final String key in keys) key: List<String>.from(parsedJson[key] as List<dynamic>),
+    };
+    return parsedManifest;
+  }
 
-    group('AssetBundle asset variants (with Unix-style paths)', () {
-      late Platform platform;
-      late FileSystem fs;
+  group('AssetBundle asset variants (with Unix-style paths)', () {
+    late Platform platform;
+    late FileSystem fs;
 
-      setUp(() {
-        platform = FakePlatform();
-        fs = MemoryFileSystem.test();
-        Cache.flutterRoot = Cache.defaultFlutterRoot(
-          platform: platform,
-          fileSystem: fs,
-          userMessages: UserMessages()
-        );
+    setUp(() {
+      platform = FakePlatform();
+      fs = MemoryFileSystem.test();
+      Cache.flutterRoot = Cache.defaultFlutterRoot(
+        platform: platform,
+        fileSystem: fs,
+        userMessages: UserMessages()
+      );
 
-        fs.file('.packages').createSync();
+      fs.file('.packages').createSync();
 
-        fs.file('pubspec.yaml').writeAsStringSync(
-  '''
-  name: test
-  dependencies:
-    flutter:
-      sdk: flutter
+      fs.file('pubspec.yaml').writeAsStringSync(
+'''
+name: test
+dependencies:
   flutter:
-    assets:
-      - assets/
-  '''
-        );
-      });
-
-      testWithoutContext('Only images in folders named with device pixel ratios (e.g. 2x, 3.0x) should be considered as variants of other images', () async {
-        const String image = 'assets/image.jpg';
-        const String image2xVariant = 'assets/2x/image.jpg';
-        const String imageNonVariant = 'assets/notAVariant/image.jpg';
-
-        final List<String> assets = <String>[
-          image,
-          image2xVariant,
-          imageNonVariant
-        ];
-
-        for (final String asset in assets) {
-          final File assetFile = fs.file(asset);
-          assetFile.createSync(recursive: true);
-          assetFile.writeAsStringSync(asset);
-        }
-
-        final ManifestAssetBundle bundle = ManifestAssetBundle(
-          logger: BufferLogger.test(),
-          fileSystem: fs,
-          platform: platform,
-        );
-
-        await bundle.build(
-          packagesPath: '.packages',
-          flutterProject:  FlutterProject.fromDirectoryTest(fs.currentDirectory),
-        );
-
-        final Map<String, List<String>> manifest = await extractAssetManifestFromBundle(bundle);
-
-        expect(manifest, hasLength(2));
-        expect(manifest[image], equals(<String>[image, image2xVariant]));
-        expect(manifest[imageNonVariant], equals(<String>[imageNonVariant]));
-      });
-
-      testWithoutContext('Asset directories are recursively searched for assets', () async {
-        const String topLevelImage = 'assets/image.jpg';
-        const String secondLevelImage = 'assets/folder/secondLevel.jpg';
-        const String secondLevel2xVariant = 'assets/folder/2x/secondLevel.jpg';
-
-        final List<String> assets = <String>[
-          topLevelImage,
-          secondLevelImage,
-          secondLevel2xVariant
-        ];
-
-        for (final String asset in assets) {
-          final File assetFile = fs.file(asset);
-          assetFile.createSync(recursive: true);
-          assetFile.writeAsStringSync(asset);
-        }
-
-        final ManifestAssetBundle bundle = ManifestAssetBundle(
-          logger: BufferLogger.test(),
-          fileSystem: fs,
-          platform: platform,
-        );
-
-        await bundle.build(
-          packagesPath: '.packages',
-          flutterProject:  FlutterProject.fromDirectoryTest(fs.currentDirectory),
-        );
-
-        final Map<String, List<String>> manifest = await extractAssetManifestFromBundle(bundle);
-        expect(manifest, hasLength(2));
-        expect(manifest[topLevelImage], equals(<String>[topLevelImage]));
-        expect(manifest[secondLevelImage], equals(<String>[secondLevelImage, secondLevel2xVariant]));
-      });
-
-      testWithoutContext('Asset paths should never be URI-encoded', () async {
-        const String image = 'assets/normalFolder/i have URI-reserved_characters.jpg';
-        const String imageVariant = 'assets/normalFolder/3x/i have URI-reserved_characters.jpg';
-
-        final List<String> assets = <String>[
-          image,
-          imageVariant
-        ];
-
-        for (final String asset in assets) {
-          final File assetFile = fs.file(asset);
-          assetFile.createSync(recursive: true);
-          assetFile.writeAsStringSync(asset);
-        }
-
-        final ManifestAssetBundle bundle = ManifestAssetBundle(
-          logger: BufferLogger.test(),
-          fileSystem: fs,
-          platform: platform,
-        );
-
-        await bundle.build(
-          packagesPath: '.packages',
-          flutterProject:  FlutterProject.fromDirectoryTest(fs.currentDirectory),
-        );
-
-        final Map<String, List<String>> manifest = await extractAssetManifestFromBundle(bundle);
-        expect(manifest, hasLength(1));
-        expect(manifest[image], equals(<String>[image, imageVariant]));
-      });
+    sdk: flutter
+flutter:
+  assets:
+    - assets/
+'''
+      );
     });
 
+    testWithoutContext('Only images in folders named with device pixel ratios (e.g. 2x, 3.0x) should be considered as variants of other images', () async {
+      const String image = 'assets/image.jpg';
+      const String image2xVariant = 'assets/2x/image.jpg';
+      const String imageNonVariant = 'assets/notAVariant/image.jpg';
 
-    group('AssetBundle asset variants (with Windows-style filepaths)', () {
-      late final Platform platform;
-      late final FileSystem fs;
+      final List<String> assets = <String>[
+        image,
+        image2xVariant,
+        imageNonVariant
+      ];
 
-      setUp(() {
-        platform = FakePlatform(operatingSystem: 'windows');
-        fs = MemoryFileSystem.test(style: FileSystemStyle.windows);
-        Cache.flutterRoot = Cache.defaultFlutterRoot(
-          platform: platform,
-          fileSystem: fs,
-          userMessages: UserMessages()
-        );
+      for (final String asset in assets) {
+        final File assetFile = fs.file(asset);
+        assetFile.createSync(recursive: true);
+        assetFile.writeAsStringSync(asset);
+      }
 
-        fs.file('.packages').createSync();
+      final ManifestAssetBundle bundle = ManifestAssetBundle(
+        logger: BufferLogger.test(),
+        fileSystem: fs,
+        platform: platform,
+      );
 
-        fs.file('pubspec.yaml').writeAsStringSync(
-  '''
-  name: test
-  dependencies:
-    flutter:
-      sdk: flutter
-  flutter:
-    assets:
-      - assets/
-  '''
-        );
-      });
+      await bundle.build(
+        packagesPath: '.packages',
+        flutterProject:  FlutterProject.fromDirectoryTest(fs.currentDirectory),
+      );
 
-      testWithoutContext('Variant detection works with windows-style filepaths', () async {
-        const List<String> assets = <String>[
-          r'assets\foo.jpg',
-          r'assets\2x\foo.jpg',
-          r'assets\somewhereElse\bar.jpg',
-          r'assets\somewhereElse\2x\bar.jpg',
-        ];
+      final Map<String, List<String>> manifest = await extractAssetManifestFromBundle(bundle);
 
-        for (final String asset in assets) {
-          final File assetFile = fs.file(asset);
-          assetFile.createSync(recursive: true);
-          assetFile.writeAsStringSync(asset);
-        }
+      expect(manifest, hasLength(2));
+      expect(manifest[image], equals(<String>[image, image2xVariant]));
+      expect(manifest[imageNonVariant], equals(<String>[imageNonVariant]));
+    });
 
-        final ManifestAssetBundle bundle = ManifestAssetBundle(
-          logger: BufferLogger.test(),
-          fileSystem: fs,
-          platform: platform,
-        );
+    testWithoutContext('Asset directories are recursively searched for assets', () async {
+      const String topLevelImage = 'assets/image.jpg';
+      const String secondLevelImage = 'assets/folder/secondLevel.jpg';
+      const String secondLevel2xVariant = 'assets/folder/2x/secondLevel.jpg';
 
-        await bundle.build(
-          packagesPath: '.packages',
-          flutterProject:  FlutterProject.fromDirectoryTest(fs.currentDirectory),
-        );
+      final List<String> assets = <String>[
+        topLevelImage,
+        secondLevelImage,
+        secondLevel2xVariant
+      ];
 
-        final Map<String, List<String>> manifest = await extractAssetManifestFromBundle(bundle);
+      for (final String asset in assets) {
+        final File assetFile = fs.file(asset);
+        assetFile.createSync(recursive: true);
+        assetFile.writeAsStringSync(asset);
+      }
 
-        expect(manifest, hasLength(2));
-        expect(manifest['assets/foo.jpg'], equals(<String>['assets/foo.jpg', 'assets/2x/foo.jpg']));
-        expect(manifest['assets/somewhereElse/bar.jpg'], equals(<String>['assets/somewhereElse/bar.jpg', 'assets/somewhereElse/2x/bar.jpg']));
-      });
+      final ManifestAssetBundle bundle = ManifestAssetBundle(
+        logger: BufferLogger.test(),
+        fileSystem: fs,
+        platform: platform,
+      );
+
+      await bundle.build(
+        packagesPath: '.packages',
+        flutterProject:  FlutterProject.fromDirectoryTest(fs.currentDirectory),
+      );
+
+      final Map<String, List<String>> manifest = await extractAssetManifestFromBundle(bundle);
+      expect(manifest, hasLength(2));
+      expect(manifest[topLevelImage], equals(<String>[topLevelImage]));
+      expect(manifest[secondLevelImage], equals(<String>[secondLevelImage, secondLevel2xVariant]));
+    });
+
+    testWithoutContext('Asset paths should never be URI-encoded', () async {
+      const String image = 'assets/normalFolder/i have URI-reserved_characters.jpg';
+      const String imageVariant = 'assets/normalFolder/3x/i have URI-reserved_characters.jpg';
+
+      final List<String> assets = <String>[
+        image,
+        imageVariant
+      ];
+
+      for (final String asset in assets) {
+        final File assetFile = fs.file(asset);
+        assetFile.createSync(recursive: true);
+        assetFile.writeAsStringSync(asset);
+      }
+
+      final ManifestAssetBundle bundle = ManifestAssetBundle(
+        logger: BufferLogger.test(),
+        fileSystem: fs,
+        platform: platform,
+      );
+
+      await bundle.build(
+        packagesPath: '.packages',
+        flutterProject:  FlutterProject.fromDirectoryTest(fs.currentDirectory),
+      );
+
+      final Map<String, List<String>> manifest = await extractAssetManifestFromBundle(bundle);
+      expect(manifest, hasLength(1));
+      expect(manifest[image], equals(<String>[image, imageVariant]));
     });
   });
 
-  group('Current asset manifest (AssetManifest.bin)', () {
-    Future<String> extractAssetManifestFromBundleAsJson(ManifestAssetBundle bundle) async {
-      final List<int> manifestBytes = await bundle.entries['AssetManifest.bin']!.contentsAsBytes();
-      return json.encode(const StandardMessageCodec().decodeMessage(
-        ByteData.sublistView(Uint8List.fromList(manifestBytes))
-      ));
-    }
 
-    group('AssetBundle asset variants (with Unix-style paths)', () {
-      late Platform platform;
-      late FileSystem fs;
+  group('AssetBundle asset variants (with Windows-style filepaths)', () {
+    late final Platform platform;
+    late final FileSystem fs;
 
-      setUp(() {
-        platform = FakePlatform();
-        fs = MemoryFileSystem.test();
-        Cache.flutterRoot = Cache.defaultFlutterRoot(
-          platform: platform,
-          fileSystem: fs,
-          userMessages: UserMessages()
-        );
+    setUp(() {
+      platform = FakePlatform(operatingSystem: 'windows');
+      fs = MemoryFileSystem.test(style: FileSystemStyle.windows);
+      Cache.flutterRoot = Cache.defaultFlutterRoot(
+        platform: platform,
+        fileSystem: fs,
+        userMessages: UserMessages()
+      );
 
-        fs.file('.packages').createSync();
+      fs.file('.packages').createSync();
 
-        fs.file('pubspec.yaml').writeAsStringSync(
-  '''
-  name: test
-  dependencies:
-    flutter:
-      sdk: flutter
+      fs.file('pubspec.yaml').writeAsStringSync(
+'''
+name: test
+dependencies:
   flutter:
-    assets:
-      - assets/
-  '''
-        );
-      });
-
-      testWithoutContext('Only images in folders named with device pixel ratios (e.g. 2x, 3.0x) should be considered as variants of other images', () async {
-        const String image = 'assets/image.jpg';
-        const String image2xVariant = 'assets/2x/image.jpg';
-        const String imageNonVariant = 'assets/notAVariant/image.jpg';
-
-        final List<String> assets = <String>[
-          image,
-          image2xVariant,
-          imageNonVariant
-        ];
-
-        for (final String asset in assets) {
-          final File assetFile = fs.file(asset);
-          assetFile.createSync(recursive: true);
-          assetFile.writeAsStringSync(asset);
-        }
-
-        final ManifestAssetBundle bundle = ManifestAssetBundle(
-          logger: BufferLogger.test(),
-          fileSystem: fs,
-          platform: platform,
-        );
-
-        await bundle.build(
-          packagesPath: '.packages',
-          flutterProject:  FlutterProject.fromDirectoryTest(fs.currentDirectory),
-        );
-
-        const String expectedManifest = '{"$image":[{"asset":"$image2xVariant","dpr":2.0}],'
-          '"$imageNonVariant":[]}';
-
-        final String manifest = await extractAssetManifestFromBundleAsJson(bundle);
-        expect(manifest, equals(expectedManifest));
-      });
-
-      testWithoutContext('Asset directories are recursively searched for assets', () async {
-        const String topLevelImage = 'assets/image.jpg';
-        const String secondLevelImage = 'assets/folder/secondLevel.jpg';
-        const String secondLevel2xVariant = 'assets/folder/2x/secondLevel.jpg';
-
-        final List<String> assets = <String>[
-          topLevelImage,
-          secondLevelImage,
-          secondLevel2xVariant
-        ];
-
-        for (final String asset in assets) {
-          final File assetFile = fs.file(asset);
-          assetFile.createSync(recursive: true);
-          assetFile.writeAsStringSync(asset);
-        }
-
-        final ManifestAssetBundle bundle = ManifestAssetBundle(
-          logger: BufferLogger.test(),
-          fileSystem: fs,
-          platform: platform,
-        );
-
-        await bundle.build(
-          packagesPath: '.packages',
-          flutterProject:  FlutterProject.fromDirectoryTest(fs.currentDirectory),
-        );
-
-        const String expectedManifest = '{'
-          '"$secondLevelImage":[{"asset":"$secondLevel2xVariant","dpr":2.0}],'
-          '"$topLevelImage":[]'
-        '}';
-
-        final String manifest = await extractAssetManifestFromBundleAsJson(bundle);
-        expect(manifest, equals(expectedManifest));
-      });
-
-      testWithoutContext('Asset paths should never be URI-encoded', () async {
-        const String image = 'assets/normalFolder/i have URI-reserved_characters.jpg';
-        const String imageVariant = 'assets/normalFolder/3x/i have URI-reserved_characters.jpg';
-
-        final List<String> assets = <String>[
-          image,
-          imageVariant
-        ];
-
-        for (final String asset in assets) {
-          final File assetFile = fs.file(asset);
-          assetFile.createSync(recursive: true);
-          assetFile.writeAsStringSync(asset);
-        }
-
-        final ManifestAssetBundle bundle = ManifestAssetBundle(
-          logger: BufferLogger.test(),
-          fileSystem: fs,
-          platform: platform,
-        );
-
-        await bundle.build(
-          packagesPath: '.packages',
-          flutterProject:  FlutterProject.fromDirectoryTest(fs.currentDirectory),
-        );
-
-        const String expectedManifest = '{"$image":[{"asset":"$imageVariant","dpr":3.0}]}';
-
-        final String manifest = await extractAssetManifestFromBundleAsJson(bundle);
-        expect(manifest, equals(expectedManifest));
-      });
+    sdk: flutter
+flutter:
+  assets:
+    - assets/
+'''
+      );
     });
 
+    testWithoutContext('Variant detection works with windows-style filepaths', () async {
+      const List<String> assets = <String>[
+        r'assets\foo.jpg',
+        r'assets\2x\foo.jpg',
+        r'assets\somewhereElse\bar.jpg',
+        r'assets\somewhereElse\2x\bar.jpg',
+      ];
 
-    group('AssetBundle asset variants (with Windows-style filepaths)', () {
-      late final Platform platform;
-      late final FileSystem fs;
+      for (final String asset in assets) {
+        final File assetFile = fs.file(asset);
+        assetFile.createSync(recursive: true);
+        assetFile.writeAsStringSync(asset);
+      }
 
-      setUp(() {
-        platform = FakePlatform(operatingSystem: 'windows');
-        fs = MemoryFileSystem.test(style: FileSystemStyle.windows);
-        Cache.flutterRoot = Cache.defaultFlutterRoot(
-          platform: platform,
-          fileSystem: fs,
-          userMessages: UserMessages()
-        );
+      final ManifestAssetBundle bundle = ManifestAssetBundle(
+        logger: BufferLogger.test(),
+        fileSystem: fs,
+        platform: platform,
+      );
 
-        fs.file('.packages').createSync();
+      await bundle.build(
+        packagesPath: '.packages',
+        flutterProject:  FlutterProject.fromDirectoryTest(fs.currentDirectory),
+      );
 
-        fs.file('pubspec.yaml').writeAsStringSync(
-  '''
-  name: test
-  dependencies:
-    flutter:
-      sdk: flutter
-  flutter:
-    assets:
-      - assets/
-  '''
-        );
-      });
+      final Map<String, List<String>> manifest = await extractAssetManifestFromBundle(bundle);
 
-      testWithoutContext('Variant detection works with windows-style filepaths', () async {
-        const List<String> assets = <String>[
-          r'assets\foo.jpg',
-          r'assets\2x\foo.jpg',
-          r'assets\somewhereElse\bar.jpg',
-          r'assets\somewhereElse\2x\bar.jpg',
-        ];
-
-        for (final String asset in assets) {
-          final File assetFile = fs.file(asset);
-          assetFile.createSync(recursive: true);
-          assetFile.writeAsStringSync(asset);
-        }
-
-        final ManifestAssetBundle bundle = ManifestAssetBundle(
-          logger: BufferLogger.test(),
-          fileSystem: fs,
-          platform: platform,
-        );
-
-        await bundle.build(
-          packagesPath: '.packages',
-          flutterProject:  FlutterProject.fromDirectoryTest(fs.currentDirectory),
-        );
-
-        const String expectedManifest = '{"assets/foo.jpg":[{"asset":"assets/2x/foo.jpg","dpr":2.0}],'
-        '"assets/somewhereElse/bar.jpg":[{"asset":"assets/somewhereElse/2x/bar.jpg","dpr":2.0}]}';
-
-        final String manifest = await extractAssetManifestFromBundleAsJson(bundle);
-        expect(manifest, equals(expectedManifest));
-      });
+      expect(manifest, hasLength(2));
+      expect(manifest['assets/foo.jpg'], equals(<String>['assets/foo.jpg', 'assets/2x/foo.jpg']));
+      expect(manifest['assets/somewhereElse/bar.jpg'], equals(<String>['assets/somewhereElse/bar.jpg', 'assets/somewhereElse/2x/bar.jpg']));
     });
   });
 }