Update icon tree shaker to allow system font fallback (#147202)

Fixes https://github.com/flutter/flutter/issues/147189

This allows const `IconData` to fallback to the system font if `fontFamily` is not provided.

A similar non-fatal error occurs when IconData specifies a font that is not included in the manifest, so I modeled after that error message:

b4121a1867/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart (L122)
This commit is contained in:
Kate Lovett 2024-04-23 11:40:29 -05:00 committed by GitHub
parent a83e111a87
commit e10e9a90af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 113 additions and 3 deletions

View file

@ -327,15 +327,25 @@ class IconTreeShaker {
final Object? package = iconDataMap['fontPackage'];
final Object? fontFamily = iconDataMap['fontFamily'];
final Object? codePoint = iconDataMap['codePoint'];
if ((package ?? '') is! String || // Null is ok here.
fontFamily is! String ||
if ((package ?? '') is! String ||
(fontFamily ?? '') is! String ||
codePoint is! num) {
throw IconTreeShakerException._(
'Invalid ConstFinder result. Expected "fontPackage" to be a String, '
'"fontFamily" to be a String, and "codePoint" to be an int, '
'got: $iconDataMap.');
}
final String family = fontFamily;
if (fontFamily == null) {
_logger.printTrace(
'Expected to find fontFamily for constant IconData with codepoint: '
'$codePoint, but found fontFamily: $fontFamily. This usually means '
'you are relying on the system font. Alternatively, font families in '
'an IconData class can be provided in the assets section of your '
'pubspec.yaml, or you are missing "uses-material-design: true".',
);
continue;
}
final String family = fontFamily as String;
final String key = package == null
? family
: 'packages/$package/$family';

View file

@ -561,6 +561,90 @@ void main() {
expect(processManager, hasNoRemainingExpectations);
});
testWithoutContext('Allow system font fallback when fontFamily is null', () async {
final Environment environment = createEnvironment(<String, String>{
kIconTreeShakerFlag: 'true',
kBuildMode: 'release',
});
final File appDill = environment.buildDir.childFile('app.dill')
..createSync(recursive: true);
// Valid manifest, just not using it.
fontManifestContent = DevFSStringContent(validFontManifestJson);
final IconTreeShaker iconTreeShaker = IconTreeShaker(
environment,
fontManifestContent,
logger: logger,
processManager: processManager,
fileSystem: fileSystem,
artifacts: artifacts,
targetPlatform: TargetPlatform.android,
);
addConstFinderInvocation(appDill.path, stdout: emptyConstFinderResult);
// Does not throw
await iconTreeShaker.subsetFont(
input: fileSystem.file(inputPath),
outputPath: outputPath,
relativePath: relativePath,
);
expect(
logger.traceText,
contains(
'Expected to find fontFamily for constant IconData with codepoint: '
'59470, but found fontFamily: null. This usually means '
'you are relying on the system font. Alternatively, font families in '
'an IconData class can be provided in the assets section of your '
'pubspec.yaml, or you are missing "uses-material-design: true".\n'
),
);
expect(processManager, hasNoRemainingExpectations);
});
testWithoutContext('Allow system font fallback when fontFamily is null and manifest is empty', () async {
final Environment environment = createEnvironment(<String, String>{
kIconTreeShakerFlag: 'true',
kBuildMode: 'release',
});
final File appDill = environment.buildDir.childFile('app.dill')
..createSync(recursive: true);
// Nothing in font manifest
fontManifestContent = DevFSStringContent(emptyFontManifestJson);
final IconTreeShaker iconTreeShaker = IconTreeShaker(
environment,
fontManifestContent,
logger: logger,
processManager: processManager,
fileSystem: fileSystem,
artifacts: artifacts,
targetPlatform: TargetPlatform.android,
);
addConstFinderInvocation(appDill.path, stdout: emptyConstFinderResult);
// Does not throw
await iconTreeShaker.subsetFont(
input: fileSystem.file(inputPath),
outputPath: outputPath,
relativePath: relativePath,
);
expect(
logger.traceText,
contains(
'Expected to find fontFamily for constant IconData with codepoint: '
'59470, but found fontFamily: null. This usually means '
'you are relying on the system font. Alternatively, font families in '
'an IconData class can be provided in the assets section of your '
'pubspec.yaml, or you are missing "uses-material-design: true".\n'
),
);
expect(processManager, hasNoRemainingExpectations);
});
testWithoutContext('ConstFinder non-zero exit', () async {
final Environment environment = createEnvironment(<String, String>{
kIconTreeShakerFlag: 'true',
@ -609,6 +693,20 @@ const String validConstFinderResult = '''
}
''';
const String emptyConstFinderResult = '''
{
"constantInstances": [
{
"codePoint": 59470,
"fontFamily": null,
"fontPackage": null,
"matchTextDirection": false
}
],
"nonConstantLocations": []
}
''';
const String constFinderResultWithInvalid = '''
{
"constantInstances": [
@ -668,3 +766,5 @@ const String invalidFontManifestJson = '''
]
}
''';
const String emptyFontManifestJson = '[]';