Skip to content

Commit

Permalink
* Fixed bug that created duplicate android:windowFullscreen tags in s…
Browse files Browse the repository at this point in the history
…tyles.xml. Closes #147.

* Fixed fullscreen in Android dark mode.
* Print errors instead of throwing exceptions for cleaner output.
* Added message for missing subviews in iOS LaunchScreen.storyboard. Fixes #146.
* Removed duplicate exceptions for missing image file since that is now checked at package start.
  • Loading branch information
jonbhanson committed Mar 18, 2021
1 parent 708b03e commit 6c3d4f4
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 153 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## [1.1.4] - (2021-Mar-18)

* Fixed bug that created duplicate android:windowFullscreen tags in styles.xml. Closes [#147](https://github.com/jonbhanson/flutter_native_splash/issues/147).
* Fixed fullscreen in Android dark mode.
* Print errors instead of throwing exceptions for cleaner output.
* Added message for missing subviews in iOS LaunchScreen.storyboard. Fixes [#146](https://github.com/jonbhanson/flutter_native_splash/issues/146).
* Removed duplicate exceptions for missing image file since that is now checked at package start.

## [1.1.3] - (2021-Mar-18)

* Fixed bug that was giving error on copying background image. Closes [#144](https://github.com/jonbhanson/flutter_native_splash/issues/144).
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ First, add `flutter_native_splash` as a dev dependency in your pubspec.yaml file

```yaml
dev_dependencies:
flutter_native_splash: ^1.1.3
flutter_native_splash: ^1.1.4
```
Don't forget to `flutter pub get`.
Expand Down
94 changes: 45 additions & 49 deletions lib/android.dart
Original file line number Diff line number Diff line change
Expand Up @@ -94,22 +94,24 @@ void _createAndroidSplash({
}
}

_applyStylesXml(fullScreen: fullscreen);
_applyStylesXml(
fullScreen: fullscreen,
file: _androidStylesFile,
template: _androidStylesXml);
_applyStylesXml(
fullScreen: fullscreen,
file: _androidNightStylesFile,
template: _androidNightStylesFile);
}

/// Create splash screen as drawables for multiple screens (dpi)
void _applyImageAndroid({required String imagePath, bool dark = false}) {
print('[Android] Creating ' + (dark ? 'dark mode ' : '') + 'splash images');

final file = File(imagePath);

if (!file.existsSync()) {
throw _NoImageFileFoundException('The file $imagePath was not found.');
}

final image = decodeImage(File(imagePath).readAsBytesSync());
if (image == null) {
throw _NoImageFileFoundException('The file $imagePath could not be read.');
print('The file $imagePath could not be read.');
exit(1);
}

for (var template in dark ? _splashImagesDark : _splashImages) {
Expand Down Expand Up @@ -160,14 +162,18 @@ void _applyLaunchBackgroundXml(
}

/// Create or update styles.xml full screen mode setting
void _applyStylesXml({required bool fullScreen}) {
final stylesFile = File(_androidStylesFile);
void _applyStylesXml(
{required bool fullScreen,
required String file,
required String template}) {
final stylesFile = File(file);

if (!stylesFile.existsSync()) {
print('[Android] No styles.xml file found in your Android project');
print(
'[Android] Creating styles.xml file and adding it to your Android project');
_createStylesFileWithImagePath(stylesFile: stylesFile);
print('[Android] Creating styles.xml file and adding it to your Android '
'project');
stylesFile.createSync(recursive: true);
stylesFile.writeAsStringSync(template);
}
print('[Android] Updating styles.xml with full screen mode setting');
_updateStylesFile(fullScreen: fullScreen, stylesFile: stylesFile);
Expand All @@ -176,48 +182,38 @@ void _applyStylesXml({required bool fullScreen}) {
/// Updates styles.xml adding full screen property
void _updateStylesFile({required bool fullScreen, required File stylesFile}) {
final stylesDocument = XmlDocument.parse(stylesFile.readAsStringSync());
final styles = stylesDocument.findAllElements('style');
if (styles.length == 1) {
final resources = stylesDocument.getElement('resources');
final styles = resources?.findElements('style');
if (styles?.length == 1) {
print('[Android] Only 1 style in styles.xml. Flutter V2 embedding has 2 '
'styles by default. Full screen mode not supported in Flutter V1 '
'embedding. Skipping update of styles.xml with fullscreen mode');
return;
}
var found = true;
final launchTheme = styles.firstWhere(
(element) => (element.attributes.any((attribute) =>
attribute.name.toString() == 'name' &&
attribute.value == 'LaunchTheme')), orElse: () {
found = false;
return XmlElement(XmlName('dummy'));
});
if (found) {
final fullScreenElement = launchTheme.children.firstWhere(
(element) => (element.attributes.any((attribute) {
return attribute.name.toString() == 'name' &&
attribute.value == 'android:windowFullscreen';
})), orElse: () {
found = false;
return XmlElement(XmlName('dummy'));
});
if (found) {
launchTheme.children.add(XmlElement(
XmlName('item'),
[XmlAttribute(XmlName('name'), 'android:windowFullscreen')],
[XmlText(fullScreen.toString())]));
} else {
fullScreenElement.children.clear();
fullScreenElement.children.add(XmlText(fullScreen.toString()));
}
stylesFile.writeAsStringSync(
stylesDocument.toXmlString(pretty: true, indent: ' '));

XmlElement launchTheme;
try {
launchTheme = styles!.singleWhere((element) => (element.attributes.any(
(attribute) =>
attribute.name.toString() == 'name' &&
attribute.value == 'LaunchTheme')));
} on StateError {
print('LaunchTheme was not found in styles.xml. Skipping fullscreen'
'mode');
return;
}
print('[Android] Failed to update styles.xml with full screen mode setting');
}

/// Creates styles.xml with full screen property
void _createStylesFileWithImagePath({required File stylesFile}) {
stylesFile.createSync(recursive: true);
stylesFile.writeAsStringSync(_androidStylesXml);
launchTheme.children
.removeWhere((element) => (element.attributes.any((attribute) {
return attribute.name.toString() == 'name' &&
attribute.value == 'android:windowFullscreen';
})));

launchTheme.children.add(XmlElement(
XmlName('item'),
[XmlAttribute(XmlName('name'), 'android:windowFullscreen')],
[XmlText(fullScreen.toString())]));

stylesFile.writeAsStringSync(
stylesDocument.toXmlString(pretty: true, indent: ' '));
}
2 changes: 2 additions & 0 deletions lib/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const String _androidLaunchBackgroundFile =
const String _androidLaunchDarkBackgroundFile =
_androidNightDrawableFolder + 'launch_background.xml';
const String _androidStylesFile = _androidResFolder + 'values/styles.xml';
const String _androidNightStylesFile =
_androidResFolder + 'values-night/styles.xml';
const String _androidV21DrawableFolder = _androidResFolder + 'drawable-v21/';
const String _androidV21LaunchBackgroundFile =
_androidV21DrawableFolder + 'launch_background.xml';
Expand Down
61 changes: 0 additions & 61 deletions lib/exceptions.dart

This file was deleted.

64 changes: 37 additions & 27 deletions lib/ios.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,11 @@ void _createiOSSplash({
/// Create splash screen images for original size, @2x and @3x
void _applyImageiOS({required String imagePath, bool dark = false}) {
print('[iOS] Creating ' + (dark ? 'dark mode ' : '') + 'splash images');
if (!File(imagePath).existsSync()) {
throw _NoImageFileFoundException('The file $imagePath was not found.');
}

final image = decodeImage(File(imagePath).readAsBytesSync());
if (image == null) {
throw _NoImageFileFoundException(imagePath + ' could not be loaded.');
print(imagePath + ' could not be loaded.');
exit(1);
}
for (var template in dark ? _iOSSplashImagesDark : _iOSSplashImages) {
_saveImageiOS(template: template, image: image);
Expand Down Expand Up @@ -127,8 +125,8 @@ void _applyLaunchScreenStoryboard(
imagePath: imagePath, iosContentMode: iosContentMode);
} else {
print('[iOS] No LaunchScreen.storyboard file found in your iOS project');
print(
'[iOS] Creating LaunchScreen.storyboard file and adding it to your iOS project');
print('[iOS] Creating LaunchScreen.storyboard file and adding it '
'to your iOS project');
return _createLaunchScreenStoryboard(
imagePath: imagePath, iosContentMode: iosContentMode);
}
Expand All @@ -149,34 +147,49 @@ void _updateLaunchScreenStoryboard(
element.getAttribute('id') == 'Ze5-6b-2t3');
});
if (view == null) {
throw _LaunchScreenStoryboardModified(
'Default Flutter view Ze5-6b-2t3 not found. Did you modify your default LaunchScreen.storyboard file?');
print('Default Flutter view Ze5-6b-2t3 not found. '
'Did you modify your default LaunchScreen.storyboard file?');
exit(1);
}

// Find the splash imageView
final subViews = view.getElement('subviews');
final imageView = subViews?.children.whereType<XmlElement>().firstWhere(
if (subViews == null) {
print('Not able to find "subviews" in LaunchScreen.storyboard. Image for '
'splash screen not updated. Did you modify your default '
'LaunchScreen.storyboard file?');
exit(1);
}
final imageView = subViews.children.whereType<XmlElement>().firstWhere(
(element) => (element.name.qualified == 'imageView' &&
element.getAttribute('image') == 'LaunchImage'),
orElse: () => throw _LaunchScreenStoryboardModified(
"Not able to find 'LaunchImage' in LaunchScreen.storyboard. Image for splash screen not updated. Did you modify your default LaunchScreen.storyboard file?"));
subViews?.children.whereType<XmlElement>().firstWhere(
element.getAttribute('image') == 'LaunchImage'), orElse: () {
print('Not able to find "LaunchImage" in LaunchScreen.storyboard. Image '
'for splash screen not updated. Did you modify your default '
'LaunchScreen.storyboard file?');
exit(1);
});
subViews.children.whereType<XmlElement>().firstWhere(
(element) => (element.name.qualified == 'imageView' &&
element.getAttribute('image') == 'LaunchBackground'), orElse: () {
subViews.children.insert(
0, XmlDocument.parse(_iOSLaunchBackgroundSubview).rootElement.copy());
return XmlElement(XmlName(''));
});
// Update the fill property
imageView?.setAttribute('contentMode', iosContentMode);
imageView.setAttribute('contentMode', iosContentMode);

// Find the resources
final resources = documentData?.getElement('resources');
var launchImageResource = resources?.children.whereType<XmlElement>().firstWhere(
(element) => (element.name.qualified == 'image' &&
element.getAttribute('name') == 'LaunchImage'),
orElse: () => throw _LaunchScreenStoryboardModified(
"Not able to find 'LaunchImage' in LaunchScreen.storyboard. Image for splash screen not updated. Did you modify your default LaunchScreen.storyboard file?"));
var launchImageResource = resources?.children
.whereType<XmlElement>()
.firstWhere(
(element) => (element.name.qualified == 'image' &&
element.getAttribute('name') == 'LaunchImage'), orElse: () {
print('Not able to find "LaunchImage" in LaunchScreen.storyboard. Image '
'for splash screen not updated. Did you modify your default '
'LaunchScreen.storyboard file?');
exit(1);
});

resources?.children.whereType<XmlElement>().firstWhere(
(element) => (element.name.qualified == 'image' &&
Expand All @@ -195,13 +208,10 @@ void _updateLaunchScreenStoryboard(
XmlDocument.parse(_iOSLaunchBackgroundConstraints).rootElement.copy());

if (imagePath.isNotEmpty) {
if (!File(imagePath).existsSync()) {
throw _NoImageFileFoundException('The file $imagePath was not found.');
}

final image = decodeImage(File(imagePath).readAsBytesSync());
if (image == null) {
throw _NoImageFileFoundException(imagePath + ' could not be loaded.');
print(imagePath + ' could not be loaded.');
exit(1);
}
launchImageResource?.setAttribute('width', image.width.toString());
launchImageResource?.setAttribute('height', image.height.toString());
Expand Down Expand Up @@ -277,10 +287,10 @@ void _applyInfoPList({List<String>? plistFiles, required bool fullscreen}) {

plistFiles.forEach((plistFile) {
if (!File(plistFile).existsSync()) {
throw _CantFindInfoPlistFile(
'File $plistFile not found. If you renamed the file, make sure to '
'specify it in the info_plist_files section of your '
print('File $plistFile not found. If you renamed the file, make sure to'
' specify it in the info_plist_files section of your '
'flutter_native_splash configuration.');
exit(1);
}

print('[iOS] Updating $plistFile for status bar hidden/visible');
Expand Down
Loading

0 comments on commit 6c3d4f4

Please sign in to comment.