diff --git a/.gitignore b/.gitignore
index 4655c8a..9be145f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,55 +21,9 @@
#.vscode/
# Flutter/Dart/Pub related
+# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
+/pubspec.lock
**/doc/api/
.dart_tool/
-.flutter-plugins
-.flutter-plugins-dependencies
.packages
-.pub-cache/
-.pub/
build/
-pubspec.lock
-
-# Android related
-**/android/**/gradle-wrapper.jar
-**/android/.gradle
-**/android/captures/
-**/android/gradlew
-**/android/gradlew.bat
-**/android/local.properties
-**/android/**/GeneratedPluginRegistrant.java
-
-# iOS/XCode related
-**/ios/**/*.mode1v3
-**/ios/**/*.mode2v3
-**/ios/**/*.moved-aside
-**/ios/**/*.pbxuser
-**/ios/**/*.perspectivev3
-**/ios/**/*sync/
-**/ios/**/.sconsign.dblite
-**/ios/**/.tags*
-**/ios/**/.vagrant/
-**/ios/**/DerivedData/
-**/ios/**/Icon?
-**/ios/**/Pods/
-**/ios/**/.symlinks/
-**/ios/**/profile
-**/ios/**/xcuserdata
-**/ios/.generated/
-**/ios/Flutter/App.framework
-**/ios/Flutter/Flutter.framework
-**/ios/Flutter/Flutter.podspec
-**/ios/Flutter/Generated.xcconfig
-**/ios/Flutter/app.flx
-**/ios/Flutter/app.zip
-**/ios/Flutter/flutter_assets/
-**/ios/Flutter/flutter_export_environment.sh
-**/ios/ServiceDefinitions.json
-**/ios/Runner/GeneratedPluginRegistrant.*
-
-# Exceptions to above rules.
-!**/ios/**/default.mode1v3
-!**/ios/**/default.mode2v3
-!**/ios/**/default.pbxuser
-!**/ios/**/default.perspectivev3
diff --git a/.metadata b/.metadata
index 45789c7..af84dae 100644
--- a/.metadata
+++ b/.metadata
@@ -4,7 +4,7 @@
# This file should be version controlled and should not be manually edited.
version:
- revision: 20e59316b8b8474554b38493b8ca888794b0234a
+ revision: 77d935af4db863f6abd0b9c31c7e6df2a13de57b
channel: stable
project_type: package
diff --git a/.run/create.run.xml b/.run/create.run.xml
new file mode 100644
index 0000000..e8e74af
--- /dev/null
+++ b/.run/create.run.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.run/remove.run.xml b/.run/remove.run.xml
new file mode 100644
index 0000000..dd4d43a
--- /dev/null
+++ b/.run/remove.run.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5914fd2..d65ecee 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
+## [2.0.0] - (2022-Jan-29)
+* BREAKING CHANGE: Added `removeAfter` method which allows the native splash to remain until an initialization routine is complete. In order to use this method, the `flutter_native_splash` dependency must be moved from `dev_dependencies` to `dependencies`. Thanks [Ahmed](https://github.com/Ahmed-gubara) for the tip. Closes [#271](https://github.com/jonbhanson/flutter_native_splash/issues/271).
+
## [1.3.3] - (2022-Jan-01)
* Merged PR that adds branding. Thanks [Faiizii](https://github.com/Faiizii) for PR. Closes [#256](https://github.com/jonbhanson/flutter_native_splash/issues/256).
* Updated readme. Closes [#258](https://github.com/jonbhanson/flutter_native_splash/issues/258).
diff --git a/README.md b/README.md
index 516f302..d33263e 100644
--- a/README.md
+++ b/README.md
@@ -9,15 +9,19 @@ When your app is opened, there is a brief time while the native app loads Flutte
+# What's New
+
+You can now keep the splash screen up while your app initializes! No need for a secondary splash screen anymore. Just use the `removeAfter` method to remove the splash screen after your initialization is complete. See [example below](https://pub.dev/packages/flutter_native_splash#3-set-up-app-initialization-optional).
+
# Usage
Would you prefer a video tutorial instead? Check out Johannes Milke's tutorial.
-First, add `flutter_native_splash` as a dev dependency in your pubspec.yaml file. It belongs in `dev_dependencies` because it is a command line tool. Please disregard the instructions in the *Installing* tab that gives different instructions.
+First, add `flutter_native_splash` as a dependency in your pubspec.yaml file.
```yaml
-dev_dependencies:
- flutter_native_splash: ^1.3.3
+dependencies:
+ flutter_native_splash: ^2.0.0
```
Don't forget to `flutter pub get`.
@@ -59,8 +63,8 @@ flutter_native_splash:
# To position the branding image at the bottom of the screen you can use bottom, bottomRight,
# and bottomLeft. The default values is bottom if not specified or specified something else.
#
- # Make sure this content mode value should not be similar to android_gravity value and ios_content_mode
- # value.
+ # Make sure this content mode value should not be similar to android_gravity value and
+ # ios_content_mode value.
branding_mode: bottom
# The color_dark, background_image_dark, and image_dark are parameters that set the background
@@ -127,6 +131,24 @@ To specify the YAML file location just add --path with the command in the termin
flutter pub run flutter_native_splash:create --path=path/to/my/file.yaml
```
+## 3. Set up app initialization (optional)
+
+By default, the splash screen will be removed when Flutter has drawn the first frame. If you would like the splash screen to remain while your initializes, you can use the `removeAfter` method in the following manner:
+
+```dart
+void main() {
+ FlutterNativeSplash.removeAfter(initialization);
+ // runApp will run, but not be shown until initialization completes:
+ runApp(const MyApp());
+}
+
+void initialization() async {
+ // This is where you can initialize the resources needed by your app while
+ // the splash screen is displayed. After this function completes, the
+ // splash screen will be removed.
+}
+```
+
# Android 12 Support
Android 12 has a [new method](https://developer.android.com/about/versions/12/features/splash-screen) of adding splash screens, which consists of a window background, icon, and the icon background. Currently, this package supports setting the background color and the icon is taken from the launcher icon.
@@ -134,10 +156,6 @@ Android 12 has a [new method](https://developer.android.com/about/versions/12/fe
If you [enable Android 12 support](https://developer.android.com/about/versions/12/setup-sdk), the package will add a `styles.xml` in `values-v31` and `values-night-v31` resource folders, which will provide Android 12 support while maintaining the legacy splash screen for previous versions of Android.
NOTE: The splash screen may not appear when you launch the app from Android Studio. However, it should appear when you launch by clicking on the launch icon in Android.
-
-# Recommendations
-## Secondary splash screen:
-The native splash screen is displayed while the native app loads the Flutter framework. Once Flutter loads, there are probably still resources that need to be loaded before your app is ready. For this reason, you should consider implementing a secondary Flutter splash screen or placeholders that display while these resources load. The [example](https://github.com/jonbhanson/flutter_native_splash/blob/master/example/lib/main.dart) shows an implementation of a secondary splash screen.
# FAQs
## I got the error "A splash screen was provided to Flutter, but this is deprecated."
@@ -152,11 +170,8 @@ This message is not related to this package but is related to a [change](https:/
```
The solution is to remove the above code. Note that this will also remove the fade effect between the native splash screen and your app.
-## Can I change the duration of the splash screen?
-No, it is not possible to change the duration of the splash screen. The native splash screen is displayed while the native app loads the Flutter framework. Because the resources in your app cannot load while the native splash screen is displayed, the native splash screen must be as fast as possible. Note that delaying the user experience is a poor design decision.
-
## Are animations/lottie/GIF images supported?
-Not at this time. However, you may want to consider a secondary splash screen that supports animation. See the [secondary splash screen](#secondary-splash-screen) recommendation.
+Not at this time. PRs are always welcome!
## I got the error AAPT: error: style attribute 'android:attr/windowSplashScreenBackground' not found
This attribute is only found in Android 12, so if you are getting this error, it means your project is not fully set up for Android 12. Did you [update your app's build configuration](https://developer.android.com/about/versions/12/setup-sdk#config)?
@@ -166,7 +181,7 @@ This is caused by an [iOS splash caching bug](https://stackoverflow.com/question
## I see a white screen between splash screen and app
1. It may be caused by an [iOS splash caching bug](https://stackoverflow.com/questions/33002829/ios-keeping-old-launch-screen-and-app-icon-after-update), which can be solved by uninstalling your app, powering off your device, power back on, and then try reinstalling.
-2. It may be caused by the delay due to initialization in your app. To test this, make a test where your `main()` returns a `Container(color: Colors.black);`. If the white flash goes away, it will show that your content is not loading fast enough. You could solve this by creating a [secondary splash screen](https://pub.dev/packages/flutter_native_splash#secondary-splash-screen) or loading a barebones version of your app with placeholders, and then populate the placeholders as content loads.
+2. It may be caused by the delay due to initialization in your app. To solve this, put any initialization code in the `removeAfter` method.
# Notes
* If the splash screen was not updated correctly on iOS or if you experience a white screen before the splash screen, run `flutter clean` and recompile your app. If that does not solve the problem, delete your app, power down the device, power up the device, install and launch the app as per [this StackOverflow thread](https://stackoverflow.com/questions/33002829/ios-keeping-old-launch-screen-and-app-icon-after-update).
@@ -192,14 +207,6 @@ This is caused by an [iOS splash caching bug](https://stackoverflow.com/question
* Your splash image will be resized to `1x`, `2x`, `3x`, and `4x` sizes and placed in `web/splash/img`.
* The splash style sheet will be added to the app's `web/index.html`, as well as the HTML for the splash pictures.
-# Removing
-
-If you would like to restore Flutter's default white splash screen, run the following command in the terminal:
-
-```
-flutter pub run flutter_native_splash:remove
-```
-
# Acknowledgments
This package was originally created by [Henrique Arthur](https://github.com/henriquearthur) and it is currently maintained by [Jon Hanson](https://github.com/jonbhanson).
diff --git a/bin/create.dart b/bin/create.dart
index b54350a..a1c5903 100644
--- a/bin/create.dart
+++ b/bin/create.dart
@@ -1,10 +1,8 @@
import 'package:args/args.dart';
-import 'package:flutter_native_splash/flutter_native_splash.dart'
- as flutter_native_splash;
+import 'package:flutter_native_splash/cli_commands.dart';
void main(List args) {
var parser = ArgParser();
- parser.addOption('path',
- callback: (path) => {flutter_native_splash.createSplash(path: path)});
+ parser.addOption('path', callback: (path) => {createSplash(path: path)});
parser.parse(args);
}
diff --git a/bin/remove.dart b/bin/remove.dart
index 8b57b51..a1fe595 100644
--- a/bin/remove.dart
+++ b/bin/remove.dart
@@ -1,10 +1,8 @@
import 'package:args/args.dart';
-import 'package:flutter_native_splash/flutter_native_splash.dart'
- as flutter_native_splash;
+import 'package:flutter_native_splash/cli_commands.dart';
void main(List args) {
var parser = ArgParser();
- parser.addOption('path',
- callback: (path) => {flutter_native_splash.removeSplash(path: path)});
+ parser.addOption('path', callback: (path) => {removeSplash(path: path)});
parser.parse(args);
}
diff --git a/example/assets/1.5x/splash.png b/example/assets/1.5x/splash.png
deleted file mode 100644
index b09ba5d..0000000
Binary files a/example/assets/1.5x/splash.png and /dev/null differ
diff --git a/example/assets/1.5x/splash_dark.png b/example/assets/1.5x/splash_dark.png
deleted file mode 100644
index ba6d9ed..0000000
Binary files a/example/assets/1.5x/splash_dark.png and /dev/null differ
diff --git a/example/assets/2.0x/splash.png b/example/assets/2.0x/splash.png
deleted file mode 100644
index 93da431..0000000
Binary files a/example/assets/2.0x/splash.png and /dev/null differ
diff --git a/example/assets/2.0x/splash_dark.png b/example/assets/2.0x/splash_dark.png
deleted file mode 100644
index 350f6d4..0000000
Binary files a/example/assets/2.0x/splash_dark.png and /dev/null differ
diff --git a/example/assets/3.0x/splash.png b/example/assets/3.0x/splash.png
deleted file mode 100644
index 83bdafa..0000000
Binary files a/example/assets/3.0x/splash.png and /dev/null differ
diff --git a/example/assets/3.0x/splash_dark.png b/example/assets/3.0x/splash_dark.png
deleted file mode 100644
index bebe14e..0000000
Binary files a/example/assets/3.0x/splash_dark.png and /dev/null differ
diff --git a/example/assets/4.0x/splash.png b/example/assets/4.0x/splash.png
deleted file mode 100644
index 1b52a9b..0000000
Binary files a/example/assets/4.0x/splash.png and /dev/null differ
diff --git a/example/assets/4.0x/splash_dark.png b/example/assets/4.0x/splash_dark.png
deleted file mode 100644
index 95eb328..0000000
Binary files a/example/assets/4.0x/splash_dark.png and /dev/null differ
diff --git a/example/assets/splash.png b/example/assets/splash.png
deleted file mode 100644
index a918251..0000000
Binary files a/example/assets/splash.png and /dev/null differ
diff --git a/example/assets/splash_dark.png b/example/assets/splash_dark.png
deleted file mode 100644
index ce932e9..0000000
Binary files a/example/assets/splash_dark.png and /dev/null differ
diff --git a/example/lib/main.dart b/example/lib/main.dart
index 4b2cee9..b1ec0a3 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -1,45 +1,46 @@
import 'package:flutter/material.dart';
-import 'package:flutter/services.dart';
+import 'package:flutter_native_splash/flutter_native_splash.dart';
void main() {
- WidgetsFlutterBinding.ensureInitialized();
- SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
- overlays: [SystemUiOverlay.bottom, SystemUiOverlay.top]);
+ FlutterNativeSplash.removeAfter(initialization);
runApp(const MyApp());
}
+void initialization() async {
+ // This is where you can initialize the resources needed by your app while
+ // the splash screen is displayed. Remove the following example because
+ // delaying the user experience is a bad design practice!
+ // ignore_for_file: avoid_print
+ print('ready in 3...');
+ await Future.delayed(const Duration(seconds: 1));
+ print('ready in 2...');
+ await Future.delayed(const Duration(seconds: 1));
+ print('ready in 1...');
+ await Future.delayed(const Duration(seconds: 1));
+ print('go!');
+}
+
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
- return FutureBuilder(
- future: Init.instance.initialize(),
- builder: (context, AsyncSnapshot snapshot) {
- // Show splash screen while waiting for app resources to load:
- if (snapshot.connectionState == ConnectionState.waiting) {
- return const MaterialApp(home: Splash());
- } else {
- // Loading is done, return the app:
- return MaterialApp(
- title: 'Flutter Demo',
- theme: ThemeData(
- // This is the theme of your application.
- //
- // Try running your application with "flutter run". You'll see the
- // application has a blue toolbar. Then, without quitting the app, try
- // changing the primarySwatch below to Colors.green and then invoke
- // "hot reload" (press "r" in the console where you ran "flutter run",
- // or simply save your changes to "hot reload" in a Flutter IDE).
- // Notice that the counter didn't reset back to zero; the application
- // is not restarted.
- primarySwatch: Colors.blue,
- ),
- home: const MyHomePage(title: 'Flutter Demo Home Page'),
- );
- }
- },
+ return MaterialApp(
+ title: 'Flutter Demo',
+ theme: ThemeData(
+ // This is the theme of your application.
+ //
+ // Try running your application with "flutter run". You'll see the
+ // application has a blue toolbar. Then, without quitting the app, try
+ // changing the primarySwatch below to Colors.green and then invoke
+ // "hot reload" (press "r" in the console where you ran "flutter run",
+ // or simply save your changes to "hot reload" in a Flutter IDE).
+ // Notice that the counter didn't reset back to zero; the application
+ // is not restarted.
+ primarySwatch: Colors.blue,
+ ),
+ home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
@@ -128,33 +129,3 @@ class _MyHomePageState extends State {
);
}
}
-
-class Splash extends StatelessWidget {
- const Splash({Key? key}) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- bool lightMode =
- MediaQuery.of(context).platformBrightness == Brightness.light;
- return Scaffold(
- backgroundColor:
- lightMode ? const Color(0xffe1f5fe) : const Color(0xff042a49),
- body: Center(
- child: lightMode
- ? Image.asset('assets/splash.png')
- : Image.asset('assets/splash_dark.png')),
- );
- }
-}
-
-class Init {
- Init._();
- static final instance = Init._();
-
- Future initialize() async {
- // This is where you can initialize the resources needed by your app while
- // the splash screen is displayed. Remove the following example because
- // delaying the user experience is a bad design practice!
- await Future.delayed(const Duration(seconds: 3));
- }
-}
diff --git a/example/pubspec.lock b/example/pubspec.lock
index 75c26b0..3c986a9 100644
--- a/example/pubspec.lock
+++ b/example/pubspec.lock
@@ -7,7 +7,7 @@ packages:
name: archive
url: "https://pub.dartlang.org"
source: hosted
- version: "3.1.8"
+ version: "3.1.9"
args:
dependency: transitive
description:
@@ -91,12 +91,12 @@ packages:
source: hosted
version: "1.0.4"
flutter_native_splash:
- dependency: "direct dev"
+ dependency: "direct main"
description:
path: ".."
relative: true
source: path
- version: "1.3.3"
+ version: "2.0.0"
flutter_test:
dependency: "direct dev"
description: flutter
@@ -108,7 +108,7 @@ packages:
name: image
url: "https://pub.dartlang.org"
source: hosted
- version: "3.1.0"
+ version: "3.1.1"
lints:
dependency: transitive
description:
@@ -228,3 +228,4 @@ packages:
version: "3.1.0"
sdks:
dart: ">=2.15.1 <3.0.0"
+ flutter: ">=1.17.0"
diff --git a/example/pubspec.yaml b/example/pubspec.yaml
index eb15440..5eca2d2 100644
--- a/example/pubspec.yaml
+++ b/example/pubspec.yaml
@@ -30,16 +30,15 @@ dependencies:
flutter:
sdk: flutter
-
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.3
+ flutter_native_splash:
+ path: ..
dev_dependencies:
flutter_test:
sdk: flutter
- flutter_native_splash:
- path: ..
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
@@ -122,8 +121,8 @@ flutter_native_splash:
# To position the branding image at the bottom of the screen you can use bottom, bottomRight,
# and bottomLeft. The default values is bottom if not specified or specified something else.
#
- # Make sure this content mode value should not be similar to android_gravity value and ios_content_mode
- # value.
+ # Make sure this content mode value should not be similar to android_gravity value and
+ # ios_content_mode value.
branding_mode: bottom
# The color_dark, background_image_dark, and image_dark are parameters that set the background
diff --git a/lib/cli_commands.dart b/lib/cli_commands.dart
new file mode 100644
index 0000000..2e6cdbc
--- /dev/null
+++ b/lib/cli_commands.dart
@@ -0,0 +1,231 @@
+/// ## Flutter Native Splash
+///
+/// This is the main entry point for the Flutter Native Splash package.
+library flutter_native_splash;
+
+import 'package:image/image.dart';
+import 'package:meta/meta.dart';
+import 'package:path/path.dart' as p;
+import 'package:universal_io/io.dart';
+import 'package:xml/xml.dart';
+import 'package:yaml/yaml.dart';
+
+part 'android.dart';
+part 'constants.dart';
+part 'ios.dart';
+part 'templates.dart';
+part 'web.dart';
+
+/// Create splash screens for Android and iOS
+void createSplash({String? path}) {
+ var config = getConfig(configFile: path);
+ _checkConfig(config);
+ createSplashByConfig(config);
+}
+
+/// Create splash screens for Android and iOS based on a config argument
+void createSplashByConfig(Map config) {
+ var image = _checkImageExists(config: config, parameter: 'image');
+ var darkImage = _checkImageExists(config: config, parameter: 'image_dark');
+ var brandingImage = _checkImageExists(config: config, parameter: 'branding');
+ var brandingDarkImage =
+ _checkImageExists(config: config, parameter: 'branding_dark');
+ var color = parseColor(config['color']);
+ var darkColor = parseColor(config['color_dark']);
+ var backgroundImage =
+ _checkImageExists(config: config, parameter: 'background_image');
+ var darkBackgroundImage =
+ _checkImageExists(config: config, parameter: 'background_image_dark');
+ var plistFiles = config['info_plist_files'];
+ var gravity = (config['fill'] ?? false) ? 'fill' : 'center';
+ if (config['android_gravity'] != null) gravity = config['android_gravity'];
+
+ var brandingGravity = config['branding_mode'] ?? 'bottom';
+
+ bool fullscreen = config['fullscreen'] ?? false;
+ String iosContentMode = config['ios_content_mode'] ?? 'center';
+ final webImageMode = (config['web_image_mode'] ?? 'center');
+
+ if (!config.containsKey('android') || config['android']) {
+ if (Directory('android').existsSync()) {
+ _createAndroidSplash(
+ imagePath: image,
+ darkImagePath: darkImage,
+ brandingImagePath: brandingImage,
+ brandingDarkImagePath: brandingDarkImage,
+ backgroundImage: backgroundImage,
+ darkBackgroundImage: darkBackgroundImage,
+ color: color,
+ darkColor: darkColor,
+ gravity: gravity,
+ brandingGravity: brandingGravity,
+ fullscreen: fullscreen,
+ );
+ } else {
+ print('Android folder not found, skipping Android splash update...');
+ }
+ }
+
+ if (!config.containsKey('ios') || config['ios']) {
+ if (Directory('ios').existsSync()) {
+ _createiOSSplash(
+ imagePath: image,
+ darkImagePath: darkImage,
+ backgroundImage: backgroundImage,
+ darkBackgroundImage: darkBackgroundImage,
+ brandingImagePath: brandingImage,
+ brandingDarkImagePath: brandingDarkImage,
+ color: color,
+ darkColor: darkColor,
+ plistFiles: plistFiles,
+ iosContentMode: iosContentMode,
+ iosBrandingContentMode: brandingGravity,
+ fullscreen: fullscreen,
+ );
+ } else {
+ print('iOS folder not found, skipping iOS splash update...');
+ }
+ }
+
+ if (!config.containsKey('web') || config['web']) {
+ if (Directory('web').existsSync()) {
+ _createWebSplash(
+ imagePath: image,
+ darkImagePath: darkImage,
+ backgroundImage: backgroundImage,
+ darkBackgroundImage: darkBackgroundImage,
+ color: color,
+ darkColor: darkColor,
+ imageMode: webImageMode);
+ } else {
+ print('Web folder not found, skipping web splash update...');
+ }
+ }
+
+ print('');
+ print('Native splash complete. 👍');
+ print('Now go finish building something awesome! 💪 You rock! 🤘🤩');
+}
+
+/// Remove any splash screen by setting the default white splash
+void removeSplash({String? path}) {
+ print('Restoring Flutter\'s default native splash screen...');
+ var config = getConfig(configFile: path);
+
+ var removeConfig = {
+ 'color': '#ffffff',
+ 'color_dark': '#000000'
+ };
+ if (config.containsKey('android')) {
+ removeConfig['android'] = config['android'];
+ }
+ if (config.containsKey('ios')) {
+ removeConfig['ios'] = config['ios'];
+ }
+ if (config.containsKey('web')) {
+ removeConfig['web'] = config['web'];
+ }
+ createSplashByConfig(removeConfig);
+}
+
+String? _checkImageExists(
+ {required Map config, required String parameter}) {
+ String image = config[parameter] ?? '';
+ if (image.isNotEmpty && !File(image).existsSync()) {
+ print('The file "$image" set as the parameter "$parameter" was not found.');
+ exit(1);
+ }
+
+ if (image.isNotEmpty && p.extension(image).toLowerCase() != '.png') {
+ print('Unsupported file format: ' +
+ image +
+ ' Your image must be a PNG file.');
+ exit(1);
+ }
+ return image == '' ? null : image;
+}
+
+/// Get config from `pubspec.yaml` or `flutter_native_splash.yaml`
+Map getConfig({String? configFile}) {
+ // if `flutter_native_splash.yaml` exists use it as config file, otherwise use `pubspec.yaml`
+ String filePath;
+ if (configFile != null) {
+ if (File(configFile).existsSync()) {
+ filePath = configFile;
+ } else {
+ print('The config file `$configFile` was not found.');
+ exit(1);
+ }
+ } else if (File('flutter_native_splash.yaml').existsSync()) {
+ filePath = 'flutter_native_splash.yaml';
+ } else {
+ filePath = 'pubspec.yaml';
+ }
+
+ final Map yamlMap = loadYaml(File(filePath).readAsStringSync());
+
+ if (yamlMap['flutter_native_splash'] is! Map) {
+ throw Exception('Your `$filePath` file does not contain a '
+ '`flutter_native_splash` section.');
+ }
+
+ // yamlMap has the type YamlMap, which has several unwanted side effects
+ final config = {};
+ for (MapEntry entry
+ in yamlMap['flutter_native_splash'].entries) {
+ if (entry.value is YamlList) {
+ var list = [];
+ for (var value in (entry.value as YamlList)) {
+ if (value is String) {
+ list.add(value);
+ }
+ }
+ config[entry.key] = list;
+ } else {
+ config[entry.key] = entry.value;
+ }
+ }
+ return config;
+}
+
+void _checkConfig(Map config) {
+ if (config.containsKey('color') && config.containsKey('background_image')) {
+ print('Your `flutter_native_splash` section cannot not contain both a '
+ '`color` and `background_image`.');
+ exit(1);
+ }
+
+ if (!config.containsKey('color') && !config.containsKey('background_image')) {
+ print('Your `flutter_native_splash` section does not contain a `color` or '
+ '`background_image`.');
+ exit(1);
+ }
+
+ if (config.containsKey('color_dark') &&
+ config.containsKey('background_image_dark')) {
+ print('Your `flutter_native_splash` section cannot not contain both a '
+ '`color_dark` and `background_image_dark`.');
+ exit(1);
+ }
+
+ if (config.containsKey('image_dark') &&
+ !config.containsKey('color_dark') &&
+ !config.containsKey('background_image_dark')) {
+ print('Your `flutter_native_splash` section contains `image_dark` but '
+ 'does not contain a `color_dark` or a `background_image_dark`.');
+ exit(1);
+ }
+}
+
+@visibleForTesting
+String? parseColor(var color) {
+ if (color is int) color = color.toString().padLeft(6, '0');
+
+ if (color is String) {
+ color = color.replaceAll('#', '').replaceAll(' ', '');
+ if (color.length == 6) return color;
+ }
+ if (color == null) return null;
+
+ throw Exception('Invalid color value');
+}
diff --git a/lib/flutter_native_splash.dart b/lib/flutter_native_splash.dart
index 342fa10..80c16ea 100644
--- a/lib/flutter_native_splash.dart
+++ b/lib/flutter_native_splash.dart
@@ -1,231 +1,22 @@
-/// ## Flutter Native Splash
-///
-/// This is the main entry point for the Flutter Native Splash package.
library flutter_native_splash;
-import 'package:image/image.dart';
-import 'package:meta/meta.dart';
-import 'package:path/path.dart' as p;
-import 'package:universal_io/io.dart';
-import 'package:xml/xml.dart';
-import 'package:yaml/yaml.dart';
+import 'package:flutter/widgets.dart';
-part 'android.dart';
-part 'constants.dart';
-part 'ios.dart';
-part 'templates.dart';
-part 'web.dart';
+class FlutterNativeSplash {
+ static void removeAfter(Function initializeFunction) {
+ final binding = WidgetsFlutterBinding.ensureInitialized();
-/// Create splash screens for Android and iOS
-void createSplash({String? path}) {
- var config = getConfig(configFile: path);
- checkConfig(config);
- createSplashByConfig(config);
-}
-
-/// Create splash screens for Android and iOS based on a config argument
-void createSplashByConfig(Map config) {
- var image = checkImageExists(config: config, parameter: 'image');
- var darkImage = checkImageExists(config: config, parameter: 'image_dark');
- var brandingImage = checkImageExists(config: config, parameter: 'branding');
- var brandingDarkImage =
- checkImageExists(config: config, parameter: 'branding_dark');
- var color = parseColor(config['color']);
- var darkColor = parseColor(config['color_dark']);
- var backgroundImage =
- checkImageExists(config: config, parameter: 'background_image');
- var darkBackgroundImage =
- checkImageExists(config: config, parameter: 'background_image_dark');
- var plistFiles = config['info_plist_files'];
- var gravity = (config['fill'] ?? false) ? 'fill' : 'center';
- if (config['android_gravity'] != null) gravity = config['android_gravity'];
-
- var brandingGravity = config['branding_mode'] ?? 'bottom';
-
- bool fullscreen = config['fullscreen'] ?? false;
- String iosContentMode = config['ios_content_mode'] ?? 'center';
- final webImageMode = (config['web_image_mode'] ?? 'center');
-
- if (!config.containsKey('android') || config['android']) {
- if (Directory('android').existsSync()) {
- _createAndroidSplash(
- imagePath: image,
- darkImagePath: darkImage,
- brandingImagePath: brandingImage,
- brandingDarkImagePath: brandingDarkImage,
- backgroundImage: backgroundImage,
- darkBackgroundImage: darkBackgroundImage,
- color: color,
- darkColor: darkColor,
- gravity: gravity,
- brandingGravity: brandingGravity,
- fullscreen: fullscreen,
- );
- } else {
- print('Android folder not found, skipping Android splash update...');
- }
- }
-
- if (!config.containsKey('ios') || config['ios']) {
- if (Directory('ios').existsSync()) {
- _createiOSSplash(
- imagePath: image,
- darkImagePath: darkImage,
- backgroundImage: backgroundImage,
- darkBackgroundImage: darkBackgroundImage,
- brandingImagePath: brandingImage,
- brandingDarkImagePath: brandingDarkImage,
- color: color,
- darkColor: darkColor,
- plistFiles: plistFiles,
- iosContentMode: iosContentMode,
- iosBrandingContentMode: brandingGravity,
- fullscreen: fullscreen,
- );
- } else {
- print('iOS folder not found, skipping iOS splash update...');
- }
- }
-
- if (!config.containsKey('web') || config['web']) {
- if (Directory('web').existsSync()) {
- _createWebSplash(
- imagePath: image,
- darkImagePath: darkImage,
- backgroundImage: backgroundImage,
- darkBackgroundImage: darkBackgroundImage,
- color: color,
- darkColor: darkColor,
- imageMode: webImageMode);
- } else {
- print('Web folder not found, skipping web splash update...');
- }
- }
-
- print('');
- print('Native splash complete. 👍');
- print('Now go finish building something awesome! 💪 You rock! 🤘🤩');
-}
-
-/// Remove any splash screen by setting the default white splash
-void removeSplash({String? path}) {
- print('Restoring Flutter\'s default native splash screen...');
- var config = getConfig(configFile: path);
-
- var removeConfig = {
- 'color': '#ffffff',
- 'color_dark': '#000000'
- };
- if (config.containsKey('android')) {
- removeConfig['android'] = config['android'];
- }
- if (config.containsKey('ios')) {
- removeConfig['ios'] = config['ios'];
- }
- if (config.containsKey('web')) {
- removeConfig['web'] = config['web'];
- }
- createSplashByConfig(removeConfig);
-}
-
-String? checkImageExists(
- {required Map config, required String parameter}) {
- String image = config[parameter] ?? '';
- if (image.isNotEmpty && !File(image).existsSync()) {
- print('The file "$image" set as the parameter "$parameter" was not found.');
- exit(1);
- }
-
- if (image.isNotEmpty && p.extension(image).toLowerCase() != '.png') {
- print('Unsupported file format: ' +
- image +
- ' Your image must be a PNG file.');
- exit(1);
- }
- return image == '' ? null : image;
-}
-
-/// Get config from `pubspec.yaml` or `flutter_native_splash.yaml`
-Map getConfig({String? configFile}) {
- // if `flutter_native_splash.yaml` exists use it as config file, otherwise use `pubspec.yaml`
- String filePath;
- if (configFile != null) {
- if (File(configFile).existsSync()) {
- filePath = configFile;
- } else {
- print('The config file `$configFile` was not found.');
- exit(1);
- }
- } else if (File('flutter_native_splash.yaml').existsSync()) {
- filePath = 'flutter_native_splash.yaml';
- } else {
- filePath = 'pubspec.yaml';
- }
-
- final Map yamlMap = loadYaml(File(filePath).readAsStringSync());
-
- if (yamlMap['flutter_native_splash'] is! Map) {
- throw Exception('Your `$filePath` file does not contain a '
- '`flutter_native_splash` section.');
- }
-
- // yamlMap has the type YamlMap, which has several unwanted side effects
- final config = {};
- for (MapEntry entry
- in yamlMap['flutter_native_splash'].entries) {
- if (entry.value is YamlList) {
- var list = [];
- for (var value in (entry.value as YamlList)) {
- if (value is String) {
- list.add(value);
- }
+ // Prevents app from closing splash screen, app layout will be build but not displayed.
+ binding.deferFirstFrame();
+ binding.addPostFrameCallback((_) async {
+ BuildContext? context = binding.renderViewElement;
+ if (context != null) {
+ // Run any sync or awaited async function you want to wait for before showing app layout
+ await initializeFunction.call();
}
- config[entry.key] = list;
- } else {
- config[entry.key] = entry.value;
- }
- }
- return config;
-}
-void checkConfig(Map config) {
- if (config.containsKey('color') && config.containsKey('background_image')) {
- print('Your `flutter_native_splash` section cannot not contain both a '
- '`color` and `background_image`.');
- exit(1);
+ // Closes splash screen, and show the app layout.
+ binding.allowFirstFrame();
+ });
}
-
- if (!config.containsKey('color') && !config.containsKey('background_image')) {
- print('Your `flutter_native_splash` section does not contain a `color` or '
- '`background_image`.');
- exit(1);
- }
-
- if (config.containsKey('color_dark') &&
- config.containsKey('background_image_dark')) {
- print('Your `flutter_native_splash` section cannot not contain both a '
- '`color_dark` and `background_image_dark`.');
- exit(1);
- }
-
- if (config.containsKey('image_dark') &&
- !config.containsKey('color_dark') &&
- !config.containsKey('background_image_dark')) {
- print('Your `flutter_native_splash` section contains `image_dark` but '
- 'does not contain a `color_dark` or a `background_image_dark`.');
- exit(1);
- }
-}
-
-@visibleForTesting
-String? parseColor(var color) {
- if (color is int) color = color.toString().padLeft(6, '0');
-
- if (color is String) {
- color = color.replaceAll('#', '').replaceAll(' ', '');
- if (color.length == 6) return color;
- }
- if (color == null) return null;
-
- throw Exception('Invalid color value');
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 5382b84..3250874 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,20 +1,26 @@
name: flutter_native_splash
description: Customize Flutter's default white native splash screen with background color and splash image. Supports dark mode, full screen, and more.
-version: 1.3.3
+version: 2.0.0
homepage: https://github.com/jonbhanson/flutter_native_splash
environment:
sdk: ">=2.15.1 <3.0.0"
+ flutter: ">=1.17.0"
dependencies:
args: ^2.3.0
- image: ^3.1.0
+ image: ^3.1.1
meta: ^1.7.0
path: ^1.8.0
xml: ^5.3.1
yaml: ^3.1.0
universal_io: ^2.0.4
+ flutter:
+ sdk: flutter
dev_dependencies:
+ flutter_test:
+ sdk: flutter
flutter_lints: ^1.0.4
- test: any
+
+flutter:
diff --git a/test/flutter_native_splash_test.dart b/test/flutter_native_splash_test.dart
index 9b3a2bc..84cebe8 100644
--- a/test/flutter_native_splash_test.dart
+++ b/test/flutter_native_splash_test.dart
@@ -1,8 +1,8 @@
import 'dart:io';
-import 'package:flutter_native_splash/flutter_native_splash.dart';
+import 'package:flutter_native_splash/cli_commands.dart';
+import 'package:flutter_test/flutter_test.dart';
import 'package:path/path.dart' as p;
-import 'package:test/test.dart';
void main() {
test('Android splash images list is correct size', () {