mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Tighten asset variant detection criteria to only include device-pixel-ratio variants (#110721)
This commit is contained in:
parent
2853a60133
commit
cb5b5c3459
@ -169,7 +169,6 @@ flutter:
|
||||
- packages/flutter_gallery_assets/products/table.png
|
||||
- packages/flutter_gallery_assets/products/teaset.png
|
||||
- packages/flutter_gallery_assets/products/top.png
|
||||
- packages/flutter_gallery_assets/people/ali.png
|
||||
- packages/flutter_gallery_assets/people/square/ali.png
|
||||
- packages/flutter_gallery_assets/people/square/peter.png
|
||||
- packages/flutter_gallery_assets/people/square/sandra.png
|
||||
|
@ -23,6 +23,9 @@ const String defaultManifestPath = 'pubspec.yaml';
|
||||
|
||||
const String kFontManifestJson = 'FontManifest.json';
|
||||
|
||||
// Should match '2x', '/1x', '1.5x', etc.
|
||||
final RegExp _assetVariantDirectoryRegExp = RegExp(r'/?(\d+(\.\d*)?)x$');
|
||||
|
||||
/// The effect of adding `uses-material-design: true` to the pubspec is to insert
|
||||
/// the following snippet into the asset manifest:
|
||||
///
|
||||
@ -92,7 +95,6 @@ abstract class AssetBundle {
|
||||
/// Returns 0 for success; non-zero for failure.
|
||||
Future<int> build({
|
||||
String manifestPath = defaultManifestPath,
|
||||
String? assetDirPath,
|
||||
required String packagesPath,
|
||||
bool deferredComponentsEnabled = false,
|
||||
TargetPlatform? targetPlatform,
|
||||
@ -205,23 +207,22 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
@override
|
||||
Future<int> build({
|
||||
String manifestPath = defaultManifestPath,
|
||||
String? assetDirPath,
|
||||
FlutterProject? flutterProject,
|
||||
required String packagesPath,
|
||||
bool deferredComponentsEnabled = false,
|
||||
TargetPlatform? targetPlatform,
|
||||
}) async {
|
||||
assetDirPath ??= getAssetBuildDirectory();
|
||||
FlutterProject flutterProject;
|
||||
try {
|
||||
flutterProject = FlutterProject.fromDirectory(_fileSystem.file(manifestPath).parent);
|
||||
} on Exception catch (e) {
|
||||
_logger.printStatus('Error detected in pubspec.yaml:', emphasis: true);
|
||||
_logger.printError('$e');
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (flutterProject == null) {
|
||||
return 1;
|
||||
try {
|
||||
flutterProject = FlutterProject.fromDirectory(_fileSystem.file(manifestPath).parent);
|
||||
} on Exception catch (e) {
|
||||
_logger.printStatus('Error detected in pubspec.yaml:', emphasis: true);
|
||||
_logger.printError('$e');
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
final FlutterManifest flutterManifest = flutterProject.manifest;
|
||||
// If the last build time isn't set before this early return, empty pubspecs will
|
||||
// hang on hot reload, as the incremental dill files will never be copied to the
|
||||
@ -243,27 +244,14 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
final List<Uri> wildcardDirectories = <Uri>[];
|
||||
|
||||
// The _assetVariants map contains an entry for each asset listed
|
||||
// in the pubspec.yaml file's assets and font and sections. The
|
||||
// in the pubspec.yaml file's assets and font sections. The
|
||||
// value of each image asset is a list of resolution-specific "variants",
|
||||
// see _AssetDirectoryCache.
|
||||
final List<String> excludeDirs = <String>[
|
||||
assetDirPath,
|
||||
getBuildDirectory(),
|
||||
if (flutterProject.ios.existsSync())
|
||||
flutterProject.ios.hostAppRoot.path,
|
||||
if (flutterProject.macos.existsSync())
|
||||
flutterProject.macos.managedDirectory.path,
|
||||
if (flutterProject.windows.existsSync())
|
||||
flutterProject.windows.managedDirectory.path,
|
||||
if (flutterProject.linux.existsSync())
|
||||
flutterProject.linux.managedDirectory.path,
|
||||
];
|
||||
final Map<_Asset, List<_Asset>>? assetVariants = _parseAssets(
|
||||
packageConfig,
|
||||
flutterManifest,
|
||||
wildcardDirectories,
|
||||
assetBasePath,
|
||||
excludeDirs: excludeDirs,
|
||||
);
|
||||
|
||||
if (assetVariants == null) {
|
||||
@ -277,7 +265,6 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
assetBasePath,
|
||||
wildcardDirectories,
|
||||
flutterProject.directory,
|
||||
excludeDirs: excludeDirs,
|
||||
);
|
||||
if (!_splitDeferredAssets || !deferredComponentsEnabled) {
|
||||
// Include the assets in the regular set of assets if not using deferred
|
||||
@ -373,8 +360,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
// variant files exist. An image's main entry is treated the same as a
|
||||
// "1x" resolution variant and if both exist then the explicit 1x
|
||||
// variant is preferred.
|
||||
if (assetFile.existsSync()) {
|
||||
assert(!variants.contains(asset));
|
||||
if (assetFile.existsSync() && !variants.contains(asset)) {
|
||||
variants.insert(0, asset);
|
||||
}
|
||||
for (final _Asset variant in variants) {
|
||||
@ -407,8 +393,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
// variant files exist. An image's main entry is treated the same as a
|
||||
// "1x" resolution variant and if both exist then the explicit 1x
|
||||
// variant is preferred.
|
||||
if (assetFile.existsSync()) {
|
||||
assert(!assetsMap[asset]!.contains(asset));
|
||||
if (assetFile.existsSync() && !assetsMap[asset]!.contains(asset)) {
|
||||
assetsMap[asset]!.insert(0, asset);
|
||||
}
|
||||
for (final _Asset variant in assetsMap[asset]!) {
|
||||
@ -606,7 +591,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
}
|
||||
for (final DeferredComponent component in components) {
|
||||
deferredComponentsAssetVariants[component.name] = <_Asset, List<_Asset>>{};
|
||||
final _AssetDirectoryCache cache = _AssetDirectoryCache(<String>[], _fileSystem);
|
||||
final _AssetDirectoryCache cache = _AssetDirectoryCache(_fileSystem);
|
||||
for (final Uri assetUri in component.assets) {
|
||||
if (assetUri.path.endsWith('/')) {
|
||||
wildcardDirectories.add(assetUri);
|
||||
@ -617,7 +602,6 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
cache,
|
||||
deferredComponentsAssetVariants[component.name]!,
|
||||
assetUri,
|
||||
excludeDirs: excludeDirs,
|
||||
);
|
||||
} else {
|
||||
_parseAssetFromFile(
|
||||
@ -728,13 +712,12 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
FlutterManifest flutterManifest,
|
||||
List<Uri> wildcardDirectories,
|
||||
String assetBase, {
|
||||
List<String> excludeDirs = const <String>[],
|
||||
String? packageName,
|
||||
Package? attributedPackage,
|
||||
}) {
|
||||
final Map<_Asset, List<_Asset>> result = <_Asset, List<_Asset>>{};
|
||||
|
||||
final _AssetDirectoryCache cache = _AssetDirectoryCache(excludeDirs, _fileSystem);
|
||||
final _AssetDirectoryCache cache = _AssetDirectoryCache(_fileSystem);
|
||||
for (final Uri assetUri in flutterManifest.assets) {
|
||||
if (assetUri.path.endsWith('/')) {
|
||||
wildcardDirectories.add(assetUri);
|
||||
@ -745,7 +728,6 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
cache,
|
||||
result,
|
||||
assetUri,
|
||||
excludeDirs: excludeDirs,
|
||||
packageName: packageName,
|
||||
attributedPackage: attributedPackage,
|
||||
);
|
||||
@ -757,7 +739,6 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
cache,
|
||||
result,
|
||||
assetUri,
|
||||
excludeDirs: excludeDirs,
|
||||
packageName: packageName,
|
||||
attributedPackage: attributedPackage,
|
||||
);
|
||||
@ -772,7 +753,6 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
cache,
|
||||
result,
|
||||
shaderUri,
|
||||
excludeDirs: excludeDirs,
|
||||
packageName: packageName,
|
||||
attributedPackage: attributedPackage,
|
||||
assetKind: AssetKind.shader,
|
||||
@ -808,7 +788,6 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
_AssetDirectoryCache cache,
|
||||
Map<_Asset, List<_Asset>> result,
|
||||
Uri assetUri, {
|
||||
List<String> excludeDirs = const <String>[],
|
||||
String? packageName,
|
||||
Package? attributedPackage,
|
||||
}) {
|
||||
@ -820,10 +799,9 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
return;
|
||||
}
|
||||
|
||||
final Iterable<File> files = _fileSystem
|
||||
.directory(directoryPath)
|
||||
.listSync()
|
||||
.whereType<File>();
|
||||
final Iterable<FileSystemEntity> entities = _fileSystem.directory(directoryPath).listSync();
|
||||
|
||||
final Iterable<File> files = entities.whereType<File>();
|
||||
for (final File file in files) {
|
||||
final String relativePath = _fileSystem.path.relative(file.path, from: assetBase);
|
||||
final Uri uri = Uri.file(relativePath, windows: _platform.isWindows);
|
||||
@ -839,6 +817,22 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
attributedPackage: attributedPackage,
|
||||
);
|
||||
}
|
||||
|
||||
final Iterable<Directory> nonVariantSubDirectories = entities
|
||||
.whereType<Directory>()
|
||||
.where((Directory directory) => !_assetVariantDirectoryRegExp.hasMatch(directory.basename));
|
||||
for (final Directory dir in nonVariantSubDirectories) {
|
||||
final String relativePath = _fileSystem.path.relative(dir.path, from: assetBase);
|
||||
final Uri relativePathsUri = Uri.directory(relativePath, windows: _platform.isWindows);
|
||||
|
||||
_parseAssetsFromFolder(packageConfig,
|
||||
flutterManifest,
|
||||
assetBase,
|
||||
cache,
|
||||
result,
|
||||
relativePathsUri
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _parseAssetFromFile(
|
||||
@ -1011,54 +1005,48 @@ class _Asset {
|
||||
|
||||
// Given an assets directory like this:
|
||||
//
|
||||
// assets/foo
|
||||
// assets/var1/foo
|
||||
// assets/var2/foo
|
||||
// assets/bar
|
||||
// assets/foo.png
|
||||
// assets/2x/foo.png
|
||||
// assets/3.0x/foo.png
|
||||
// assets/bar/foo.png
|
||||
// assets/bar.png
|
||||
//
|
||||
// variantsFor('assets/foo') => ['/assets/var1/foo', '/assets/var2/foo']
|
||||
// variantsFor('assets/bar') => []
|
||||
// variantsFor('assets/foo.png') => ['/assets/foo.png', '/assets/2x/foo.png', 'assets/3.0x/foo.png']
|
||||
// variantsFor('assets/bar.png') => ['/assets/bar.png']
|
||||
// variantsFor('assets/bar/foo.png') => ['/assets/bar/foo.png']
|
||||
class _AssetDirectoryCache {
|
||||
_AssetDirectoryCache(Iterable<String> excluded, this._fileSystem)
|
||||
: _excluded = excluded
|
||||
.map<String>(_fileSystem.path.absolute)
|
||||
.toList();
|
||||
_AssetDirectoryCache(this._fileSystem);
|
||||
|
||||
final FileSystem _fileSystem;
|
||||
final List<String> _excluded;
|
||||
final Map<String, Map<String, List<String>>> _cache = <String, Map<String, List<String>>>{};
|
||||
final Map<String, List<String>> _cache = <String, List<String>>{};
|
||||
|
||||
List<String> variantsFor(String assetPath) {
|
||||
final String assetName = _fileSystem.path.basename(assetPath);
|
||||
final String directory = _fileSystem.path.dirname(assetPath);
|
||||
|
||||
if (!_fileSystem.directory(directory).existsSync()) {
|
||||
return const <String>[];
|
||||
}
|
||||
|
||||
if (_cache[directory] == null) {
|
||||
final List<String> paths = <String>[];
|
||||
for (final FileSystemEntity entity in _fileSystem.directory(directory).listSync(recursive: true)) {
|
||||
final String path = entity.path;
|
||||
if (_fileSystem.isFileSync(path)
|
||||
&& assetPath != path
|
||||
&& !_excluded.any((String exclude) => _fileSystem.path.isWithin(exclude, path))) {
|
||||
paths.add(path);
|
||||
}
|
||||
}
|
||||
|
||||
final Map<String, List<String>> variants = <String, List<String>>{};
|
||||
for (final String path in paths) {
|
||||
final String variantName = _fileSystem.path.basename(path);
|
||||
if (directory == _fileSystem.path.dirname(path)) {
|
||||
continue;
|
||||
}
|
||||
variants[variantName] ??= <String>[];
|
||||
variants[variantName]!.add(path);
|
||||
}
|
||||
_cache[directory] = variants;
|
||||
if (_cache.containsKey(assetPath)) {
|
||||
return _cache[assetPath]!;
|
||||
}
|
||||
|
||||
return _cache[directory]![assetName] ?? const <String>[];
|
||||
final List<FileSystemEntity> entitiesInDirectory = _fileSystem.directory(directory).listSync();
|
||||
|
||||
final List<String> pathsOfVariants = <String>[
|
||||
// It's possible that the user specifies only explicit variants (e.g. .../1x/asset.png),
|
||||
// so there does not necessarily need to be a file at the given path.
|
||||
if (_fileSystem.file(assetPath).existsSync())
|
||||
assetPath,
|
||||
...entitiesInDirectory
|
||||
.whereType<Directory>()
|
||||
.where((Directory dir) => _assetVariantDirectoryRegExp.hasMatch(dir.basename))
|
||||
.expand((Directory dir) => dir.listSync())
|
||||
.whereType<File>()
|
||||
.map((File file) => file.path),
|
||||
];
|
||||
|
||||
_cache[assetPath] = pathsOfVariants;
|
||||
return pathsOfVariants;
|
||||
}
|
||||
}
|
||||
|
@ -121,7 +121,6 @@ Future<AssetBundle?> buildAssets({
|
||||
final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle();
|
||||
final int result = await assetBundle.build(
|
||||
manifestPath: manifestPath,
|
||||
assetDirPath: assetDirPath,
|
||||
packagesPath: packagesPath,
|
||||
targetPlatform: targetPlatform,
|
||||
);
|
||||
|
@ -222,11 +222,11 @@ $assetsSection
|
||||
assets: <String>['a/foo'],
|
||||
);
|
||||
|
||||
final List<String> assets = <String>['a/foo', 'a/v/foo'];
|
||||
final List<String> assets = <String>['a/foo', 'a/2x/foo'];
|
||||
writeAssets('p/p/', assets);
|
||||
|
||||
const String expectedManifest = '{"packages/test_package/a/foo":'
|
||||
'["packages/test_package/a/foo","packages/test_package/a/v/foo"]}';
|
||||
'["packages/test_package/a/foo","packages/test_package/a/2x/foo"]}';
|
||||
|
||||
await buildAndVerifyAssets(
|
||||
assets,
|
||||
@ -251,11 +251,11 @@ $assetsSection
|
||||
'test_package',
|
||||
);
|
||||
|
||||
final List<String> assets = <String>['a/foo', 'a/v/foo'];
|
||||
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/v/foo"]}';
|
||||
'["packages/test_package/a/foo","packages/test_package/a/2x/foo"]}';
|
||||
|
||||
await buildAndVerifyAssets(
|
||||
assets,
|
||||
@ -344,15 +344,15 @@ $assetsSection
|
||||
assets: <String>['a/foo'],
|
||||
);
|
||||
|
||||
final List<String> assets = <String>['a/foo', 'a/v/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/v/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/v/foo"]}';
|
||||
'["packages/test_package2/a/foo","packages/test_package2/a/2x/foo"]}';
|
||||
|
||||
await buildAndVerifyAssets(
|
||||
assets,
|
||||
@ -384,15 +384,15 @@ $assetsSection
|
||||
'test_package2',
|
||||
);
|
||||
|
||||
final List<String> assets = <String>['a/foo', 'a/v/foo'];
|
||||
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/v/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/v/foo"]}';
|
||||
'["packages/test_package2/a/foo","packages/test_package2/a/2x/foo"]}';
|
||||
|
||||
await buildAndVerifyAssets(
|
||||
assets,
|
||||
@ -421,12 +421,12 @@ $assetsSection
|
||||
'test_package2',
|
||||
);
|
||||
|
||||
final List<String> assets = <String>['a/foo', 'a/v/foo'];
|
||||
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/v/foo"]}';
|
||||
'["packages/test_package2/a/foo","packages/test_package2/a/2x/foo"]}';
|
||||
|
||||
await buildAndVerifyAssets(
|
||||
assets,
|
||||
@ -553,7 +553,7 @@ $assetsSection
|
||||
writePubspecFile('pubspec.yaml', 'test');
|
||||
writePackagesFile('test_package:p/p/lib/');
|
||||
|
||||
final List<String> assetsOnDisk = <String>['a/foo','a/b/foo'];
|
||||
final List<String> assetsOnDisk = <String>['a/foo','a/2x/foo'];
|
||||
final List<String> assetOnManifest = <String>['a/',];
|
||||
|
||||
writePubspecFile(
|
||||
@ -564,7 +564,7 @@ $assetsSection
|
||||
|
||||
writeAssets('p/p/', assetsOnDisk);
|
||||
const String expectedAssetManifest =
|
||||
'{"packages/test_package/a/foo":["packages/test_package/a/foo","packages/test_package/a/b/foo"]}';
|
||||
'{"packages/test_package/a/foo":["packages/test_package/a/foo","packages/test_package/a/2x/foo"]}';
|
||||
|
||||
await buildAndVerifyAssets(
|
||||
assetsOnDisk,
|
||||
@ -580,7 +580,7 @@ $assetsSection
|
||||
writePubspecFile('pubspec.yaml', 'test');
|
||||
writePackagesFile('test_package:p/p/lib/');
|
||||
|
||||
final List<String> assetsOnDisk = <String>['a/foo', 'a/b/foo'];
|
||||
final List<String> assetsOnDisk = <String>['a/foo', 'a/2x/foo'];
|
||||
final List<String> assetOnManifest = <String>[];
|
||||
|
||||
writePubspecFile(
|
||||
|
@ -643,7 +643,7 @@ name: example
|
||||
|
||||
flutter:
|
||||
assets:
|
||||
- foo.txt
|
||||
- assets/foo.txt
|
||||
''');
|
||||
globals.fs.file('assets/foo.txt').createSync(recursive: true);
|
||||
|
||||
|
@ -9,37 +9,43 @@ import 'package:file/memory.dart';
|
||||
|
||||
import 'package:flutter_tools/src/asset.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:flutter_tools/src/base/user_messages.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
|
||||
import '../src/common.dart';
|
||||
import '../src/context.dart';
|
||||
|
||||
void main() {
|
||||
String fixPath(String path) {
|
||||
// The in-memory file system is strict about slashes on Windows being the
|
||||
// correct way so until https://github.com/google/file.dart/issues/112 is
|
||||
// fixed we fix them here.
|
||||
// TODO(dantup): Remove this function once the above issue is fixed and
|
||||
// rolls into Flutter.
|
||||
return path.replaceAll('/', globals.fs.path.separator);
|
||||
|
||||
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', () {
|
||||
late FileSystem testFileSystem;
|
||||
setUp(() async {
|
||||
testFileSystem = MemoryFileSystem(
|
||||
style: globals.platform.isWindows
|
||||
? FileSystemStyle.windows
|
||||
: FileSystemStyle.posix,
|
||||
);
|
||||
testFileSystem.currentDirectory = testFileSystem.systemTempDirectory.createTempSync('flutter_asset_bundle_variant_test.');
|
||||
});
|
||||
group('AssetBundle asset variants (with POSIX-style paths)', () {
|
||||
late final Platform platform;
|
||||
late final FileSystem fs;
|
||||
|
||||
testUsingContext('main asset and variants', () async {
|
||||
globals.fs.file('pubspec.yaml')
|
||||
..createSync()
|
||||
..writeAsStringSync(
|
||||
setUpAll(() {
|
||||
platform = FakePlatform();
|
||||
fs = MemoryFileSystem.test();
|
||||
Cache.flutterRoot = Cache.defaultFlutterRoot(
|
||||
platform: platform,
|
||||
fileSystem: fs,
|
||||
userMessages: UserMessages()
|
||||
);
|
||||
|
||||
fs.file('.packages').createSync();
|
||||
|
||||
fs.file('pubspec.yaml').writeAsStringSync(
|
||||
'''
|
||||
name: test
|
||||
dependencies:
|
||||
@ -47,46 +53,187 @@ dependencies:
|
||||
sdk: flutter
|
||||
flutter:
|
||||
assets:
|
||||
- a/b/c/foo
|
||||
- assets/
|
||||
'''
|
||||
);
|
||||
globals.fs.file('.packages').createSync();
|
||||
});
|
||||
|
||||
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>[
|
||||
'a/b/c/foo',
|
||||
'a/b/c/var1/foo',
|
||||
'a/b/c/var2/foo',
|
||||
'a/b/c/var3/foo',
|
||||
image,
|
||||
image2xVariant,
|
||||
imageNonVariant
|
||||
];
|
||||
|
||||
for (final String asset in assets) {
|
||||
globals.fs.file(fixPath(asset))
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync(asset);
|
||||
final File assetFile = fs.file(asset);
|
||||
assetFile.createSync(recursive: true);
|
||||
assetFile.writeAsStringSync(asset);
|
||||
}
|
||||
|
||||
AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
await bundle.build(packagesPath: '.packages');
|
||||
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);
|
||||
final List<String> variantsForImage = manifest[image]!;
|
||||
|
||||
expect(variantsForImage, contains(image2xVariant));
|
||||
expect(variantsForImage, isNot(contains(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
|
||||
];
|
||||
|
||||
// The main asset file, /a/b/c/foo, and its variants exist.
|
||||
for (final String asset in assets) {
|
||||
expect(bundle.entries.containsKey(asset), true);
|
||||
expect(utf8.decode(await bundle.entries[asset]!.contentsAsBytes()), asset);
|
||||
final File assetFile = fs.file(asset);
|
||||
assetFile.createSync(recursive: true);
|
||||
assetFile.writeAsStringSync(asset);
|
||||
}
|
||||
|
||||
globals.fs.file(fixPath('a/b/c/foo')).deleteSync();
|
||||
bundle = AssetBundleFactory.instance.createBundle();
|
||||
await bundle.build(packagesPath: '.packages');
|
||||
final ManifestAssetBundle bundle = ManifestAssetBundle(
|
||||
logger: BufferLogger.test(),
|
||||
fileSystem: fs,
|
||||
platform: platform,
|
||||
);
|
||||
|
||||
// Now the main asset file, /a/b/c/foo, does not exist. This is OK because
|
||||
// the /a/b/c/*/foo variants do exist.
|
||||
expect(bundle.entries.containsKey('a/b/c/foo'), false);
|
||||
for (final String asset in assets.skip(1)) {
|
||||
expect(bundle.entries.containsKey(asset), true);
|
||||
expect(utf8.decode(await bundle.entries[asset]!.contentsAsBytes()), asset);
|
||||
await bundle.build(
|
||||
packagesPath: '.packages',
|
||||
flutterProject: FlutterProject.fromDirectoryTest(fs.currentDirectory),
|
||||
);
|
||||
|
||||
final Map<String, List<String>> manifest = await extractAssetManifestFromBundle(bundle);
|
||||
expect(manifest, contains(secondLevelImage));
|
||||
expect(manifest, contains(topLevelImage));
|
||||
expect(manifest[secondLevelImage], hasLength(2));
|
||||
expect(manifest[secondLevelImage], contains(secondLevelImage));
|
||||
expect(manifest[secondLevelImage], contains(secondLevel2xVariant));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
group('AssetBundle asset variants (with Windows-style filepaths)', () {
|
||||
late final Platform platform;
|
||||
late final FileSystem fs;
|
||||
|
||||
String correctPathSeparators(String path) {
|
||||
// The in-memory file system is strict about slashes on Windows being the
|
||||
// correct way. See https://github.com/google/file.dart/issues/112.
|
||||
return path.replaceAll('/', fs.path.separator);
|
||||
}
|
||||
|
||||
setUpAll(() {
|
||||
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('pubspec.yaml').writeAsStringSync(
|
||||
'''
|
||||
name: test
|
||||
dependencies:
|
||||
flutter:
|
||||
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';
|
||||
|
||||
final List<String> assets = <String>[
|
||||
image,
|
||||
image2xVariant,
|
||||
imageNonVariant
|
||||
];
|
||||
|
||||
for (final String asset in assets) {
|
||||
final File assetFile = fs.file(correctPathSeparators(asset));
|
||||
assetFile.createSync(recursive: true);
|
||||
assetFile.writeAsStringSync(asset);
|
||||
}
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => testFileSystem,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
|
||||
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);
|
||||
final List<String> variantsForImage = manifest[image]!;
|
||||
|
||||
expect(variantsForImage, contains(image2xVariant));
|
||||
expect(variantsForImage, isNot(contains(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(correctPathSeparators(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, contains(secondLevelImage));
|
||||
expect(manifest, contains(topLevelImage));
|
||||
expect(manifest[secondLevelImage], hasLength(2));
|
||||
expect(manifest[secondLevelImage], contains(secondLevelImage));
|
||||
expect(manifest[secondLevelImage], contains(secondLevel2xVariant));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user