1
1
import 'dart:io' ;
2
+
2
3
import 'package:flutter_launcher_icons/constants.dart' ;
4
+ import 'package:flutter_launcher_icons/constants.dart' as constants;
5
+ import 'package:flutter_launcher_icons/custom_exceptions.dart' ;
3
6
import 'package:flutter_launcher_icons/flutter_launcher_icons_config.dart' ;
4
7
import 'package:flutter_launcher_icons/utils.dart' ;
5
8
import 'package:flutter_launcher_icons/xml_templates.dart' as xml_template;
6
9
import 'package:image/image.dart' ;
7
- import 'package:flutter_launcher_icons/custom_exceptions.dart' ;
8
- import 'package:flutter_launcher_icons/constants.dart' as constants;
9
10
import 'package:path/path.dart' as path;
10
11
11
12
class AndroidIconTemplate {
@@ -31,7 +32,10 @@ List<AndroidIconTemplate> androidIcons = <AndroidIconTemplate>[
31
32
AndroidIconTemplate (directoryName: 'mipmap-xxxhdpi' , size: 192 ),
32
33
];
33
34
34
- void createDefaultIcons (FlutterLauncherIconsConfig flutterLauncherIconsConfig, String ? flavor) {
35
+ void createDefaultIcons (
36
+ FlutterLauncherIconsConfig flutterLauncherIconsConfig,
37
+ String ? flavor,
38
+ ) {
35
39
printStatus ('Creating default icons Android' );
36
40
// todo: support prefixPath
37
41
final String ? filePath = flutterLauncherIconsConfig.getImagePathAndroid ();
@@ -53,29 +57,46 @@ void createDefaultIcons(FlutterLauncherIconsConfig flutterLauncherIconsConfig, S
53
57
}
54
58
overwriteAndroidManifestWithNewLauncherIcon (iconName, androidManifestFile);
55
59
} else {
56
- printStatus ('Overwriting the default Android launcher icon with a new icon' );
60
+ printStatus (
61
+ 'Overwriting the default Android launcher icon with a new icon' ,
62
+ );
57
63
for (AndroidIconTemplate template in androidIcons) {
58
- overwriteExistingIcons (template, image, constants.androidFileName, flavor);
64
+ overwriteExistingIcons (
65
+ template,
66
+ image,
67
+ constants.androidFileName,
68
+ flavor,
69
+ );
59
70
}
60
- overwriteAndroidManifestWithNewLauncherIcon (constants.androidDefaultIconName, androidManifestFile);
71
+ overwriteAndroidManifestWithNewLauncherIcon (
72
+ constants.androidDefaultIconName,
73
+ androidManifestFile,
74
+ );
61
75
}
62
76
}
63
77
64
78
/// Ensures that the Android icon name is in the correct format
65
79
bool isAndroidIconNameCorrectFormat (String iconName) {
66
80
// assure the icon only consists of lowercase letters, numbers and underscore
67
81
if (! RegExp (r'^[a-z0-9_]+$' ).hasMatch (iconName)) {
68
- throw const InvalidAndroidIconNameException (constants.errorIncorrectIconName);
82
+ throw const InvalidAndroidIconNameException (
83
+ constants.errorIncorrectIconName,
84
+ );
69
85
}
70
86
return true ;
71
87
}
72
88
73
- void createAdaptiveIcons (FlutterLauncherIconsConfig flutterLauncherIconsConfig, String ? flavor) {
89
+ void createAdaptiveIcons (
90
+ FlutterLauncherIconsConfig flutterLauncherIconsConfig,
91
+ String ? flavor,
92
+ ) {
74
93
printStatus ('Creating adaptive icons Android' );
75
94
76
95
// Retrieve the necessary Flutter Launcher Icons configuration from the pubspec.yaml file
77
- final String ? backgroundConfig = flutterLauncherIconsConfig.adaptiveIconBackground;
78
- final String ? foregroundImagePath = flutterLauncherIconsConfig.adaptiveIconForeground;
96
+ final String ? backgroundConfig =
97
+ flutterLauncherIconsConfig.adaptiveIconBackground;
98
+ final String ? foregroundImagePath =
99
+ flutterLauncherIconsConfig.adaptiveIconForeground;
79
100
if (backgroundConfig == null || foregroundImagePath == null ) {
80
101
throw const InvalidConfigException (errorMissingImagePath);
81
102
}
@@ -86,12 +107,21 @@ void createAdaptiveIcons(FlutterLauncherIconsConfig flutterLauncherIconsConfig,
86
107
87
108
// Create adaptive icon foreground images
88
109
for (AndroidIconTemplate androidIcon in adaptiveForegroundIcons) {
89
- overwriteExistingIcons (androidIcon, foregroundImage, constants.androidAdaptiveForegroundFileName, flavor);
110
+ overwriteExistingIcons (
111
+ androidIcon,
112
+ foregroundImage,
113
+ constants.androidAdaptiveForegroundFileName,
114
+ flavor,
115
+ );
90
116
}
91
117
92
118
// Create adaptive icon background
93
119
if (isAdaptiveIconConfigPngFile (backgroundConfig)) {
94
- _createAdaptiveBackgrounds (flutterLauncherIconsConfig, backgroundConfig, flavor);
120
+ _createAdaptiveBackgrounds (
121
+ flutterLauncherIconsConfig,
122
+ backgroundConfig,
123
+ flavor,
124
+ );
95
125
} else {
96
126
createAdaptiveIconMipmapXmlFile (flutterLauncherIconsConfig, flavor);
97
127
updateColorsXmlFile (backgroundConfig, flavor);
@@ -112,24 +142,33 @@ void updateColorsXmlFile(String backgroundConfig, String? flavor) {
112
142
updateColorsFile (colorsXml, backgroundConfig);
113
143
} else {
114
144
printStatus ('No colors.xml file found in your Android project' );
115
- printStatus ('Creating colors.xml file and adding it to your Android project' );
145
+ printStatus (
146
+ 'Creating colors.xml file and adding it to your Android project' ,
147
+ );
116
148
createNewColorsFile (backgroundConfig, flavor);
117
149
}
118
150
}
119
151
120
152
/// Creates the xml file required for the adaptive launcher icon
121
153
/// FILE LOCATED HERE: res/mipmap-anydpi/{icon-name-from-yaml-config}.xml
122
- void createAdaptiveIconMipmapXmlFile (FlutterLauncherIconsConfig flutterLauncherIconsConfig, String ? flavor) {
154
+ void createAdaptiveIconMipmapXmlFile (
155
+ FlutterLauncherIconsConfig flutterLauncherIconsConfig,
156
+ String ? flavor,
157
+ ) {
123
158
if (flutterLauncherIconsConfig.isCustomAndroidFile) {
124
- File (constants.androidAdaptiveXmlFolder (flavor) + flutterLauncherIconsConfig.android + '.xml' )
125
- .create (recursive: true )
126
- .then ((File adaptiveIcon) {
159
+ File (
160
+ constants.androidAdaptiveXmlFolder (flavor) +
161
+ flutterLauncherIconsConfig.android +
162
+ '.xml' ,
163
+ ).create (recursive: true ).then ((File adaptiveIcon) {
127
164
adaptiveIcon.writeAsString (xml_template.icLauncherXml);
128
165
});
129
166
} else {
130
- File (constants.androidAdaptiveXmlFolder (flavor) + constants.androidDefaultIconName + '.xml' )
131
- .create (recursive: true )
132
- .then ((File adaptiveIcon) {
167
+ File (
168
+ constants.androidAdaptiveXmlFolder (flavor) +
169
+ constants.androidDefaultIconName +
170
+ '.xml' ,
171
+ ).create (recursive: true ).then ((File adaptiveIcon) {
133
172
adaptiveIcon.writeAsString (xml_template.icLauncherXml);
134
173
});
135
174
}
@@ -150,29 +189,40 @@ void _createAdaptiveBackgrounds(
150
189
// creates a png image (ic_adaptive_background.png) for the adaptive icon background in each of the locations
151
190
// it is required
152
191
for (AndroidIconTemplate androidIcon in adaptiveForegroundIcons) {
153
- _saveNewImages (androidIcon, image, constants.androidAdaptiveBackgroundFileName, flavor);
192
+ _saveNewImages (
193
+ androidIcon,
194
+ image,
195
+ constants.androidAdaptiveBackgroundFileName,
196
+ flavor,
197
+ );
154
198
}
155
199
156
200
// Creates the xml file required for the adaptive launcher icon
157
201
// FILE LOCATED HERE: res/mipmap-anydpi/{icon-name-from-yaml-config}.xml
158
202
if (flutterLauncherIconsConfig.isCustomAndroidFile) {
159
- File (constants.androidAdaptiveXmlFolder (flavor) + flutterLauncherIconsConfig.android + '.xml' )
160
- .create (recursive: true )
161
- .then ((File adaptiveIcon) {
203
+ File (
204
+ constants.androidAdaptiveXmlFolder (flavor) +
205
+ flutterLauncherIconsConfig.android +
206
+ '.xml' ,
207
+ ).create (recursive: true ).then ((File adaptiveIcon) {
162
208
adaptiveIcon.writeAsString (xml_template.icLauncherDrawableBackgroundXml);
163
209
});
164
210
} else {
165
- File (constants.androidAdaptiveXmlFolder (flavor) + constants.androidDefaultIconName + '.xml' )
166
- .create (recursive: true )
167
- .then ((File adaptiveIcon) {
211
+ File (
212
+ constants.androidAdaptiveXmlFolder (flavor) +
213
+ constants.androidDefaultIconName +
214
+ '.xml' ,
215
+ ).create (recursive: true ).then ((File adaptiveIcon) {
168
216
adaptiveIcon.writeAsString (xml_template.icLauncherDrawableBackgroundXml);
169
217
});
170
218
}
171
219
}
172
220
173
221
/// Creates a colors.xml file if it was missing from android/app/src/main/res/values/colors.xml
174
222
void createNewColorsFile (String backgroundColor, String ? flavor) {
175
- File (constants.androidColorsFile (flavor)).create (recursive: true ).then ((File colorsFile) {
223
+ File (constants.androidColorsFile (flavor))
224
+ .create (recursive: true )
225
+ .then ((File colorsFile) {
176
226
colorsFile.writeAsString (xml_template.colorsXml).then ((File file) {
177
227
updateColorsFile (colorsFile, backgroundColor);
178
228
});
@@ -197,7 +247,10 @@ void updateColorsFile(File colorsFile, String backgroundColor) {
197
247
198
248
// Add new line if we didn't find an existing value
199
249
if (! foundExisting) {
200
- lines.insert (lines.length - 1 , '\t <color name="ic_launcher_background">$backgroundColor </color>' );
250
+ lines.insert (
251
+ lines.length - 1 ,
252
+ '\t <color name="ic_launcher_background">$backgroundColor </color>' ,
253
+ );
201
254
}
202
255
203
256
colorsFile.writeAsStringSync (lines.join ('\n ' ));
@@ -214,21 +267,32 @@ void overwriteExistingIcons(
214
267
String ? flavor,
215
268
) {
216
269
final Image newFile = createResizedImage (template.size, image);
217
- File (constants.androidResFolder (flavor) + template.directoryName + '/' + filename)
218
- .create (recursive: true )
219
- .then ((File file) {
270
+ File (
271
+ constants.androidResFolder (flavor) +
272
+ template.directoryName +
273
+ '/' +
274
+ filename,
275
+ ).create (recursive: true ).then ((File file) {
220
276
file.writeAsBytesSync (encodePng (newFile));
221
277
});
222
278
}
223
279
224
280
/// Saves new launcher icons to the project, keeping the old launcher icons.
225
281
/// Note: Do not change interpolation unless you end up with better results
226
282
/// https://github.com/fluttercommunity/flutter_launcher_icons/issues/101#issuecomment-495528733
227
- void _saveNewImages (AndroidIconTemplate template, Image image, String iconFilePath, String ? flavor) {
283
+ void _saveNewImages (
284
+ AndroidIconTemplate template,
285
+ Image image,
286
+ String iconFilePath,
287
+ String ? flavor,
288
+ ) {
228
289
final Image newFile = createResizedImage (template.size, image);
229
- File (constants.androidResFolder (flavor) + template.directoryName + '/' + iconFilePath)
230
- .create (recursive: true )
231
- .then ((File file) {
290
+ File (
291
+ constants.androidResFolder (flavor) +
292
+ template.directoryName +
293
+ '/' +
294
+ iconFilePath,
295
+ ).create (recursive: true ).then ((File file) {
232
296
file.writeAsBytesSync (encodePng (newFile));
233
297
});
234
298
}
@@ -237,15 +301,23 @@ void _saveNewImages(AndroidIconTemplate template, Image image, String iconFilePa
237
301
/// with the new icon name (only if it has changed)
238
302
///
239
303
/// Note: default iconName = "ic_launcher"
240
- Future <void > overwriteAndroidManifestWithNewLauncherIcon (String iconName, File androidManifestFile) async {
304
+ Future <void > overwriteAndroidManifestWithNewLauncherIcon (
305
+ String iconName,
306
+ File androidManifestFile,
307
+ ) async {
241
308
// we do not use `file.readAsLinesSync()` here because that always gets rid of the last empty newline
242
- final List <String > oldManifestLines = (await androidManifestFile.readAsString ()).split ('\n ' );
243
- final List <String > transformedLines = _transformAndroidManifestWithNewLauncherIcon (oldManifestLines, iconName);
309
+ final List <String > oldManifestLines =
310
+ (await androidManifestFile.readAsString ()).split ('\n ' );
311
+ final List <String > transformedLines =
312
+ _transformAndroidManifestWithNewLauncherIcon (oldManifestLines, iconName);
244
313
await androidManifestFile.writeAsString (transformedLines.join ('\n ' ));
245
314
}
246
315
247
316
/// Updates only the line containing android:icon with the specified iconName
248
- List <String > _transformAndroidManifestWithNewLauncherIcon (List <String > oldManifestLines, String iconName) {
317
+ List <String > _transformAndroidManifestWithNewLauncherIcon (
318
+ List <String > oldManifestLines,
319
+ String iconName,
320
+ ) {
249
321
return oldManifestLines.map ((String line) {
250
322
if (line.contains ('android:icon' )) {
251
323
// Using RegExp replace the value of android:icon to point to the new icon
@@ -255,7 +327,10 @@ List<String> _transformAndroidManifestWithNewLauncherIcon(List<String> oldManife
255
327
// repeat as often as wanted with no quote at start: [^"]*(\"[^"]*)*
256
328
// escaping the slash to place in string: [^"]*(\\"[^"]*)*"
257
329
// result: any string which does only include escaped quotes
258
- return line.replaceAll (RegExp (r'android:icon="[^"]*(\\"[^"]*)*"' ), 'android:icon="@mipmap/$iconName "' );
330
+ return line.replaceAll (
331
+ RegExp (r'android:icon="[^"]*(\\"[^"]*)*"' ),
332
+ 'android:icon="@mipmap/$iconName "' ,
333
+ );
259
334
} else {
260
335
return line;
261
336
}
@@ -286,7 +361,8 @@ int? _getMinSdkFromFile(File file) {
286
361
final List <String > lines = file.readAsLinesSync ();
287
362
for (String line in lines) {
288
363
if (line.contains ('minSdkVersion' )) {
289
- if (line.contains ('//' ) && line.indexOf ('//' ) < line.indexOf ('minSdkVersion' )) {
364
+ if (line.contains ('//' ) &&
365
+ line.indexOf ('//' ) < line.indexOf ('minSdkVersion' )) {
290
366
// This line is commented
291
367
continue ;
292
368
}
@@ -307,7 +383,8 @@ String? _getFlutterSdkPathFromLocalProperties(File file) {
307
383
if (! line.contains ('flutter.sdk=' )) {
308
384
continue ;
309
385
}
310
- if (line.contains ('#' ) && line.indexOf ('#' ) < line.indexOf ('flutter.sdk=' )) {
386
+ if (line.contains ('#' ) &&
387
+ line.indexOf ('#' ) < line.indexOf ('flutter.sdk=' )) {
311
388
continue ;
312
389
}
313
390
final flutterSdkPath = line.split ('=' ).last.trim ();
@@ -321,19 +398,22 @@ String? _getFlutterSdkPathFromLocalProperties(File file) {
321
398
322
399
/// Retrives value of `minSdkVersion` from `flutter.gradle`
323
400
int ? _getMinSdkFlutterGradle (File localPropertiesFile) {
324
- final flutterRoot = _getFlutterSdkPathFromLocalProperties (localPropertiesFile);
401
+ final flutterRoot =
402
+ _getFlutterSdkPathFromLocalProperties (localPropertiesFile);
325
403
if (flutterRoot == null ) {
326
404
return null ;
327
405
}
328
406
329
- final flutterGradleFile = File (path.join (flutterRoot, constants.androidFlutterGardlePath));
407
+ final flutterGradleFile =
408
+ File (path.join (flutterRoot, constants.androidFlutterGardlePath));
330
409
331
410
final List <String > lines = flutterGradleFile.readAsLinesSync ();
332
411
for (String line in lines) {
333
412
if (! line.contains ('static int minSdkVersion =' )) {
334
413
continue ;
335
414
}
336
- if (line.contains ('//' ) && line.indexOf ('//' ) < line.indexOf ('static int minSdkVersion =' )) {
415
+ if (line.contains ('//' ) &&
416
+ line.indexOf ('//' ) < line.indexOf ('static int minSdkVersion =' )) {
337
417
continue ;
338
418
}
339
419
final minSdk = line.split ('=' ).last.trim ();
0 commit comments