Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding anydpi-v21 folder #318

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 29 additions & 77 deletions lib/android.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ final List<AndroidIconTemplate> adaptiveForegroundIcons = <AndroidIconTemplate>[
AndroidIconTemplate(directoryName: 'drawable-xhdpi', size: 216),
AndroidIconTemplate(directoryName: 'drawable-xxhdpi', size: 324),
AndroidIconTemplate(directoryName: 'drawable-xxxhdpi', size: 432),
AndroidIconTemplate(directoryName: 'drawable-anydpi-v21', size: 432),
];

List<AndroidIconTemplate> androidIcons = <AndroidIconTemplate>[
Expand All @@ -28,8 +29,7 @@ List<AndroidIconTemplate> androidIcons = <AndroidIconTemplate>[
AndroidIconTemplate(directoryName: 'mipmap-xxxhdpi', size: 192),
];

void createDefaultIcons(
Map<String, dynamic> flutterLauncherIconsConfig, String? flavor) {
void createDefaultIcons(Map<String, dynamic> flutterLauncherIconsConfig, String? flavor) {
printStatus('Creating default icons Android');
final String filePath = getAndroidIconPath(flutterLauncherIconsConfig);
final Image? image = decodeImageFile(filePath);
Expand All @@ -47,51 +47,42 @@ void createDefaultIcons(
}
overwriteAndroidManifestWithNewLauncherIcon(iconName, androidManifestFile);
} else {
printStatus(
'Overwriting the default Android launcher icon with a new icon');
printStatus('Overwriting the default Android launcher icon with a new icon');
for (AndroidIconTemplate template in androidIcons) {
overwriteExistingIcons(
template, image, constants.androidFileName, flavor);
overwriteExistingIcons(template, image, constants.androidFileName, flavor);
}
overwriteAndroidManifestWithNewLauncherIcon(
constants.androidDefaultIconName, androidManifestFile);
overwriteAndroidManifestWithNewLauncherIcon(constants.androidDefaultIconName, androidManifestFile);
}
}

/// Ensures that the Android icon name is in the correct format
bool isAndroidIconNameCorrectFormat(String iconName) {
// assure the icon only consists of lowercase letters, numbers and underscore
if (!RegExp(r'^[a-z0-9_]+$').hasMatch(iconName)) {
throw const InvalidAndroidIconNameException(
constants.errorIncorrectIconName);
throw const InvalidAndroidIconNameException(constants.errorIncorrectIconName);
}
return true;
}

void createAdaptiveIcons(
Map<String, dynamic> flutterLauncherIconsConfig, String? flavor) {
void createAdaptiveIcons(Map<String, dynamic> flutterLauncherIconsConfig, String? flavor) {
printStatus('Creating adaptive icons Android');

// Retrieve the necessary Flutter Launcher Icons configuration from the pubspec.yaml file
final String backgroundConfig =
flutterLauncherIconsConfig['adaptive_icon_background'];
final String foregroundImagePath =
flutterLauncherIconsConfig['adaptive_icon_foreground'];
final String backgroundConfig = flutterLauncherIconsConfig['adaptive_icon_background'];
final String foregroundImagePath = flutterLauncherIconsConfig['adaptive_icon_foreground'];
final Image? foregroundImage = decodeImageFile(foregroundImagePath);
if (foregroundImage == null) {
return;
}

// Create adaptive icon foreground images
for (AndroidIconTemplate androidIcon in adaptiveForegroundIcons) {
overwriteExistingIcons(androidIcon, foregroundImage,
constants.androidAdaptiveForegroundFileName, flavor);
overwriteExistingIcons(androidIcon, foregroundImage, constants.androidAdaptiveForegroundFileName, flavor);
}

// Create adaptive icon background
if (isAdaptiveIconConfigPngFile(backgroundConfig)) {
createAdaptiveBackgrounds(
flutterLauncherIconsConfig, backgroundConfig, flavor);
createAdaptiveBackgrounds(flutterLauncherIconsConfig, backgroundConfig, flavor);
} else {
createAdaptiveIconMipmapXmlFile(flutterLauncherIconsConfig, flavor);
updateColorsXmlFile(backgroundConfig, flavor);
Expand All @@ -112,38 +103,27 @@ void updateColorsXmlFile(String backgroundConfig, String? flavor) {
updateColorsFile(colorsXml, backgroundConfig);
} else {
printStatus('No colors.xml file found in your Android project');
printStatus(
'Creating colors.xml file and adding it to your Android project');
printStatus('Creating colors.xml file and adding it to your Android project');
createNewColorsFile(backgroundConfig, flavor);
}
}

/// Creates the xml file required for the adaptive launcher icon
/// FILE LOCATED HERE: res/mipmap-anydpi/{icon-name-from-yaml-config}.xml
void createAdaptiveIconMipmapXmlFile(
Map<String, dynamic> flutterLauncherIconsConfig, String? flavor) {
void createAdaptiveIconMipmapXmlFile(Map<String, dynamic> flutterLauncherIconsConfig, String? flavor) {
if (isCustomAndroidFile(flutterLauncherIconsConfig)) {
File(constants.androidAdaptiveXmlFolder(flavor) +
getNewIconName(flutterLauncherIconsConfig) +
'.xml')
.create(recursive: true)
.then((File adaptiveIcon) {
File(constants.androidAdaptiveXmlFolder(flavor) + getNewIconName(flutterLauncherIconsConfig) + '.xml').create(recursive: true).then((File adaptiveIcon) {
adaptiveIcon.writeAsString(xml_template.icLauncherXml);
});
} else {
File(constants.androidAdaptiveXmlFolder(flavor) +
constants.androidDefaultIconName +
'.xml')
.create(recursive: true)
.then((File adaptiveIcon) {
File(constants.androidAdaptiveXmlFolder(flavor) + constants.androidDefaultIconName + '.xml').create(recursive: true).then((File adaptiveIcon) {
adaptiveIcon.writeAsString(xml_template.icLauncherXml);
});
}
}

/// creates adaptive background using png image
void createAdaptiveBackgrounds(Map<String, dynamic> yamlConfig,
String adaptiveIconBackgroundImagePath, String? flavor) {
void createAdaptiveBackgrounds(Map<String, dynamic> yamlConfig, String adaptiveIconBackgroundImagePath, String? flavor) {
final String filePath = adaptiveIconBackgroundImagePath;
final Image? image = decodeImageFile(filePath);
if (image == null) {
Expand All @@ -153,36 +133,25 @@ void createAdaptiveBackgrounds(Map<String, dynamic> yamlConfig,
// creates a png image (ic_adaptive_background.png) for the adaptive icon background in each of the locations
// it is required
for (AndroidIconTemplate androidIcon in adaptiveForegroundIcons) {
saveNewImages(androidIcon, image,
constants.androidAdaptiveBackgroundFileName, flavor);
saveNewImages(androidIcon, image, constants.androidAdaptiveBackgroundFileName, flavor);
}

// Creates the xml file required for the adaptive launcher icon
// FILE LOCATED HERE: res/mipmap-anydpi/{icon-name-from-yaml-config}.xml
if (isCustomAndroidFile(yamlConfig)) {
File(constants.androidAdaptiveXmlFolder(flavor) +
getNewIconName(yamlConfig) +
'.xml')
.create(recursive: true)
.then((File adaptiveIcon) {
File(constants.androidAdaptiveXmlFolder(flavor) + getNewIconName(yamlConfig) + '.xml').create(recursive: true).then((File adaptiveIcon) {
adaptiveIcon.writeAsString(xml_template.icLauncherDrawableBackgroundXml);
});
} else {
File(constants.androidAdaptiveXmlFolder(flavor) +
constants.androidDefaultIconName +
'.xml')
.create(recursive: true)
.then((File adaptiveIcon) {
File(constants.androidAdaptiveXmlFolder(flavor) + constants.androidDefaultIconName + '.xml').create(recursive: true).then((File adaptiveIcon) {
adaptiveIcon.writeAsString(xml_template.icLauncherDrawableBackgroundXml);
});
}
}

/// Creates a colors.xml file if it was missing from android/app/src/main/res/values/colors.xml
void createNewColorsFile(String backgroundColor, String? flavor) {
File(constants.androidColorsFile(flavor))
.create(recursive: true)
.then((File colorsFile) {
File(constants.androidColorsFile(flavor)).create(recursive: true).then((File colorsFile) {
colorsFile.writeAsString(xml_template.colorsXml).then((File file) {
updateColorsFile(colorsFile, backgroundColor);
});
Expand All @@ -207,8 +176,7 @@ void updateColorsFile(File colorsFile, String backgroundColor) {

// Add new line if we didn't find an existing value
if (!foundExisting) {
lines.insert(lines.length - 1,
'\t<color name="ic_launcher_background">$backgroundColor</color>');
lines.insert(lines.length - 1, '\t<color name="ic_launcher_background">$backgroundColor</color>');
}

colorsFile.writeAsStringSync(lines.join('\n'));
Expand Down Expand Up @@ -238,28 +206,17 @@ void overwriteExistingIcons(
String? flavor,
) {
final Image newFile = createResizedImage(template.size, image);
File(constants.androidResFolder(flavor) +
template.directoryName +
'/' +
filename)
.create(recursive: true)
.then((File file) {
File(constants.androidResFolder(flavor) + template.directoryName + '/' + filename).create(recursive: true).then((File file) {
file.writeAsBytesSync(encodePng(newFile));
});
}

/// Saves new launcher icons to the project, keeping the old launcher icons.
/// Note: Do not change interpolation unless you end up with better results
/// https://github.com/fluttercommunity/flutter_launcher_icons/issues/101#issuecomment-495528733
void saveNewImages(AndroidIconTemplate template, Image image,
String iconFilePath, String? flavor) {
void saveNewImages(AndroidIconTemplate template, Image image, String iconFilePath, String? flavor) {
final Image newFile = createResizedImage(template.size, image);
File(constants.androidResFolder(flavor) +
template.directoryName +
'/' +
iconFilePath)
.create(recursive: true)
.then((File file) {
File(constants.androidResFolder(flavor) + template.directoryName + '/' + iconFilePath).create(recursive: true).then((File file) {
file.writeAsBytesSync(encodePng(newFile));
});
}
Expand All @@ -268,19 +225,15 @@ void saveNewImages(AndroidIconTemplate template, Image image,
/// with the new icon name (only if it has changed)
///
/// Note: default iconName = "ic_launcher"
Future<void> overwriteAndroidManifestWithNewLauncherIcon(
String iconName, File androidManifestFile) async {
Future<void> overwriteAndroidManifestWithNewLauncherIcon(String iconName, File androidManifestFile) async {
// we do not use `file.readAsLinesSync()` here because that always gets rid of the last empty newline
final List<String> oldManifestLines =
(await androidManifestFile.readAsString()).split('\n');
final List<String> transformedLines =
transformAndroidManifestWithNewLauncherIcon(oldManifestLines, iconName);
final List<String> oldManifestLines = (await androidManifestFile.readAsString()).split('\n');
final List<String> transformedLines = transformAndroidManifestWithNewLauncherIcon(oldManifestLines, iconName);
await androidManifestFile.writeAsString(transformedLines.join('\n'));
}

/// Updates only the line containing android:icon with the specified iconName
List<String> transformAndroidManifestWithNewLauncherIcon(
List<String> oldManifestLines, String iconName) {
List<String> transformAndroidManifestWithNewLauncherIcon(List<String> oldManifestLines, String iconName) {
return oldManifestLines.map((String line) {
if (line.contains('android:icon')) {
// Using RegExp replace the value of android:icon to point to the new icon
Expand All @@ -290,8 +243,7 @@ List<String> transformAndroidManifestWithNewLauncherIcon(
// repeat as often as wanted with no quote at start: [^"]*(\"[^"]*)*
// escaping the slash to place in string: [^"]*(\\"[^"]*)*"
// result: any string which does only include escaped quotes
return line.replaceAll(RegExp(r'android:icon="[^"]*(\\"[^"]*)*"'),
'android:icon="@mipmap/$iconName"');
return line.replaceAll(RegExp(r'android:icon="[^"]*(\\"[^"]*)*"'), 'android:icon="@mipmap/$iconName"');
} else {
return line;
}
Expand Down