Handle empty entry in asset list and add more explicit validation (#41735)


diff --git a/packages/flutter_tools/lib/src/flutter_manifest.dart b/packages/flutter_tools/lib/src/flutter_manifest.dart
index 247a21d..5334b5b 100644
--- a/packages/flutter_tools/lib/src/flutter_manifest.dart
+++ b/packages/flutter_tools/lib/src/flutter_manifest.dart
@@ -186,16 +186,27 @@
         : fontList.map<Map<String, dynamic>>(castStringKeyedMap).toList();
   }
 
-  List<Uri> get assets {
+  List<Uri> get assets => _assets ??= _computeAssets();
+  List<Uri> _assets;
+  List<Uri> _computeAssets() {
     final List<dynamic> assets = _flutterDescriptor['assets'];
     if (assets == null) {
       return const <Uri>[];
     }
-    return assets
-        .cast<String>()
-        .map<String>(Uri.encodeFull)
-        ?.map<Uri>(Uri.parse)
-        ?.toList();
+    final List<Uri> results = <Uri>[];
+    for (Object asset in assets) {
+      if (asset is! String || asset == null || asset == '') {
+        printError('Asset manifest contains a null or empty uri.');
+        continue;
+      }
+      final String stringAsset = asset;
+      try {
+        results.add(Uri.parse(Uri.encodeFull(stringAsset)));
+      } on FormatException {
+        printError('Asset manifest contains invalid uri: $asset.');
+      }
+    }
+    return results;
   }
 
   List<Font> _fonts;
diff --git a/packages/flutter_tools/test/general.shard/flutter_manifest_test.dart b/packages/flutter_tools/test/general.shard/flutter_manifest_test.dart
index ef3c910..8432487 100644
--- a/packages/flutter_tools/test/general.shard/flutter_manifest_test.dart
+++ b/packages/flutter_tools/test/general.shard/flutter_manifest_test.dart
@@ -572,6 +572,26 @@
       expect(flutterManifest, null);
       expect(logger.errorText, contains('Expected a map.'));
     });
+
+    testUsingContext('Does not crash on empty entry', () async {
+      final BufferLogger logger = context.get<Logger>();
+      const String manifest = '''
+name: test
+dependencies:
+  flutter:
+    sdk: flutter
+flutter:
+  uses-material-design: true
+  assets:
+    - lib/gallery/example_code.dart
+    -
+''';
+      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
+      final List<Uri> assets = flutterManifest.assets;
+
+      expect(logger.errorText, contains('Asset manifest contains a null or empty uri.'));
+      expect(assets.length, 1);
+    });
   });
 
   group('FlutterManifest with MemoryFileSystem', () {