mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
feat(assets): add platform-specific asset filtering in pubspec.yaml (#176393)
## Description
This PR introduces platform-specific asset support in `pubspec.yaml`.
Currently, Flutter does not allow specifying which platforms an asset
should be included for.
This results in all declared assets being bundled for every target
platform, even if some are irrelevant (e.g. desktop-only or mobile-only
images).
### What this PR changes
- Adds a new optional `platforms` field under each asset in
`pubspec.yaml`.
- The field accepts a list of strings (platform identifiers, e.g.
`["android", "ios", "web", "windows", "macos", "linux"]`).
- Assets with a `platforms` restriction are only included in the bundle
when building for a matching platform.
- Invalid values (non-strings or unknown platform names) log an error.
### Example
```yaml
flutter:
assets:
- path: assets/logo.png
- path: assets/web_worker.js
platforms: [web]
- path: assets/desktop_icon.png
platforms: [windows, linux, macos]
```
#### Before
All assets (`logo.png`, `web_worker.js`, `desktop_icon.png`) are bundled
into **every build**, regardless of platform.
#### After
- `logo.png` is included on all platforms.
- `web_worker.js` is included only on web builds.
- `desktop_icon.png` is included only on desktop builds.
### Why this is useful
This significantly improves bundle size, prevents unused resources from
being shipped, and gives developers better control over asset
management.
## Issues
Fixes #65065
## Reviewer note
Would a design document be helpful for this change, or is the current
explanation sufficient?
## Pre-launch Checklist
- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.
<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
parent
ef29db350f
commit
5239c8db48
@ -195,7 +195,7 @@ abstract class AssetBundle {
|
||||
String manifestPath = defaultManifestPath,
|
||||
required String packageConfigPath,
|
||||
bool deferredComponentsEnabled = false,
|
||||
TargetPlatform? targetPlatform,
|
||||
required TargetPlatform targetPlatform,
|
||||
String? flavor,
|
||||
bool includeAssetsFromDevDependencies = false,
|
||||
});
|
||||
@ -326,7 +326,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
FlutterProject? flutterProject,
|
||||
required String packageConfigPath,
|
||||
bool deferredComponentsEnabled = false,
|
||||
TargetPlatform? targetPlatform,
|
||||
required TargetPlatform targetPlatform,
|
||||
String? flavor,
|
||||
bool includeAssetsFromDevDependencies = false,
|
||||
}) async {
|
||||
@ -402,6 +402,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
assetBasePath,
|
||||
wildcardDirectories,
|
||||
flutterProject.directory,
|
||||
targetPlatform: targetPlatform,
|
||||
flavor: flavor,
|
||||
);
|
||||
if (!_splitDeferredAssets || !deferredComponentsEnabled) {
|
||||
@ -716,7 +717,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
}
|
||||
}
|
||||
|
||||
void _setLicenseIfChanged(String combinedLicenses, TargetPlatform? targetPlatform) {
|
||||
void _setLicenseIfChanged(String combinedLicenses, TargetPlatform targetPlatform) {
|
||||
// On the web, don't compress the NOTICES file since the client doesn't have
|
||||
// dart:io to decompress it. So use the standard _setIfChanged to check if
|
||||
// the strings still match.
|
||||
@ -838,6 +839,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
String assetBasePath,
|
||||
List<Uri> wildcardDirectories,
|
||||
Directory projectDirectory, {
|
||||
required TargetPlatform targetPlatform,
|
||||
String? flavor,
|
||||
}) {
|
||||
final List<DeferredComponent>? components = flutterManifest.deferredComponents;
|
||||
@ -859,6 +861,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
componentAssets,
|
||||
assetsEntry.uri,
|
||||
flavors: assetsEntry.flavors,
|
||||
platforms: assetsEntry.platforms,
|
||||
transformers: assetsEntry.transformers,
|
||||
);
|
||||
} else {
|
||||
@ -870,13 +873,15 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
componentAssets,
|
||||
assetsEntry.uri,
|
||||
flavors: assetsEntry.flavors,
|
||||
platforms: assetsEntry.platforms,
|
||||
transformers: assetsEntry.transformers,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
componentAssets.removeWhere(
|
||||
(_Asset asset, List<_Asset> variants) => !asset.matchesFlavor(flavor),
|
||||
(_Asset asset, List<_Asset> variants) =>
|
||||
!asset.matchesFlavor(flavor) || !asset.matchesPlatform(targetPlatform),
|
||||
);
|
||||
deferredComponentsAssetVariants[component.name] = componentAssets;
|
||||
}
|
||||
@ -1018,7 +1023,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
FlutterManifest flutterManifest,
|
||||
List<Uri> wildcardDirectories,
|
||||
String assetBase,
|
||||
TargetPlatform? targetPlatform, {
|
||||
TargetPlatform targetPlatform, {
|
||||
String? packageName,
|
||||
Package? attributedPackage,
|
||||
required String? flavor,
|
||||
@ -1039,6 +1044,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
packageName: packageName,
|
||||
attributedPackage: attributedPackage,
|
||||
flavors: assetsEntry.flavors,
|
||||
platforms: assetsEntry.platforms,
|
||||
transformers: assetsEntry.transformers,
|
||||
);
|
||||
} else {
|
||||
@ -1052,6 +1058,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
packageName: packageName,
|
||||
attributedPackage: attributedPackage,
|
||||
flavors: assetsEntry.flavors,
|
||||
platforms: assetsEntry.platforms,
|
||||
transformers: assetsEntry.transformers,
|
||||
);
|
||||
}
|
||||
@ -1066,6 +1073,15 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
);
|
||||
return true;
|
||||
}
|
||||
if (!asset.matchesPlatform(targetPlatform)) {
|
||||
_logger.printTrace(
|
||||
'Skipping assets entry "${asset.entryUri.path}" since '
|
||||
'its configured platform(s) did not match the target platform.\n'
|
||||
'Configured platforms: ${asset.platforms.join(', ')}\n'
|
||||
'Target platform: ${targetPlatform.osName}\n',
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
@ -1101,6 +1117,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
attributedPackage: attributedPackage,
|
||||
assetKind: AssetKind.shader,
|
||||
flavors: <String>{},
|
||||
platforms: <String>{},
|
||||
transformers: <AssetTransformerEntry>[],
|
||||
);
|
||||
}
|
||||
@ -1116,6 +1133,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
attributedPackage,
|
||||
assetKind: AssetKind.font,
|
||||
flavors: <String>{},
|
||||
platforms: <String>{},
|
||||
transformers: <AssetTransformerEntry>[],
|
||||
);
|
||||
final File baseAssetFile = baseAsset.lookupAssetFile(_fileSystem);
|
||||
@ -1142,6 +1160,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
String? packageName,
|
||||
Package? attributedPackage,
|
||||
required Set<String> flavors,
|
||||
required Set<String> platforms,
|
||||
required List<AssetTransformerEntry> transformers,
|
||||
}) {
|
||||
final String directoryPath;
|
||||
@ -1174,6 +1193,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
attributedPackage: attributedPackage,
|
||||
originUri: assetUri,
|
||||
flavors: flavors,
|
||||
platforms: platforms,
|
||||
transformers: transformers,
|
||||
);
|
||||
}
|
||||
@ -1191,6 +1211,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
Package? attributedPackage,
|
||||
AssetKind assetKind = AssetKind.regular,
|
||||
required Set<String> flavors,
|
||||
required Set<String> platforms,
|
||||
required List<AssetTransformerEntry> transformers,
|
||||
}) {
|
||||
final _Asset asset = _resolveAsset(
|
||||
@ -1202,6 +1223,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
assetKind: assetKind,
|
||||
originUri: originUri,
|
||||
flavors: flavors,
|
||||
platforms: platforms,
|
||||
transformers: transformers,
|
||||
);
|
||||
|
||||
@ -1225,6 +1247,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
package: attributedPackage,
|
||||
kind: assetKind,
|
||||
flavors: flavors,
|
||||
platforms: platforms,
|
||||
transformers: transformers,
|
||||
),
|
||||
);
|
||||
@ -1335,6 +1358,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
Uri? originUri,
|
||||
AssetKind assetKind = AssetKind.regular,
|
||||
required Set<String> flavors,
|
||||
required Set<String> platforms,
|
||||
required List<AssetTransformerEntry> transformers,
|
||||
}) {
|
||||
_ensureAssetPathIsValid(assetsBaseDir: assetsBaseDir, assetUri: assetUri);
|
||||
@ -1351,6 +1375,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
assetKind: assetKind,
|
||||
originUri: originUri,
|
||||
flavors: flavors,
|
||||
platforms: platforms,
|
||||
transformers: transformers,
|
||||
);
|
||||
if (packageAsset != null) {
|
||||
@ -1370,6 +1395,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
originUri: originUri,
|
||||
kind: assetKind,
|
||||
flavors: flavors,
|
||||
platforms: platforms,
|
||||
transformers: transformers,
|
||||
);
|
||||
}
|
||||
@ -1381,6 +1407,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
AssetKind assetKind = AssetKind.regular,
|
||||
Uri? originUri,
|
||||
Set<String>? flavors,
|
||||
Set<String>? platforms,
|
||||
List<AssetTransformerEntry>? transformers,
|
||||
}) {
|
||||
assert(assetUri.pathSegments.first == 'packages');
|
||||
@ -1397,6 +1424,7 @@ class ManifestAssetBundle implements AssetBundle {
|
||||
kind: assetKind,
|
||||
originUri: originUri,
|
||||
flavors: flavors,
|
||||
platforms: platforms,
|
||||
transformers: transformers,
|
||||
);
|
||||
}
|
||||
@ -1420,9 +1448,11 @@ class _Asset {
|
||||
required this.package,
|
||||
this.kind = AssetKind.regular,
|
||||
Set<String>? flavors,
|
||||
Set<String>? platforms,
|
||||
List<AssetTransformerEntry>? transformers,
|
||||
}) : originUri = originUri ?? entryUri,
|
||||
flavors = flavors ?? const <String>{},
|
||||
platforms = platforms ?? const <String>{},
|
||||
transformers = transformers ?? const <AssetTransformerEntry>[];
|
||||
|
||||
final String baseDir;
|
||||
@ -1444,6 +1474,8 @@ class _Asset {
|
||||
|
||||
final Set<String> flavors;
|
||||
|
||||
final Set<String> platforms;
|
||||
|
||||
final List<AssetTransformerEntry> transformers;
|
||||
|
||||
File lookupAssetFile(FileSystem fileSystem) {
|
||||
@ -1472,11 +1504,20 @@ class _Asset {
|
||||
return flavors.contains(flavor);
|
||||
}
|
||||
|
||||
bool matchesPlatform(TargetPlatform targetPlatform) {
|
||||
if (platforms.isEmpty || targetPlatform == TargetPlatform.tester) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return platforms.contains(targetPlatform.osName);
|
||||
}
|
||||
|
||||
bool hasEquivalentFlavorsWith(_Asset other) {
|
||||
final Set<String> assetFlavors = flavors.toSet();
|
||||
final Set<String> otherFlavors = other.flavors.toSet();
|
||||
return assetFlavors.length == otherFlavors.length &&
|
||||
assetFlavors.every((String e) => otherFlavors.contains(e));
|
||||
return setEquals(flavors, other.flavors);
|
||||
}
|
||||
|
||||
bool hasEquivalentPlatformsWith(_Asset other) {
|
||||
return setEquals(platforms, other.platforms);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -1495,11 +1536,13 @@ class _Asset {
|
||||
other.relativeUri == relativeUri &&
|
||||
other.entryUri == entryUri &&
|
||||
other.kind == kind &&
|
||||
hasEquivalentFlavorsWith(other);
|
||||
hasEquivalentFlavorsWith(other) &&
|
||||
hasEquivalentPlatformsWith(other);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hashAll(<Object>[baseDir, relativeUri, entryUri, kind, ...flavors]);
|
||||
int get hashCode =>
|
||||
Object.hashAll(<Object>[baseDir, relativeUri, entryUri, kind, ...flavors, ...platforms]);
|
||||
}
|
||||
|
||||
// Given an assets directory like this:
|
||||
|
||||
@ -108,6 +108,9 @@ class DeferredComponent {
|
||||
if (asset.flavors.isNotEmpty) {
|
||||
out.write(' (flavors: ${asset.flavors.join(', ')})');
|
||||
}
|
||||
if (asset.platforms.isNotEmpty) {
|
||||
out.write(' (platforms: ${asset.platforms.join(', ')})');
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
@ -269,7 +269,10 @@ class CopyAssets extends Target {
|
||||
List<String> get depfiles => const <String>['flutter_assets.d'];
|
||||
|
||||
@override
|
||||
Future<void> build(Environment environment) async {
|
||||
Future<void> build(
|
||||
Environment environment, {
|
||||
TargetPlatform targetPlatform = TargetPlatform.android,
|
||||
}) async {
|
||||
final String? buildModeEnvironment = environment.defines[kBuildMode];
|
||||
if (buildModeEnvironment == null) {
|
||||
throw MissingDefineException(kBuildMode, name);
|
||||
@ -282,7 +285,7 @@ class CopyAssets extends Target {
|
||||
environment,
|
||||
output,
|
||||
dartHookResult: dartHookResult,
|
||||
targetPlatform: TargetPlatform.android,
|
||||
targetPlatform: targetPlatform,
|
||||
buildMode: buildMode,
|
||||
flavor: environment.defines[kFlavor],
|
||||
additionalContent: <String, DevFSContent>{
|
||||
|
||||
@ -108,7 +108,7 @@ Future<AssetBundle?> buildAssets({
|
||||
required String manifestPath,
|
||||
String? assetDirPath,
|
||||
required String packageConfigPath,
|
||||
TargetPlatform? targetPlatform,
|
||||
required TargetPlatform targetPlatform,
|
||||
String? flavor,
|
||||
}) async {
|
||||
assetDirPath ??= getAssetBuildDirectory();
|
||||
|
||||
@ -769,6 +769,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
|
||||
packageConfigPath: packageConfigPath,
|
||||
flavor: flavor,
|
||||
includeAssetsFromDevDependencies: true,
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
if (build != 0) {
|
||||
throwToolExit('Error: Failed to build asset bundle');
|
||||
|
||||
@ -788,20 +788,23 @@ class AssetsEntry {
|
||||
const AssetsEntry({
|
||||
required this.uri,
|
||||
this.flavors = const <String>{},
|
||||
this.platforms = const <String>{},
|
||||
this.transformers = const <AssetTransformerEntry>[],
|
||||
});
|
||||
|
||||
final Uri uri;
|
||||
final Set<String> flavors;
|
||||
final Set<String> platforms;
|
||||
final List<AssetTransformerEntry> transformers;
|
||||
|
||||
Object? get descriptor {
|
||||
if (transformers.isEmpty && flavors.isEmpty) {
|
||||
if (transformers.isEmpty && flavors.isEmpty && platforms.isEmpty) {
|
||||
return uri.toString();
|
||||
}
|
||||
return <String, Object?>{
|
||||
_pathKey: uri.toString(),
|
||||
if (flavors.isNotEmpty) _flavorKey: flavors.toList(),
|
||||
if (platforms.isNotEmpty) _platformsKey: platforms.toList(),
|
||||
if (transformers.isNotEmpty)
|
||||
_transformersKey: transformers.map((AssetTransformerEntry e) => e.descriptor).toList(),
|
||||
};
|
||||
@ -809,6 +812,7 @@ class AssetsEntry {
|
||||
|
||||
static const _pathKey = 'path';
|
||||
static const _flavorKey = 'flavors';
|
||||
static const _platformsKey = 'platforms';
|
||||
static const _transformersKey = 'transformers';
|
||||
|
||||
static AssetsEntry? parseFromYaml(Object? yaml) {
|
||||
@ -856,11 +860,15 @@ class AssetsEntry {
|
||||
final (List<String>? flavors, List<String> flavorsErrors) = _parseFlavorsSection(
|
||||
yaml[_flavorKey],
|
||||
);
|
||||
final (List<String>? platforms, List<String> platformsErrors) = _parsePlatformsSection(
|
||||
yaml[_platformsKey],
|
||||
);
|
||||
final (List<AssetTransformerEntry>? transformers, List<String> transformersErrors) =
|
||||
_parseTransformersSection(yaml[_transformersKey]);
|
||||
|
||||
final errors = <String>[
|
||||
...flavorsErrors.map((String e) => 'In $_flavorKey section of asset "$path": $e'),
|
||||
...platformsErrors.map((String e) => 'In $_platformsKey section of asset "$path": $e'),
|
||||
...transformersErrors.map(
|
||||
(String e) => 'In $_transformersKey section of asset "$path": $e',
|
||||
),
|
||||
@ -873,6 +881,7 @@ class AssetsEntry {
|
||||
AssetsEntry(
|
||||
uri: Uri(pathSegments: path.split('/')),
|
||||
flavors: Set<String>.from(flavors ?? <String>[]),
|
||||
platforms: Set<String>.from(platforms ?? <String>[]),
|
||||
transformers: transformers ?? <AssetTransformerEntry>[],
|
||||
),
|
||||
null,
|
||||
@ -894,6 +903,41 @@ class AssetsEntry {
|
||||
return _parseList<String>(yaml, _flavorKey, 'String');
|
||||
}
|
||||
|
||||
/// Parses and validates the "platforms" section of an asset entry in pubspec.yaml.
|
||||
///
|
||||
/// Returns a tuple containing the parsed platforms list and any validation errors.
|
||||
/// If errors are encountered, the platforms list will be null and errors will be non-empty.
|
||||
static (List<String>? platforms, List<String> errors) _parsePlatformsSection(Object? yaml) {
|
||||
if (yaml == null) {
|
||||
return (null, <String>[]);
|
||||
}
|
||||
|
||||
final (List<String>? platforms, List<String> errors) = _parseList<String>(
|
||||
yaml,
|
||||
_platformsKey,
|
||||
'String',
|
||||
);
|
||||
|
||||
if (errors.isNotEmpty) {
|
||||
return (null, errors);
|
||||
}
|
||||
|
||||
if (platforms != null) {
|
||||
final Set<String> invalidPlatforms = platforms.toSet().difference(_kValidPluginPlatforms);
|
||||
|
||||
if (invalidPlatforms.isNotEmpty) {
|
||||
return (
|
||||
null,
|
||||
<String>[
|
||||
'Invalid platform(s): "${invalidPlatforms.join(", ")}". Supported platforms are: "${_kValidPluginPlatforms.join(", ")}".',
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (platforms, errors);
|
||||
}
|
||||
|
||||
static (List<AssetTransformerEntry>?, List<String> errors) _parseTransformersSection(
|
||||
Object? yaml,
|
||||
) {
|
||||
@ -934,18 +978,22 @@ class AssetsEntry {
|
||||
return false;
|
||||
}
|
||||
|
||||
return uri == other.uri && setEquals(flavors, other.flavors);
|
||||
return uri == other.uri &&
|
||||
setEquals(flavors, other.flavors) &&
|
||||
setEquals(platforms, other.platforms);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hashAll(<Object?>[
|
||||
uri.hashCode,
|
||||
Object.hashAllUnordered(flavors),
|
||||
Object.hashAllUnordered(platforms),
|
||||
Object.hashAll(transformers),
|
||||
]);
|
||||
|
||||
@override
|
||||
String toString() => 'AssetsEntry(uri: $uri, flavors: $flavors, transformers: $transformers)';
|
||||
String toString() =>
|
||||
'AssetsEntry(uri: $uri, flavors: $flavors, platforms: $platforms, transformers: $transformers)';
|
||||
}
|
||||
|
||||
/// Represents an entry in the "transformers" section of an asset.
|
||||
|
||||
@ -499,6 +499,7 @@ class HotRunner extends ResidentRunner {
|
||||
),
|
||||
packageConfigPath: debuggingOptions.buildInfo.packageConfigPath,
|
||||
flavor: debuggingOptions.buildInfo.flavor,
|
||||
targetPlatform: targetPlatform,
|
||||
);
|
||||
if (result != 0) {
|
||||
return UpdateFSReport();
|
||||
|
||||
@ -76,6 +76,7 @@ class PreviewPubspecBuilder {
|
||||
return AssetsEntry(
|
||||
uri: transformAssetUri(asset.uri),
|
||||
flavors: asset.flavors,
|
||||
platforms: asset.platforms,
|
||||
transformers: asset.transformers,
|
||||
);
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ 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/build_info.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
|
||||
@ -37,6 +38,7 @@ void main() {
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory),
|
||||
flavor: flavor,
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ 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/build_info.dart';
|
||||
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
|
||||
@ -62,7 +63,10 @@ $fontsSection
|
||||
String expectedAssetManifest,
|
||||
) async {
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
await bundle.build(packageConfigPath: '.dart_tool/package_config.json');
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
for (final packageName in packages) {
|
||||
for (final packageFont in packageFonts) {
|
||||
@ -114,7 +118,10 @@ $fontsSection
|
||||
writePubspecFile('p/p/pubspec.yaml', 'test_package');
|
||||
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
await bundle.build(packageConfigPath: '.dart_tool/package_config.json');
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
expect(
|
||||
bundle.entries.keys,
|
||||
unorderedEquals(<String>['AssetManifest.bin', 'FontManifest.json', 'NOTICES.Z']),
|
||||
|
||||
@ -10,6 +10,7 @@ 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/build_info.dart';
|
||||
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:standard_message_codec/standard_message_codec.dart';
|
||||
@ -83,7 +84,11 @@ $assetsSection
|
||||
String? flavor,
|
||||
}) async {
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
await bundle.build(packageConfigPath: '.dart_tool/package_config.json', flavor: flavor);
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
flavor: flavor,
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
for (final packageName in packages) {
|
||||
for (final asset in assets) {
|
||||
@ -138,7 +143,10 @@ $assetsSection
|
||||
writePubspecFile('p/p/pubspec.yaml', 'test_package');
|
||||
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
await bundle.build(packageConfigPath: '.dart_tool/package_config.json');
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
expect(
|
||||
bundle.entries.keys,
|
||||
unorderedEquals(<String>['NOTICES.Z', 'AssetManifest.bin', 'FontManifest.json']),
|
||||
@ -166,7 +174,10 @@ $assetsSection
|
||||
writeAssets('p/p/', assets);
|
||||
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
await bundle.build(packageConfigPath: '.dart_tool/package_config.json');
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
expect(
|
||||
bundle.entries.keys,
|
||||
unorderedEquals(<String>['NOTICES.Z', 'AssetManifest.bin', 'FontManifest.json']),
|
||||
@ -665,7 +676,10 @@ $assetsSection
|
||||
writeAssets('p/p/', assetsOnDisk);
|
||||
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
await bundle.build(packageConfigPath: '.dart_tool/package_config.json');
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
expect(
|
||||
bundle.entries['AssetManifest.bin'],
|
||||
@ -754,7 +768,10 @@ $assetsSection
|
||||
writePubspecFile('p/p/pubspec.yaml', 'test_package', assets: assetOnManifest);
|
||||
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
await bundle.build(packageConfigPath: '.dart_tool/package_config.json');
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
FileSystem: () => testFileSystem,
|
||||
|
||||
@ -44,7 +44,13 @@ void main() {
|
||||
'nonempty',
|
||||
() async {
|
||||
final AssetBundle ab = AssetBundleFactory.instance.createBundle();
|
||||
expect(await ab.build(packageConfigPath: '.dart_tool/package_config.json'), 0);
|
||||
expect(
|
||||
await ab.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
),
|
||||
0,
|
||||
);
|
||||
expect(ab.entries.length, greaterThan(0));
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
@ -62,7 +68,10 @@ void main() {
|
||||
..writeAsStringSync('');
|
||||
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
await bundle.build(packageConfigPath: '.dart_tool/package_config.json');
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
expect(bundle.entries.keys, unorderedEquals(<String>['AssetManifest.bin']));
|
||||
const expectedBinAssetManifest = <Object, Object>{};
|
||||
expect(
|
||||
@ -109,7 +118,10 @@ flutter:
|
||||
}
|
||||
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
await bundle.build(packageConfigPath: '.dart_tool/package_config.json');
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
expect(
|
||||
bundle.entries.keys,
|
||||
@ -149,7 +161,10 @@ flutter:
|
||||
- assets/foo/
|
||||
''');
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
await bundle.build(packageConfigPath: '.dart_tool/package_config.json');
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
expect(
|
||||
bundle.entries.keys,
|
||||
unorderedEquals(<String>[
|
||||
@ -165,7 +180,10 @@ flutter:
|
||||
..setLastModifiedSync(packageFile.lastModifiedSync().add(const Duration(hours: 1)));
|
||||
|
||||
expect(bundle.needsBuild(), true);
|
||||
await bundle.build(packageConfigPath: '.dart_tool/package_config.json');
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
expect(
|
||||
bundle.entries.keys,
|
||||
unorderedEquals(<String>[
|
||||
@ -203,7 +221,10 @@ flutter:
|
||||
mainLibName: 'my_app',
|
||||
);
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
await bundle.build(packageConfigPath: '.dart_tool/package_config.json');
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
expect(
|
||||
bundle.entries.keys,
|
||||
unorderedEquals(<String>[
|
||||
@ -231,7 +252,10 @@ name: my_app''')
|
||||
// asset manifest and not updated. This is due to the devfs not
|
||||
// supporting file deletion.
|
||||
expect(bundle.needsBuild(), true);
|
||||
await bundle.build(packageConfigPath: '.dart_tool/package_config.json');
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
expect(
|
||||
bundle.entries.keys,
|
||||
unorderedEquals(<String>[
|
||||
@ -269,7 +293,10 @@ flutter:
|
||||
''');
|
||||
writePackageConfigFiles(directory: globals.fs.currentDirectory, mainLibName: 'my_app');
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
await bundle.build(packageConfigPath: '.dart_tool/package_config.json');
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
expect(
|
||||
bundle.entries.keys,
|
||||
unorderedEquals(<String>[
|
||||
@ -323,6 +350,7 @@ flutter:
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
deferredComponentsEnabled: true,
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
expect(
|
||||
bundle.entries.keys,
|
||||
@ -371,7 +399,10 @@ flutter:
|
||||
- assets/wild/
|
||||
''');
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
await bundle.build(packageConfigPath: '.dart_tool/package_config.json');
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
expect(
|
||||
bundle.entries.keys,
|
||||
unorderedEquals(<String>[
|
||||
@ -431,6 +462,7 @@ flutter:
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
deferredComponentsEnabled: true,
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
expect(
|
||||
bundle.entries.keys,
|
||||
@ -454,6 +486,7 @@ flutter:
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
deferredComponentsEnabled: true,
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
expect(
|
||||
@ -507,6 +540,7 @@ flutter:
|
||||
() => bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory),
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
),
|
||||
throwsToolExit(
|
||||
message:
|
||||
@ -546,6 +580,7 @@ flutter:
|
||||
() => bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory),
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
),
|
||||
throwsToolExit(
|
||||
message:
|
||||
@ -590,6 +625,7 @@ flutter:
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory),
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
expect(bundle.entries['my-asset.txt']!.content.isModified, isTrue);
|
||||
@ -597,6 +633,7 @@ flutter:
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory),
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
expect(bundle.entries['my-asset.txt']!.content.isModified, isFalse);
|
||||
@ -614,6 +651,7 @@ flutter:
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory),
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
expect(bundle.entries['my-asset.txt']!.content.isModified, isTrue);
|
||||
@ -762,12 +800,18 @@ assets:
|
||||
- assets/foo/bar.txt
|
||||
''');
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
await bundle.build(packageConfigPath: '.dart_tool/package_config.json');
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
final AssetBundleEntry? fontManifest = bundle.entries['FontManifest.json'];
|
||||
final AssetBundleEntry? license = bundle.entries['NOTICES'];
|
||||
|
||||
await bundle.build(packageConfigPath: '.dart_tool/package_config.json');
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
expect(fontManifest, bundle.entries['FontManifest.json']);
|
||||
expect(license, bundle.entries['NOTICES']);
|
||||
@ -795,7 +839,13 @@ flutter:
|
||||
''');
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
|
||||
expect(await bundle.build(packageConfigPath: '.dart_tool/package_config.json'), 0);
|
||||
expect(
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
),
|
||||
0,
|
||||
);
|
||||
expect(
|
||||
bundle.additionalDependencies.single.path,
|
||||
contains('DOES_NOT_EXIST_RERUN_FOR_WILDCARD'),
|
||||
@ -824,7 +874,13 @@ flutter:
|
||||
''');
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
|
||||
expect(await bundle.build(packageConfigPath: '.dart_tool/package_config.json'), 0);
|
||||
expect(
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
),
|
||||
0,
|
||||
);
|
||||
expect(bundle.additionalDependencies, isEmpty);
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
@ -871,7 +927,13 @@ flutter:
|
||||
''');
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
|
||||
expect(await bundle.build(packageConfigPath: '.dart_tool/package_config.json'), 0);
|
||||
expect(
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
),
|
||||
0,
|
||||
);
|
||||
|
||||
await writeBundle(
|
||||
output,
|
||||
@ -1097,7 +1159,13 @@ flutter:
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
globals.fs.file('foo/bar/fizz.txt').createSync(recursive: true);
|
||||
|
||||
expect(await bundle.build(packageConfigPath: '.dart_tool/package_config.json'), 0);
|
||||
expect(
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
),
|
||||
0,
|
||||
);
|
||||
expect(bundle.additionalDependencies, isEmpty);
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
@ -1135,7 +1203,10 @@ flutter:
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
globals.fs.file('foo/bar/fizz.txt').createSync(recursive: true);
|
||||
|
||||
await bundle.build(packageConfigPath: '.dart_tool/package_config.json');
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
expect(
|
||||
bundle.entries.keys,
|
||||
@ -1188,7 +1259,13 @@ flutter:
|
||||
''');
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
|
||||
expect(await bundle.build(packageConfigPath: '.dart_tool/package_config.json'), 1);
|
||||
expect(
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
),
|
||||
1,
|
||||
);
|
||||
expect(testLogger.errorText, contains('This asset was included from package foo'));
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
@ -1217,7 +1294,13 @@ flutter:
|
||||
''');
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
|
||||
expect(await bundle.build(packageConfigPath: '.dart_tool/package_config.json'), 1);
|
||||
expect(
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
),
|
||||
1,
|
||||
);
|
||||
expect(testLogger.errorText, isNot(contains('This asset was included from')));
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
@ -1256,7 +1339,13 @@ flutter:
|
||||
''');
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
|
||||
expect(await bundle.build(packageConfigPath: '.dart_tool/package_config.json'), 0);
|
||||
expect(
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
),
|
||||
0,
|
||||
);
|
||||
expect((bundle.entries['FontManifest.json']!.content as DevFSStringContent).string, '[]');
|
||||
expect(testLogger.errorText, contains('package:foo has `uses-material-design: true` set'));
|
||||
},
|
||||
@ -1292,7 +1381,13 @@ flutter:
|
||||
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
|
||||
expect(await bundle.build(packageConfigPath: '.dart_tool/package_config.json'), 0);
|
||||
expect(
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
),
|
||||
0,
|
||||
);
|
||||
expect(
|
||||
bundle.entries.keys,
|
||||
unorderedEquals(<String>[
|
||||
@ -1336,7 +1431,13 @@ flutter:
|
||||
globals.fs.file('assets/zebra.jpg').createSync();
|
||||
final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
|
||||
|
||||
expect(await bundle.build(packageConfigPath: '.dart_tool/package_config.json'), 0);
|
||||
expect(
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
),
|
||||
0,
|
||||
);
|
||||
expect((bundle.entries['FontManifest.json']!.content as DevFSStringContent).string, '[]');
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
@ -1375,6 +1476,7 @@ flutter:
|
||||
() => bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory),
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
),
|
||||
throwsToolExit(
|
||||
message:
|
||||
|
||||
@ -12,6 +12,7 @@ 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/build_info.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
@ -86,6 +87,7 @@ ${assets.map((String entry) => ' - $entry').join('\n')}
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
flutterProject: FlutterProject.fromDirectoryTest(fs.currentDirectory),
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
final Map<Object?, Object?> smcBinManifest = await extractAssetManifestSmcBinFromBundle(
|
||||
@ -133,6 +135,7 @@ ${assets.map((String entry) => ' - $entry').join('\n')}
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
flutterProject: FlutterProject.fromDirectoryTest(fs.currentDirectory),
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
final Map<Object?, Object?> smcBinManifest = await extractAssetManifestSmcBinFromBundle(
|
||||
@ -176,6 +179,7 @@ ${assets.map((String entry) => ' - $entry').join('\n')}
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
flutterProject: FlutterProject.fromDirectoryTest(fs.currentDirectory),
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
final Map<Object?, Object?> smcBinManifest = await extractAssetManifestSmcBinFromBundle(
|
||||
@ -215,6 +219,7 @@ ${assets.map((String entry) => ' - $entry').join('\n')}
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
flutterProject: FlutterProject.fromDirectoryTest(fs.currentDirectory),
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
final expectedManifest = <String, List<Map<String, Object>>>{
|
||||
@ -282,6 +287,7 @@ flutter:
|
||||
await bundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
flutterProject: FlutterProject.fromDirectoryTest(fs.currentDirectory),
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
final expectedAssetManifest = <String, List<Map<String, Object>>>{
|
||||
|
||||
@ -96,6 +96,7 @@ dependencies:
|
||||
packageConfigPath: packageConfigPath,
|
||||
manifestPath: manifestPath,
|
||||
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.directory('main')),
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
expect(assetBundle.entries, contains('FontManifest.json'));
|
||||
@ -254,6 +255,7 @@ flutter:
|
||||
packageConfigPath: packageConfigPath,
|
||||
manifestPath: manifestPath,
|
||||
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.directory('main')),
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
expect(assetBundle.entries, contains('FontManifest.json'));
|
||||
@ -298,6 +300,7 @@ flutter:
|
||||
manifestPath: manifestPath, // file doesn't exist
|
||||
packageConfigPath: packageConfigPath,
|
||||
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.file(manifestPath).parent),
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
|
||||
expect(assetBundle.wasBuiltOnce(), true);
|
||||
@ -397,6 +400,7 @@ flutter:
|
||||
final int result = await assetBundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory),
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
expect(result, isNot(0));
|
||||
expect(
|
||||
@ -426,6 +430,7 @@ flutter:
|
||||
final int result = await assetBundle.build(
|
||||
packageConfigPath: '.dart_tool/package_config.json',
|
||||
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory),
|
||||
targetPlatform: TargetPlatform.tester,
|
||||
);
|
||||
expect(result, isNot(0));
|
||||
expect(
|
||||
|
||||
@ -461,6 +461,161 @@ flutter:
|
||||
},
|
||||
);
|
||||
|
||||
group('platform-specific assets', () {
|
||||
/// All supported platforms that should be validated.
|
||||
const kValidPluginPlatforms = <String>{'android', 'ios', 'web', 'windows', 'linux', 'macos'};
|
||||
|
||||
TargetPlatform targetFor(String platform) =>
|
||||
TargetPlatform.values.firstWhere((p) => p.osName == platform);
|
||||
|
||||
/// Writes a `pubspec.yaml` with an asset, optionally restricted to
|
||||
/// certain [platforms], then runs the build for [targetPlatform] and
|
||||
/// returns whether the asset was bundled.
|
||||
///
|
||||
/// This helper reflects how Flutter decides which assets to include
|
||||
/// depending on the `platforms:` key in `pubspec.yaml`.
|
||||
Future<bool> setupAndBuildPlatformAsset(String platform, TargetPlatform targetPlatform) async {
|
||||
final filePath = 'assets/test-$platform.txt';
|
||||
|
||||
final pubspec = platform.isEmpty
|
||||
? '''
|
||||
name: example
|
||||
flutter:
|
||||
assets:
|
||||
- path: $filePath
|
||||
'''
|
||||
: '''
|
||||
name: example
|
||||
flutter:
|
||||
assets:
|
||||
- path: $filePath
|
||||
platforms:
|
||||
- $platform
|
||||
''';
|
||||
|
||||
fileSystem.file('pubspec.yaml')
|
||||
..createSync()
|
||||
..writeAsStringSync(pubspec);
|
||||
writePackageConfigFiles(directory: globals.fs.currentDirectory, mainLibName: 'example');
|
||||
fileSystem.file(filePath).createSync(recursive: true);
|
||||
|
||||
await const CopyAssets().build(environment, targetPlatform: targetPlatform);
|
||||
|
||||
final File file = fileSystem.file('${environment.buildDir.path}/flutter_assets/$filePath');
|
||||
return file.existsSync();
|
||||
}
|
||||
|
||||
group('includes assets only for matching platform', () {
|
||||
for (final platform in kValidPluginPlatforms) {
|
||||
testUsingContext(
|
||||
platform,
|
||||
() async {
|
||||
final TargetPlatform targetPlatform = targetFor(platform);
|
||||
final bool didInclude = await setupAndBuildPlatformAsset(platform, targetPlatform);
|
||||
|
||||
expect(didInclude, isTrue, reason: 'Expected asset for $platform to be included');
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
group('skips assets for non-matching platform', () {
|
||||
for (final platform in kValidPluginPlatforms) {
|
||||
testUsingContext(
|
||||
platform,
|
||||
() async {
|
||||
final TargetPlatform targetPlatform = platform == 'android'
|
||||
? TargetPlatform.ios
|
||||
: TargetPlatform.android;
|
||||
final bool didInclude = await setupAndBuildPlatformAsset(platform, targetPlatform);
|
||||
|
||||
expect(
|
||||
didInclude,
|
||||
isFalse,
|
||||
reason: 'Expected asset for $platform to be skipped when target is $targetPlatform',
|
||||
);
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
group('includes assets for all platforms when no restriction is set', () {
|
||||
for (final platform in kValidPluginPlatforms) {
|
||||
testUsingContext(
|
||||
platform,
|
||||
() async {
|
||||
final TargetPlatform targetPlatform = targetFor(platform);
|
||||
final bool didInclude = await setupAndBuildPlatformAsset('', targetPlatform);
|
||||
|
||||
expect(
|
||||
didInclude,
|
||||
isTrue,
|
||||
reason:
|
||||
'Expected asset to be included for all platforms when no platforms are specified (platform: $platform)',
|
||||
);
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
group('includes assets only for declared multiple platforms', () {
|
||||
for (final platform in kValidPluginPlatforms) {
|
||||
testUsingContext(
|
||||
platform,
|
||||
() async {
|
||||
const filePath = 'assets/test-multi.txt';
|
||||
final targetPlatforms = <String>['android', 'ios'];
|
||||
|
||||
fileSystem.file('pubspec.yaml')
|
||||
..createSync()
|
||||
..writeAsStringSync('''
|
||||
name: example
|
||||
flutter:
|
||||
assets:
|
||||
- path: $filePath
|
||||
platforms: [${targetPlatforms.join(',')}]
|
||||
''');
|
||||
|
||||
writePackageConfigFiles(directory: globals.fs.currentDirectory, mainLibName: 'example');
|
||||
fileSystem.file(filePath).createSync(recursive: true);
|
||||
|
||||
final TargetPlatform targetPlatform = targetFor(platform);
|
||||
|
||||
await const CopyAssets().build(environment, targetPlatform: targetPlatform);
|
||||
|
||||
final File bundledFile = fileSystem.file(
|
||||
'${environment.buildDir.path}/flutter_assets/$filePath',
|
||||
);
|
||||
|
||||
final bool exists = bundledFile.existsSync();
|
||||
|
||||
if (targetPlatforms.contains(platform)) {
|
||||
expect(exists, isTrue, reason: 'Expected asset to be included for $platform');
|
||||
} else {
|
||||
expect(exists, isFalse, reason: 'Expected asset to be skipped for $platform');
|
||||
}
|
||||
},
|
||||
overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
testUsingContext(
|
||||
'Uses processors~/2 to transform assets',
|
||||
() async {
|
||||
|
||||
@ -1516,6 +1516,74 @@ flutter:
|
||||
expect(logger.errorText, 'Expected "default-flavor" to be a string, but got 3 (int).\n');
|
||||
});
|
||||
|
||||
testWithoutContext('FlutterManifest parses asset with platforms', () async {
|
||||
const manifest = '''
|
||||
name: test
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter:
|
||||
assets:
|
||||
- path: assets/test.png
|
||||
platforms:
|
||||
- web
|
||||
- android
|
||||
''';
|
||||
|
||||
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
|
||||
manifest,
|
||||
logger: logger,
|
||||
)!;
|
||||
|
||||
expect(flutterManifest.assets, hasLength(1));
|
||||
final AssetsEntry entry = flutterManifest.assets.single;
|
||||
expect(entry.uri.path, 'assets/test.png');
|
||||
expect(entry.platforms, containsAll(<String>['web', 'android']));
|
||||
});
|
||||
|
||||
testWithoutContext(
|
||||
'FlutterManifest fails when platforms contains invalid platform name',
|
||||
() async {
|
||||
const manifest = '''
|
||||
name: test
|
||||
flutter:
|
||||
assets:
|
||||
- path: assets/test.png
|
||||
platforms:
|
||||
- toasterOS
|
||||
- windows
|
||||
''';
|
||||
|
||||
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
|
||||
manifest,
|
||||
logger: logger,
|
||||
);
|
||||
|
||||
expect(flutterManifest, isNull);
|
||||
expect(logger.errorText, contains('Invalid platform'));
|
||||
},
|
||||
);
|
||||
|
||||
testWithoutContext('FlutterManifest supports empty platforms list', () async {
|
||||
const manifest = '''
|
||||
name: test
|
||||
flutter:
|
||||
assets:
|
||||
- path: assets/test.png
|
||||
platforms: []
|
||||
''';
|
||||
|
||||
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
|
||||
manifest,
|
||||
logger: logger,
|
||||
)!;
|
||||
|
||||
expect(flutterManifest.assets, hasLength(1));
|
||||
final AssetsEntry entry = flutterManifest.assets.single;
|
||||
expect(entry.uri.path, 'assets/test.png');
|
||||
expect(entry.platforms, isEmpty);
|
||||
});
|
||||
|
||||
testWithoutContext('FlutterManifest.copyWith generates a valid manifest', () async {
|
||||
const manifest = '''
|
||||
name: test
|
||||
@ -1536,6 +1604,7 @@ flutter:
|
||||
AssetsEntry(
|
||||
uri: Uri(path: 'foo'),
|
||||
flavors: const <String>{'flavor'},
|
||||
platforms: const <String>{'web', 'android', 'ios'},
|
||||
transformers: const <AssetTransformerEntry>[
|
||||
AssetTransformerEntry(package: 'package:foo', args: <String>['arg']),
|
||||
],
|
||||
@ -1555,6 +1624,7 @@ flutter:
|
||||
AssetsEntry(
|
||||
uri: Uri(path: 'deferredComponentUri'),
|
||||
flavors: const <String>{'deferredComponentFlavor'},
|
||||
platforms: const <String>{'macos'},
|
||||
transformers: const <AssetTransformerEntry>[
|
||||
AssetTransformerEntry(
|
||||
package: 'package:deferredComponent',
|
||||
@ -1578,6 +1648,10 @@ flutter:
|
||||
- path: foo
|
||||
flavors:
|
||||
- flavor
|
||||
platforms:
|
||||
- web
|
||||
- android
|
||||
- ios
|
||||
transformers:
|
||||
- package: package:foo
|
||||
args:
|
||||
@ -1598,6 +1672,8 @@ flutter:
|
||||
- path: deferredComponentUri
|
||||
flavors:
|
||||
- deferredComponentFlavor
|
||||
platforms:
|
||||
- macos
|
||||
transformers:
|
||||
- package: package:deferredComponent
|
||||
args:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user