Put shaders under a 'shaders' section in the manifest (#106752)
diff --git a/packages/flutter_tools/lib/src/asset.dart b/packages/flutter_tools/lib/src/asset.dart
index 1cae495..9dd7272 100644
--- a/packages/flutter_tools/lib/src/asset.dart
+++ b/packages/flutter_tools/lib/src/asset.dart
@@ -63,9 +63,17 @@
AssetBundle createBundle();
}
+enum AssetKind {
+ regular,
+ font,
+ shader,
+}
+
abstract class AssetBundle {
Map<String, DevFSContent> get entries;
+ Map<String, AssetKind> get entryKinds;
+
/// The files that were specified under the deferred components assets sections
/// in pubspec.
Map<String, Map<String, DevFSContent>> get deferredComponentsEntries;
@@ -136,6 +144,9 @@
final Map<String, DevFSContent> entries = <String, DevFSContent>{};
@override
+ final Map<String, AssetKind> entryKinds = <String, AssetKind>{};
+
+ @override
final Map<String, Map<String, DevFSContent>> deferredComponentsEntries = <String, Map<String, DevFSContent>>{};
@override
@@ -218,6 +229,7 @@
_lastBuildTimestamp = DateTime.now();
if (flutterManifest.isEmpty) {
entries[_kAssetManifestJson] = DevFSStringContent('{}');
+ entryKinds[_kAssetManifestJson] = AssetKind.regular;
return 0;
}
@@ -370,6 +382,7 @@
inputFiles.add(variantFile);
assert(variantFile.existsSync());
entries[variant.entryUri.path] ??= DevFSFileContent(variantFile);
+ entryKinds[variant.entryUri.path] ??= variant.assetKind;
}
}
// Save the contents of each deferred component image, image variant, and font
@@ -418,6 +431,7 @@
final File assetFile = asset.lookupAssetFile(_fileSystem);
assert(assetFile.existsSync(), 'Missing ${assetFile.path}');
entries[asset.entryUri.path] ??= DevFSFileContent(assetFile);
+ entryKinds[asset.entryUri.path] ??= asset.assetKind;
}
// Update wildcard directories we can detect changes in them.
@@ -449,8 +463,8 @@
_fileSystem.file('DOES_NOT_EXIST_RERUN_FOR_WILDCARD$suffix').absolute);
}
- _setIfChanged(_kAssetManifestJson, assetManifest);
- _setIfChanged(kFontManifestJson, fontManifest);
+ _setIfChanged(_kAssetManifestJson, assetManifest, AssetKind.regular);
+ _setIfChanged(kFontManifestJson, fontManifest, AssetKind.regular);
_setLicenseIfChanged(licenseResult.combinedLicenses, targetPlatform);
return 0;
}
@@ -458,14 +472,16 @@
@override
List<File> additionalDependencies = <File>[];
- void _setIfChanged(String key, DevFSStringContent content) {
+ void _setIfChanged(String key, DevFSStringContent content, AssetKind assetKind) {
if (!entries.containsKey(key)) {
entries[key] = content;
+ entryKinds[key] = assetKind;
return;
}
final DevFSStringContent? oldContent = entries[key] as DevFSStringContent?;
if (oldContent?.string != content.string) {
entries[key] = content;
+ entryKinds[key] = assetKind;
}
}
@@ -477,7 +493,7 @@
// dart:io to decompress it. So use the standard _setIfChanged to check if
// the strings still match.
if (targetPlatform == TargetPlatform.web_javascript) {
- _setIfChanged(_kNoticeFile, DevFSStringContent(combinedLicenses));
+ _setIfChanged(_kNoticeFile, DevFSStringContent(combinedLicenses), AssetKind.regular);
return;
}
@@ -495,6 +511,7 @@
// common English words with domain specific words like copyright.
hintString: 'copyrightsoftwaretothisinandorofthe',
);
+ entryKinds[_kNoticeZippedFile] = AssetKind.regular;
}
}
@@ -519,6 +536,7 @@
relativeUri: Uri(path: entryUri.pathSegments.last),
entryUri: entryUri,
package: null,
+ assetKind: AssetKind.font,
));
}
}
@@ -546,6 +564,7 @@
relativeUri: Uri(path: entryUri.pathSegments.last),
entryUri: entryUri,
package: null,
+ assetKind: AssetKind.shader,
));
}
@@ -745,6 +764,21 @@
}
}
+ for (final Uri shaderUri in flutterManifest.shaders) {
+ _parseAssetFromFile(
+ packageConfig,
+ flutterManifest,
+ assetBase,
+ cache,
+ result,
+ shaderUri,
+ excludeDirs: excludeDirs,
+ packageName: packageName,
+ attributedPackage: attributedPackage,
+ assetKind: AssetKind.shader,
+ );
+ }
+
// Add assets referenced in the fonts section of the manifest.
for (final Font font in flutterManifest.fonts) {
for (final FontAsset fontAsset in font.fontAssets) {
@@ -754,6 +788,7 @@
fontAsset.assetUri,
packageName,
attributedPackage,
+ assetKind: AssetKind.font,
);
final File baseAssetFile = baseAsset.lookupAssetFile(_fileSystem);
if (!baseAssetFile.existsSync()) {
@@ -816,6 +851,7 @@
List<String> excludeDirs = const <String>[],
String? packageName,
Package? attributedPackage,
+ AssetKind assetKind = AssetKind.regular,
}) {
final _Asset asset = _resolveAsset(
packageConfig,
@@ -823,6 +859,7 @@
assetUri,
packageName,
attributedPackage,
+ assetKind: assetKind,
);
final List<_Asset> variants = <_Asset>[];
final File assetFile = asset.lookupAssetFile(_fileSystem);
@@ -839,6 +876,7 @@
entryUri: entryUri,
relativeUri: relativeUri,
package: attributedPackage,
+ assetKind: assetKind,
),
);
}
@@ -852,8 +890,9 @@
String assetsBaseDir,
Uri assetUri,
String? packageName,
- Package? attributedPackage,
- ) {
+ Package? attributedPackage, {
+ AssetKind assetKind = AssetKind.regular,
+ }) {
final String assetPath = _fileSystem.path.fromUri(assetUri);
if (assetUri.pathSegments.first == 'packages'
&& !_fileSystem.isFileSync(_fileSystem.path.join(assetsBaseDir, assetPath))) {
@@ -863,6 +902,7 @@
assetUri,
packageConfig,
attributedPackage,
+ assetKind: assetKind,
);
if (packageAsset != null) {
return packageAsset;
@@ -876,10 +916,16 @@
: Uri(pathSegments: <String>['packages', packageName, ...assetUri.pathSegments]), // Asset from, and declared in $packageName.
relativeUri: assetUri,
package: attributedPackage,
+ assetKind: assetKind,
);
}
- _Asset? _resolvePackageAsset(Uri assetUri, PackageConfig packageConfig, Package? attributedPackage) {
+ _Asset? _resolvePackageAsset(
+ Uri assetUri,
+ PackageConfig packageConfig,
+ Package? attributedPackage, {
+ AssetKind assetKind = AssetKind.regular,
+ }) {
assert(assetUri.pathSegments.first == 'packages');
if (assetUri.pathSegments.length > 1) {
final String packageName = assetUri.pathSegments[1];
@@ -891,6 +937,7 @@
entryUri: assetUri,
relativeUri: Uri(pathSegments: assetUri.pathSegments.sublist(2)),
package: attributedPackage,
+ assetKind: assetKind,
);
}
}
@@ -910,6 +957,7 @@
required this.relativeUri,
required this.entryUri,
required this.package,
+ this.assetKind = AssetKind.regular,
});
final String baseDir;
@@ -923,6 +971,8 @@
/// A platform-independent URL representing the entry for the asset manifest.
final Uri entryUri;
+ final AssetKind assetKind;
+
File lookupAssetFile(FileSystem fileSystem) {
return fileSystem.file(fileSystem.path.join(baseDir, fileSystem.path.fromUri(relativeUri)));
}
@@ -951,7 +1001,8 @@
return other is _Asset
&& other.baseDir == baseDir
&& other.relativeUri == relativeUri
- && other.entryUri == entryUri;
+ && other.entryUri == entryUri
+ && other.assetKind == assetKind;
}
@override
diff --git a/packages/flutter_tools/lib/src/build_system/targets/assets.dart b/packages/flutter_tools/lib/src/build_system/targets/assets.dart
index a9e186b..5f458bd 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/assets.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/assets.dart
@@ -88,6 +88,9 @@
if (skslBundle != null)
kSkSLShaderBundlePath: skslBundle,
};
+ final Map<String, AssetKind> entryKinds = <String, AssetKind>{
+ ...assetBundle.entryKinds,
+ };
await Future.wait<void>(
assetEntries.entries.map<Future<void>>((MapEntry<String, DevFSContent> entry) async {
@@ -100,19 +103,31 @@
// and the native APIs will look for files this way.
final File file = environment.fileSystem.file(
environment.fileSystem.path.join(outputDirectory.path, entry.key));
+ final AssetKind assetKind = entryKinds[entry.key] ?? AssetKind.regular;
outputs.add(file);
file.parent.createSync(recursive: true);
final DevFSContent content = entry.value;
if (content is DevFSFileContent && content.file is File) {
inputs.add(content.file as File);
- if (!await iconTreeShaker.subsetFont(
- input: content.file as File,
- outputPath: file.path,
- relativePath: entry.key,
- ) && !await shaderCompiler.compileShader(
- input: content.file as File,
- outputPath: file.path,
- )) {
+ bool doCopy = true;
+ switch (assetKind) {
+ case AssetKind.regular:
+ break;
+ case AssetKind.font:
+ doCopy = !await iconTreeShaker.subsetFont(
+ input: content.file as File,
+ outputPath: file.path,
+ relativePath: entry.key,
+ );
+ break;
+ case AssetKind.shader:
+ doCopy = !await shaderCompiler.compileShader(
+ input: content.file as File,
+ outputPath: file.path,
+ );
+ break;
+ }
+ if (doCopy) {
await (content.file as File).copy(file.path);
}
} else {
@@ -127,8 +142,8 @@
// The assets are included in assetBundle.entries as a normal asset when
// building as debug.
if (environment.defines[kDeferredComponents] == 'true' && buildMode != null) {
- await Future.wait<void>(
- assetBundle.deferredComponentsEntries.entries.map<Future<void>>((MapEntry<String, Map<String, DevFSContent>> componentEntries) async {
+ await Future.wait<void>(assetBundle.deferredComponentsEntries.entries.map<Future<void>>(
+ (MapEntry<String, Map<String, DevFSContent>> componentEntries) async {
final Directory componentOutputDir =
environment.projectDir
.childDirectory('build')
diff --git a/packages/flutter_tools/lib/src/bundle_builder.dart b/packages/flutter_tools/lib/src/bundle_builder.dart
index 9a5f2f1..4317091 100644
--- a/packages/flutter_tools/lib/src/bundle_builder.dart
+++ b/packages/flutter_tools/lib/src/bundle_builder.dart
@@ -134,6 +134,7 @@
Future<void> writeBundle(
Directory bundleDir,
Map<String, DevFSContent> assetEntries,
+ Map<String, AssetKind> entryKinds,
{ Logger? loggerOverride }
) async {
loggerOverride ??= globals.logger;
diff --git a/packages/flutter_tools/lib/src/commands/test.dart b/packages/flutter_tools/lib/src/commands/test.dart
index d421070..748d01b 100644
--- a/packages/flutter_tools/lib/src/commands/test.dart
+++ b/packages/flutter_tools/lib/src/commands/test.dart
@@ -477,7 +477,7 @@
}
if (_needRebuild(assetBundle.entries)) {
await writeBundle(globals.fs.directory(globals.fs.path.join('build', 'unit_test_assets')),
- assetBundle.entries);
+ assetBundle.entries, assetBundle.entryKinds);
}
}
diff --git a/packages/flutter_tools/lib/src/flutter_manifest.dart b/packages/flutter_tools/lib/src/flutter_manifest.dart
index d58f5e0..37753b6 100644
--- a/packages/flutter_tools/lib/src/flutter_manifest.dart
+++ b/packages/flutter_tools/lib/src/flutter_manifest.dart
@@ -370,6 +370,33 @@
return fonts;
}
+
+ late final List<Uri> shaders = _extractShaders();
+
+ List<Uri> _extractShaders() {
+ if (!_flutterDescriptor.containsKey('shaders')) {
+ return <Uri>[];
+ }
+
+ final List<Object?>? shaders = _flutterDescriptor['shaders'] as List<Object?>?;
+ if (shaders == null) {
+ return const <Uri>[];
+ }
+ final List<Uri> results = <Uri>[];
+ for (final Object? shader in shaders) {
+ if (shader is! String || shader == null || shader == '') {
+ _logger.printError('Shader manifest contains a null or empty uri.');
+ continue;
+ }
+ try {
+ results.add(Uri(pathSegments: shader.split('/')));
+ } on FormatException {
+ _logger.printError('Shader manifest contains invalid uri: $shader.');
+ }
+ }
+ return results;
+ }
+
/// Whether a synthetic flutter_gen package should be generated.
///
/// This can be provided to the [Pub] interface to inject a new entry
@@ -498,7 +525,17 @@
break;
case 'assets':
if (yamlValue is! YamlList) {
-
+ errors.add('Expected "$yamlKey" to be a list, but got $yamlValue (${yamlValue.runtimeType}).');
+ } else if (yamlValue.isEmpty) {
+ break;
+ } else if (yamlValue[0] is! String) {
+ errors.add(
+ 'Expected "$yamlKey" to be a list of strings, but the first element is $yamlValue (${yamlValue.runtimeType}).',
+ );
+ }
+ break;
+ case 'shaders':
+ if (yamlValue is! YamlList) {
errors.add('Expected "$yamlKey" to be a list, but got $yamlValue (${yamlValue.runtimeType}).');
} else if (yamlValue.isEmpty) {
break;
diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_build.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_build.dart
index df23f5f..41a07fa 100644
--- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_build.dart
+++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_build.dart
@@ -124,9 +124,10 @@
throwToolExit('Unable to find assets.', exitCode: 1);
}
- final Map<String, DevFSContent> assetEntries =
- Map<String, DevFSContent>.of(assets.entries);
- await writeBundle(globals.fs.directory(assetDir), assetEntries);
+ final Map<String, DevFSContent> assetEntries = Map<String, DevFSContent>.of(
+ assets.entries,
+ );
+ await writeBundle(globals.fs.directory(assetDir), assetEntries, assets.entryKinds);
final String appName = fuchsiaProject.project.manifest.appName;
final String outDir = getFuchsiaBuildDirectory();
diff --git a/packages/flutter_tools/lib/src/isolated/devfs_web.dart b/packages/flutter_tools/lib/src/isolated/devfs_web.dart
index eb38d2e..4291bef 100644
--- a/packages/flutter_tools/lib/src/isolated/devfs_web.dart
+++ b/packages/flutter_tools/lib/src/isolated/devfs_web.dart
@@ -843,6 +843,7 @@
await writeBundle(
globals.fs.directory(getAssetBuildDirectory()),
bundle.entries,
+ bundle.entryKinds,
);
}
}
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 00d0dec..eb469dc 100644
--- a/packages/flutter_tools/test/general.shard/asset_bundle_test.dart
+++ b/packages/flutter_tools/test/general.shard/asset_bundle_test.dart
@@ -308,7 +308,12 @@
..createSync();
handler.addError(directory, FileSystemOp.delete, const FileSystemException('Expected Error Text'));
- await writeBundle(directory, <String, DevFSContent>{}, loggerOverride: testLogger);
+ await writeBundle(
+ directory,
+ <String, DevFSContent>{},
+ <String, AssetKind>{},
+ loggerOverride: testLogger,
+ );
expect(testLogger.warningText, contains('Expected Error Text'));
});
@@ -415,14 +420,19 @@
..writeAsStringSync(r'''
name: example
flutter:
- assets:
+ shaders:
- assets/shader.frag
''');
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
expect(await bundle.build(packagesPath: '.packages'), 0);
- await writeBundle(output, bundle.entries, loggerOverride: testLogger);
+ await writeBundle(
+ output,
+ bundle.entries,
+ bundle.entryKinds,
+ loggerOverride: testLogger,
+ );
}, overrides: <Type, Generator>{
Artifacts: () => artifacts,
diff --git a/packages/flutter_tools/test/general.shard/devfs_test.dart b/packages/flutter_tools/test/general.shard/devfs_test.dart
index e16c09f..0b0579b 100644
--- a/packages/flutter_tools/test/general.shard/devfs_test.dart
+++ b/packages/flutter_tools/test/general.shard/devfs_test.dart
@@ -633,6 +633,9 @@
Map<String, DevFSContent> get entries => <String, DevFSContent>{};
@override
+ Map<String, AssetKind> get entryKinds => <String, AssetKind>{};
+
+ @override
List<File> get inputFiles => <File>[];
@override