From 208a070be319c3f9af44f89d762df9070663ede9 Mon Sep 17 00:00:00 2001 From: Ratakondala Arun Date: Sun, 31 Jul 2022 13:35:24 +0530 Subject: [PATCH 1/8] fix(android): minSdk not found closes #384 --- lib/android.dart | 70 ++++++++++++++++++++++++++++++++++++++-------- lib/constants.dart | 6 +++- lib/main.dart | 3 +- 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/lib/android.dart b/lib/android.dart index 4283213b21..9a57e94264 100644 --- a/lib/android.dart +++ b/lib/android.dart @@ -4,6 +4,7 @@ import 'package:flutter_launcher_icons/xml_templates.dart' as xml_template; import 'package:image/image.dart'; import 'package:flutter_launcher_icons/custom_exceptions.dart'; import 'package:flutter_launcher_icons/constants.dart' as constants; +import 'package:path/path.dart' as path; class AndroidIconTemplate { AndroidIconTemplate({required this.size, required this.directoryName}); @@ -298,22 +299,24 @@ List transformAndroidManifestWithNewLauncherIcon( }).toList(); } -/// Retrieves the minSdk value from the Android build.gradle file or local.properties file -int minSdk() { +/// Retrieves the minSdk value from the +/// - flutter.gradle: `'$FLUTTER_ROOT/packages/flutter_tools/gradle/flutter.gradle'` +/// - build.gradle: `'android/app/build.gradle'` +/// - local.properties: `'android/local.properties'` +/// +/// If found none returns 0 +int? minSdk() { final androidGradleFile = File(constants.androidGradleFile); final androidLocalPropertiesFile = File(constants.androidLocalPropertiesFile); - // look in build.gradle first - final minSdkValue = getMinSdkFromFile(androidGradleFile); - - // look in local.properties. Didn't find minSdk, assume the worst - return minSdkValue != 0 - ? minSdkValue - : getMinSdkFromFile(androidLocalPropertiesFile); + // looks for minSdk value in build.gradle, flutter.gradle & local.properties. + return getMinSdkFlutterGradle(androidLocalPropertiesFile) ?? + getMinSdkFromFile(androidGradleFile) ?? + getMinSdkFromFile(androidLocalPropertiesFile); } /// Retrieves the minSdk value from [File] -int getMinSdkFromFile(File file) { +int? getMinSdkFromFile(File file) { final List lines = file.readAsLinesSync(); for (String line in lines) { if (line.contains('minSdkVersion')) { @@ -324,10 +327,53 @@ int getMinSdkFromFile(File file) { // remove anything from the line that is not a digit final String minSdk = line.replaceAll(RegExp(r'[^\d]'), ''); // when minSdkVersion value not found - return int.tryParse(minSdk) ?? 0; + return int.tryParse(minSdk); + } + } + return null; // Didn't find minSdk, assume the worst +} + +/// A helper function to [getMinSdkFlutterGradle] +/// which retrives value of `flutter.sdk` from `local.properties` file +String? getFlutterSdkPathFromLocalProperties(File file) { + final List lines = file.readAsLinesSync(); + for (String line in lines) { + if (!line.contains('flutter.sdk=')) { + continue; + } + if (line.contains('#') && line.indexOf('#') < line.indexOf('flutter.sdk=')) { + continue; + } + final flutterSdkPath = line.split('=').last.trim(); + if (flutterSdkPath.isEmpty) { + return null; + } + return flutterSdkPath; + } + return null; +} + +/// Retrives value of `minSdkVersion` from `flutter.gradle` +int? getMinSdkFlutterGradle(File localPropertiesFile) { + final flutterRoot = getFlutterSdkPathFromLocalProperties(localPropertiesFile); + if (flutterRoot == null) { + return null; + } + + final flutterGradleFile = File(path.join(flutterRoot, constants.androidFlutterGardlePath)); + + final List lines = flutterGradleFile.readAsLinesSync(); + for (String line in lines) { + if (!line.contains('static int minSdkVersion =')) { + continue; + } + if (line.contains('//') && line.indexOf('//') < line.indexOf('static int minSdkVersion =')) { + continue; } + final minSdk = line.split('=').last.trim(); + return int.tryParse(minSdk); } - return 0; // Didn't find minSdk, assume the worst + return null; } /// Method for the retrieval of the Android icon path diff --git a/lib/constants.dart b/lib/constants.dart index 0133f802a1..307e4db48d 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -9,6 +9,10 @@ String androidColorsFile(String? flavor) => "android/app/src/${flavor ?? 'main'} const String androidManifestFile = 'android/app/src/main/AndroidManifest.xml'; const String androidGradleFile = 'android/app/build.gradle'; const String androidLocalPropertiesFile = 'android/local.properties'; + +/// Relative path to flutter.gradle from flutter sdk path +const String androidFlutterGardlePath = 'packages/flutter_tools/gradle/flutter.gradle'; + const String androidFileName = 'ic_launcher.png'; const String androidAdaptiveForegroundFileName = 'ic_launcher_foreground.png'; const String androidAdaptiveBackgroundFileName = 'ic_launcher_background.png'; @@ -62,7 +66,7 @@ const String errorMissingPlatform = 'No platform specified within config to gene const String errorMissingRegularAndroid = 'Adaptive icon config found but no regular Android config. ' 'Below API 26 the regular Android config is required'; const String errorMissingMinSdk = 'Cannot not find minSdk from android/app/build.gradle or android/local.properties' - 'Specify minSdk in either android/app/build.gradle or android/local.properties'; + ' Specify minSdk in your flutter_launcher_config.yaml with "min_sdk_android"'; const String errorIncorrectIconName = 'The icon name must contain only lowercase a-z, 0-9, or underscore: ' 'E.g. "ic_my_new_icon"'; diff --git a/lib/main.dart b/lib/main.dart index 4db400061d..64c9a48fe4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -13,7 +13,6 @@ import 'package:flutter_launcher_icons/pubspec_parser.dart'; import 'package:flutter_launcher_icons/web/web_icon_generator.dart'; import 'package:flutter_launcher_icons/windows/windows_icon_generator.dart'; import 'package:path/path.dart' as path; -import 'package:yaml/yaml.dart'; const String fileOption = 'file'; const String helpFlag = 'help'; @@ -126,7 +125,7 @@ Future createIconsFromConfig( } if (isNeedingNewAndroidIcon(config) || hasAndroidAdaptiveConfig(config)) { - final int minSdk = android_launcher_icons.minSdk(); + final int minSdk = config['min_sdk_android'] ?? android_launcher_icons.minSdk() ?? 0; if (minSdk == 0) { throw const InvalidConfigException(errorMissingMinSdk); } From 6222def4c63442a8b77a1bb14988751a881c0351 Mon Sep 17 00:00:00 2001 From: Ratakondala Arun Date: Sun, 31 Jul 2022 13:35:54 +0530 Subject: [PATCH 2/8] style: formatted --- lib/android.dart | 94 +++++++++++++++--------------------------------- 1 file changed, 29 insertions(+), 65 deletions(-) diff --git a/lib/android.dart b/lib/android.dart index 9a57e94264..9c730d5587 100644 --- a/lib/android.dart +++ b/lib/android.dart @@ -29,8 +29,7 @@ List androidIcons = [ AndroidIconTemplate(directoryName: 'mipmap-xxxhdpi', size: 192), ]; -void createDefaultIcons( - Map flutterLauncherIconsConfig, String? flavor) { +void createDefaultIcons(Map flutterLauncherIconsConfig, String? flavor) { printStatus('Creating default icons Android'); final String filePath = getAndroidIconPath(flutterLauncherIconsConfig); final Image? image = decodeImageFile(filePath); @@ -48,14 +47,11 @@ 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); } } @@ -63,21 +59,17 @@ void createDefaultIcons( 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 flutterLauncherIconsConfig, String? flavor) { +void createAdaptiveIcons(Map 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; @@ -85,14 +77,12 @@ void createAdaptiveIcons( // 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); @@ -113,28 +103,22 @@ 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 flutterLauncherIconsConfig, String? flavor) { +void createAdaptiveIconMipmapXmlFile(Map flutterLauncherIconsConfig, String? flavor) { if (isCustomAndroidFile(flutterLauncherIconsConfig)) { - File(constants.androidAdaptiveXmlFolder(flavor) + - getNewIconName(flutterLauncherIconsConfig) + - '.xml') + 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') + File(constants.androidAdaptiveXmlFolder(flavor) + constants.androidDefaultIconName + '.xml') .create(recursive: true) .then((File adaptiveIcon) { adaptiveIcon.writeAsString(xml_template.icLauncherXml); @@ -143,8 +127,8 @@ void createAdaptiveIconMipmapXmlFile( } /// creates adaptive background using png image -void createAdaptiveBackgrounds(Map yamlConfig, - String adaptiveIconBackgroundImagePath, String? flavor) { +void createAdaptiveBackgrounds( + Map yamlConfig, String adaptiveIconBackgroundImagePath, String? flavor) { final String filePath = adaptiveIconBackgroundImagePath; final Image? image = decodeImageFile(filePath); if (image == null) { @@ -154,24 +138,19 @@ void createAdaptiveBackgrounds(Map 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') + 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') + File(constants.androidAdaptiveXmlFolder(flavor) + constants.androidDefaultIconName + '.xml') .create(recursive: true) .then((File adaptiveIcon) { adaptiveIcon.writeAsString(xml_template.icLauncherDrawableBackgroundXml); @@ -181,9 +160,7 @@ void createAdaptiveBackgrounds(Map yamlConfig, /// 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); }); @@ -208,8 +185,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$backgroundColor'); + lines.insert(lines.length - 1, '\t$backgroundColor'); } colorsFile.writeAsStringSync(lines.join('\n')); @@ -239,10 +215,7 @@ void overwriteExistingIcons( String? flavor, ) { final Image newFile = createResizedImage(template.size, image); - File(constants.androidResFolder(flavor) + - template.directoryName + - '/' + - filename) + File(constants.androidResFolder(flavor) + template.directoryName + '/' + filename) .create(recursive: true) .then((File file) { file.writeAsBytesSync(encodePng(newFile)); @@ -252,13 +225,9 @@ void overwriteExistingIcons( /// 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) + File(constants.androidResFolder(flavor) + template.directoryName + '/' + iconFilePath) .create(recursive: true) .then((File file) { file.writeAsBytesSync(encodePng(newFile)); @@ -269,19 +238,15 @@ void saveNewImages(AndroidIconTemplate template, Image image, /// with the new icon name (only if it has changed) /// /// Note: default iconName = "ic_launcher" -Future overwriteAndroidManifestWithNewLauncherIcon( - String iconName, File androidManifestFile) async { +Future 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 oldManifestLines = - (await androidManifestFile.readAsString()).split('\n'); - final List transformedLines = - transformAndroidManifestWithNewLauncherIcon(oldManifestLines, iconName); + final List oldManifestLines = (await androidManifestFile.readAsString()).split('\n'); + final List transformedLines = transformAndroidManifestWithNewLauncherIcon(oldManifestLines, iconName); await androidManifestFile.writeAsString(transformedLines.join('\n')); } /// Updates only the line containing android:icon with the specified iconName -List transformAndroidManifestWithNewLauncherIcon( - List oldManifestLines, String iconName) { +List transformAndroidManifestWithNewLauncherIcon(List 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 @@ -291,8 +256,7 @@ List 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; } From 36793cb5f93b74a33360cc45bf08ac2c17f44fbd Mon Sep 17 00:00:00 2001 From: Ratakondala Arun Date: Sun, 31 Jul 2022 13:54:21 +0530 Subject: [PATCH 3/8] docs(android): added `min_sdk_android` config docs --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 559a958efe..3358798ce9 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,8 @@ Shown below is the full list of attributes which you can specify within your Flu - `image_path_ios`: The location of the icon image file specific for iOS platform (optional - if not defined then the image_path is used) +- `min_sdk_android`: Specify android min sdk value + - `web`: Add web related configs - `generate`: Specifies weather to generate icons for this platform or not - `image_path`: Path to web icon.png From 0e3ef1ff12ac0ffa21da8719b3dd7ad8d7a65859 Mon Sep 17 00:00:00 2001 From: Ratakondala Arun Date: Sun, 31 Jul 2022 13:55:09 +0530 Subject: [PATCH 4/8] docs(android): added `remove_alpha_ios` config docs closes #386 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3358798ce9..21606b7620 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,8 @@ Shown below is the full list of attributes which you can specify within your Flu - `min_sdk_android`: Specify android min sdk value +- `remove_alpha_ios`: Removes alpha channel for IOS icons + - `web`: Add web related configs - `generate`: Specifies weather to generate icons for this platform or not - `image_path`: Path to web icon.png From f2ae2d95dc88d8084edcc59b53b314bb5b15be51 Mon Sep 17 00:00:00 2001 From: Ratakondala Arun Date: Sun, 31 Jul 2022 14:05:08 +0530 Subject: [PATCH 5/8] docs(android): added `min_sdk_android` config to example --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 21606b7620..c53982274e 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ flutter_icons: android: "launcher_icon" ios: true image_path: "assets/icon/icon.png" + min_sdk_android: 21 # android min sdk min:16 web: generate: true image_path: "path/to/image.png" From 7e3b5a46fb846cee3cb88b85356179c2fb8f5f9d Mon Sep 17 00:00:00 2001 From: Ratakondala Arun Date: Mon, 1 Aug 2022 15:12:45 +0530 Subject: [PATCH 6/8] refactor: changed functions to private --- lib/android.dart | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/lib/android.dart b/lib/android.dart index 9c730d5587..1e9e66738b 100644 --- a/lib/android.dart +++ b/lib/android.dart @@ -43,7 +43,7 @@ void createDefaultIcons(Map flutterLauncherIconsConfig, String? isAndroidIconNameCorrectFormat(iconName); final String iconPath = '$iconName.png'; for (AndroidIconTemplate template in androidIcons) { - saveNewImages(template, image, iconPath, flavor); + _saveNewImages(template, image, iconPath, flavor); } overwriteAndroidManifestWithNewLauncherIcon(iconName, androidManifestFile); } else { @@ -82,7 +82,7 @@ void createAdaptiveIcons(Map flutterLauncherIconsConfig, String // Create adaptive icon background if (isAdaptiveIconConfigPngFile(backgroundConfig)) { - createAdaptiveBackgrounds(flutterLauncherIconsConfig, backgroundConfig, flavor); + _createAdaptiveBackgrounds(flutterLauncherIconsConfig, backgroundConfig, flavor); } else { createAdaptiveIconMipmapXmlFile(flutterLauncherIconsConfig, flavor); updateColorsXmlFile(backgroundConfig, flavor); @@ -127,8 +127,11 @@ void createAdaptiveIconMipmapXmlFile(Map flutterLauncherIconsCo } /// creates adaptive background using png image -void createAdaptiveBackgrounds( - Map yamlConfig, String adaptiveIconBackgroundImagePath, String? flavor) { +void _createAdaptiveBackgrounds( + Map yamlConfig, + String adaptiveIconBackgroundImagePath, + String? flavor, +) { final String filePath = adaptiveIconBackgroundImagePath; final Image? image = decodeImageFile(filePath); if (image == null) { @@ -138,7 +141,7 @@ void createAdaptiveBackgrounds( // 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 @@ -225,7 +228,7 @@ void overwriteExistingIcons( /// 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) @@ -241,12 +244,12 @@ void saveNewImages(AndroidIconTemplate template, Image image, String iconFilePat Future 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 oldManifestLines = (await androidManifestFile.readAsString()).split('\n'); - final List transformedLines = transformAndroidManifestWithNewLauncherIcon(oldManifestLines, iconName); + final List transformedLines = _transformAndroidManifestWithNewLauncherIcon(oldManifestLines, iconName); await androidManifestFile.writeAsString(transformedLines.join('\n')); } /// Updates only the line containing android:icon with the specified iconName -List transformAndroidManifestWithNewLauncherIcon(List oldManifestLines, String iconName) { +List _transformAndroidManifestWithNewLauncherIcon(List 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 @@ -274,13 +277,15 @@ int? minSdk() { final androidLocalPropertiesFile = File(constants.androidLocalPropertiesFile); // looks for minSdk value in build.gradle, flutter.gradle & local.properties. - return getMinSdkFlutterGradle(androidLocalPropertiesFile) ?? - getMinSdkFromFile(androidGradleFile) ?? - getMinSdkFromFile(androidLocalPropertiesFile); + // this should always be order + // first check build.gradle, then local.properties, then flutter.gradle + return _getMinSdkFromFile(androidGradleFile) ?? + _getMinSdkFromFile(androidLocalPropertiesFile) ?? + _getMinSdkFlutterGradle(androidLocalPropertiesFile); } /// Retrieves the minSdk value from [File] -int? getMinSdkFromFile(File file) { +int? _getMinSdkFromFile(File file) { final List lines = file.readAsLinesSync(); for (String line in lines) { if (line.contains('minSdkVersion')) { @@ -297,9 +302,9 @@ int? getMinSdkFromFile(File file) { return null; // Didn't find minSdk, assume the worst } -/// A helper function to [getMinSdkFlutterGradle] +/// A helper function to [_getMinSdkFlutterGradle] /// which retrives value of `flutter.sdk` from `local.properties` file -String? getFlutterSdkPathFromLocalProperties(File file) { +String? _getFlutterSdkPathFromLocalProperties(File file) { final List lines = file.readAsLinesSync(); for (String line in lines) { if (!line.contains('flutter.sdk=')) { @@ -318,8 +323,8 @@ String? getFlutterSdkPathFromLocalProperties(File file) { } /// Retrives value of `minSdkVersion` from `flutter.gradle` -int? getMinSdkFlutterGradle(File localPropertiesFile) { - final flutterRoot = getFlutterSdkPathFromLocalProperties(localPropertiesFile); +int? _getMinSdkFlutterGradle(File localPropertiesFile) { + final flutterRoot = _getFlutterSdkPathFromLocalProperties(localPropertiesFile); if (flutterRoot == null) { return null; } From 0f3ad185b4719da3d3a93f4cc750e55aeef22ea3 Mon Sep 17 00:00:00 2001 From: Ratakondala Arun Date: Mon, 1 Aug 2022 20:43:32 +0530 Subject: [PATCH 7/8] feat(configs): added new configs to `FlutterLauncherIconsConfig` added `min_sdk_android` and `remove_alpha_ios` to `FlutterLauncherIconsConfig` --- lib/constants.dart | 3 +++ lib/flutter_launcher_icons_config.dart | 10 ++++++++++ lib/flutter_launcher_icons_config.g.dart | 8 ++++++++ test/abs/icon_generator_test.mocks.dart | 8 ++++++++ test/flutter_launcher_icons_config_test.dart | 4 ++++ test/templates.dart | 4 ++++ test/windows/windows_icon_generator_test.mocks.dart | 8 ++++++++ 7 files changed, 45 insertions(+) diff --git a/lib/constants.dart b/lib/constants.dart index 307e4db48d..2214ecc07f 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -13,6 +13,9 @@ const String androidLocalPropertiesFile = 'android/local.properties'; /// Relative path to flutter.gradle from flutter sdk path const String androidFlutterGardlePath = 'packages/flutter_tools/gradle/flutter.gradle'; +/// Default min_sdk value for android +/// https://github.com/flutter/flutter/blob/master/packages/flutter_tools/gradle/flutter.gradle#L35-L37 +const int androidDefaultAndroidMinSDK = 21; const String androidFileName = 'ic_launcher.png'; const String androidAdaptiveForegroundFileName = 'ic_launcher_foreground.png'; const String androidAdaptiveBackgroundFileName = 'ic_launcher_background.png'; diff --git a/lib/flutter_launcher_icons_config.dart b/lib/flutter_launcher_icons_config.dart index f386bee11f..b5baa3f862 100644 --- a/lib/flutter_launcher_icons_config.dart +++ b/lib/flutter_launcher_icons_config.dart @@ -42,6 +42,14 @@ class FlutterLauncherIconsConfig { @JsonKey(name: 'adaptive_icon_background') final String? adaptiveIconBackground; + /// Android min_sdk_android + @JsonKey(name: 'min_sdk_android', defaultValue: constants.androidDefaultAndroidMinSDK) + final int minSdkAndroid; + + /// IOS remove_alpha_ios + @JsonKey(name: 'remove_alpha_ios', defaultValue: true) + final bool removeAlphaIOS; + /// Web platform config @JsonKey(name: 'web') final WebConfig? webConfig; @@ -59,6 +67,8 @@ class FlutterLauncherIconsConfig { this.imagePathIOS, this.adaptiveIconForeground, this.adaptiveIconBackground, + this.minSdkAndroid = constants.androidDefaultAndroidMinSDK, + this.removeAlphaIOS = true, this.webConfig, this.windowsConfig, }); diff --git a/lib/flutter_launcher_icons_config.g.dart b/lib/flutter_launcher_icons_config.g.dart index 7e9c9eb621..13881e7d9e 100644 --- a/lib/flutter_launcher_icons_config.g.dart +++ b/lib/flutter_launcher_icons_config.g.dart @@ -22,6 +22,10 @@ FlutterLauncherIconsConfig _$FlutterLauncherIconsConfigFromJson(Map json) => $checkedConvert('adaptive_icon_foreground', (v) => v as String?), adaptiveIconBackground: $checkedConvert('adaptive_icon_background', (v) => v as String?), + minSdkAndroid: + $checkedConvert('min_sdk_android', (v) => v as int? ?? 21), + removeAlphaIOS: + $checkedConvert('remove_alpha_ios', (v) => v as bool? ?? true), webConfig: $checkedConvert( 'web', (v) => v == null ? null : WebConfig.fromJson(v as Map)), windowsConfig: $checkedConvert('windows', @@ -35,6 +39,8 @@ FlutterLauncherIconsConfig _$FlutterLauncherIconsConfigFromJson(Map json) => 'imagePathIOS': 'image_path_ios', 'adaptiveIconForeground': 'adaptive_icon_foreground', 'adaptiveIconBackground': 'adaptive_icon_background', + 'minSdkAndroid': 'min_sdk_android', + 'removeAlphaIOS': 'remove_alpha_ios', 'webConfig': 'web', 'windowsConfig': 'windows' }, @@ -50,6 +56,8 @@ Map _$FlutterLauncherIconsConfigToJson( 'image_path_ios': instance.imagePathIOS, 'adaptive_icon_foreground': instance.adaptiveIconForeground, 'adaptive_icon_background': instance.adaptiveIconBackground, + 'min_sdk_android': instance.minSdkAndroid, + 'remove_alpha_ios': instance.removeAlphaIOS, 'web': instance.webConfig, 'windows': instance.windowsConfig, }; diff --git a/test/abs/icon_generator_test.mocks.dart b/test/abs/icon_generator_test.mocks.dart index b849b992cf..b69e2a2d26 100644 --- a/test/abs/icon_generator_test.mocks.dart +++ b/test/abs/icon_generator_test.mocks.dart @@ -29,6 +29,14 @@ class MockFlutterLauncherIconsConfig extends _i1.Mock _i1.throwOnMissingStub(this); } + @override + int get minSdkAndroid => + (super.noSuchMethod(Invocation.getter(#minSdkAndroid), returnValue: 0) + as int); + @override + bool get removeAlphaIOS => (super + .noSuchMethod(Invocation.getter(#removeAlphaIOS), returnValue: false) + as bool); @override Map toJson() => (super.noSuchMethod(Invocation.method(#toJson, []), diff --git a/test/flutter_launcher_icons_config_test.dart b/test/flutter_launcher_icons_config_test.dart index df770e7e90..1198682a08 100644 --- a/test/flutter_launcher_icons_config_test.dart +++ b/test/flutter_launcher_icons_config_test.dart @@ -28,9 +28,11 @@ void main() { expect(configs.imagePathAndroid, isNotNull); expect(configs.adaptiveIconBackground, isNotNull); expect(configs.adaptiveIconForeground, isNotNull); + expect(configs.minSdkAndroid, equals(21)); // ios configs expect(configs.ios, isTrue); expect(configs.imagePathIOS, isNotNull); + expect(configs.removeAlphaIOS, isFalse); // web configs expect(configs.webConfig, isNotNull); expect(configs.webConfig!.generate, isTrue); @@ -91,9 +93,11 @@ void main() { expect(configs.imagePathAndroid, isNotNull); expect(configs.adaptiveIconBackground, isNotNull); expect(configs.adaptiveIconForeground, isNotNull); + expect(configs.minSdkAndroid, equals(21)); // ios configs expect(configs.ios, isTrue); expect(configs.imagePathIOS, isNotNull); + expect(configs.removeAlphaIOS, isFalse); // web configs expect(configs.webConfig, isNotNull); expect(configs.webConfig!.generate, isTrue); diff --git a/test/templates.dart b/test/templates.dart index d88d384120..7a0c59396f 100644 --- a/test/templates.dart +++ b/test/templates.dart @@ -7,6 +7,8 @@ flutter_icons: image_path_ios: "assets/images/icon-1024x1024.png" adaptive_icon_background: "assets/images/christmas-background.png" adaptive_icon_foreground: "assets/images/icon-foreground-432x432.png" + min_sdk_android: 21 + remove_alpha_ios: false web: generate: true image_path: "app_icon.png" # filepath @@ -123,6 +125,8 @@ flutter_icons: image_path_ios: "assets/images/icon-1024x1024.png" adaptive_icon_background: "assets/images/christmas-background.png" adaptive_icon_foreground: "assets/images/icon-foreground-432x432.png" + min_sdk_android: 21 + remove_alpha_ios: false web: generate: true image_path: "app_icon.png" # filepath diff --git a/test/windows/windows_icon_generator_test.mocks.dart b/test/windows/windows_icon_generator_test.mocks.dart index 0436a54ada..a53b647df8 100644 --- a/test/windows/windows_icon_generator_test.mocks.dart +++ b/test/windows/windows_icon_generator_test.mocks.dart @@ -31,6 +31,14 @@ class MockFlutterLauncherIconsConfig extends _i1.Mock _i1.throwOnMissingStub(this); } + @override + int get minSdkAndroid => + (super.noSuchMethod(Invocation.getter(#minSdkAndroid), returnValue: 0) + as int); + @override + bool get removeAlphaIOS => (super + .noSuchMethod(Invocation.getter(#removeAlphaIOS), returnValue: false) + as bool); @override Map toJson() => (super.noSuchMethod(Invocation.method(#toJson, []), From f58fdce940b63c887b0943ef2fb54c6df8cad2b7 Mon Sep 17 00:00:00 2001 From: Ratakondala Arun Date: Mon, 1 Aug 2022 20:46:10 +0530 Subject: [PATCH 8/8] refactor: added 21 as default min_sdk_android --- README.md | 2 +- lib/android.dart | 5 +++-- lib/main.dart | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c53982274e..0487494d71 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ flutter_icons: android: "launcher_icon" ios: true image_path: "assets/icon/icon.png" - min_sdk_android: 21 # android min sdk min:16 + min_sdk_android: 21 # android min sdk min:16, default 21 web: generate: true image_path: "path/to/image.png" diff --git a/lib/android.dart b/lib/android.dart index 1e9e66738b..39a96df9a1 100644 --- a/lib/android.dart +++ b/lib/android.dart @@ -272,7 +272,7 @@ List _transformAndroidManifestWithNewLauncherIcon(List oldManife /// - local.properties: `'android/local.properties'` /// /// If found none returns 0 -int? minSdk() { +int minSdk() { final androidGradleFile = File(constants.androidGradleFile); final androidLocalPropertiesFile = File(constants.androidLocalPropertiesFile); @@ -281,7 +281,8 @@ int? minSdk() { // first check build.gradle, then local.properties, then flutter.gradle return _getMinSdkFromFile(androidGradleFile) ?? _getMinSdkFromFile(androidLocalPropertiesFile) ?? - _getMinSdkFlutterGradle(androidLocalPropertiesFile); + _getMinSdkFlutterGradle(androidLocalPropertiesFile) ?? + constants.androidDefaultAndroidMinSDK; } /// Retrieves the minSdk value from [File] diff --git a/lib/main.dart b/lib/main.dart index 64c9a48fe4..50ed76c9cd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -125,7 +125,7 @@ Future createIconsFromConfig( } if (isNeedingNewAndroidIcon(config) || hasAndroidAdaptiveConfig(config)) { - final int minSdk = config['min_sdk_android'] ?? android_launcher_icons.minSdk() ?? 0; + final int minSdk = config['min_sdk_android'] ?? android_launcher_icons.minSdk(); if (minSdk == 0) { throw const InvalidConfigException(errorMissingMinSdk); }