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); }