react-native-bootsplash 4.1.2 → 4.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -132,6 +132,17 @@ yarn react-native generate-bootsplash assets/bootsplash_logo_original.png \
132
132
  --flavor=main
133
133
  ```
134
134
 
135
+ #### Using an SVG
136
+
137
+ You might want to use SVG as input file. For that, you can install a CLI tool to convert your logo first:
138
+
139
+ ```bash
140
+ $ brew install librsvg # available on macOS
141
+ $ rsvg-convert -w 3000 bootsplash_logo.svg bootsplash_logo.png # create a large PNG with generous leeway for 4x Android xxxhdpi devices
142
+ $ react-native generate-bootsplash bootsplash_logo.png
143
+ $ rm bootsplash_logo.png # optionally, clean up the PNG
144
+ ```
145
+
135
146
  ![](https://raw.githubusercontent.com/zoontek/react-native-bootsplash/master/docs/cli_tool.png?raw=true)
136
147
 
137
148
  This tool relies on the naming conventions that are used in the `/example` project and will therefore create the following files:
@@ -316,8 +327,6 @@ RNBootSplash.hide(); // immediate
316
327
  RNBootSplash.hide({ fade: true }); // fade
317
328
  ```
318
329
 
319
- ---
320
-
321
330
  ### getVisibilityStatus()
322
331
 
323
332
  #### Method type
@@ -360,7 +369,25 @@ function App() {
360
369
 
361
370
  **🤙 A more complex example is available in the [`/example` folder](example).**
362
371
 
363
- ### Testing with Jest
372
+ ## Using React Navigation
373
+
374
+ If you are using React Navigation, you can hide the splash screen once the navigation container and all children have finished mounting by using the `onReady` function.
375
+
376
+ ```js
377
+ import React from "react";
378
+ import { NavigationContainer } from "@react-navigation/native";
379
+ import RNBootSplash from "react-native-bootsplash";
380
+
381
+ function App() {
382
+ return (
383
+ <NavigationContainer onReady={() => RNBootSplash.hide()}>
384
+ {/* content */}
385
+ </NavigationContainer>
386
+ );
387
+ }
388
+ ```
389
+
390
+ ## Testing with Jest
364
391
 
365
392
  Testing code which uses this library requires some setup since we need to mock the native methods.
366
393
 
@@ -383,24 +410,6 @@ After that, we need to add the setup file in the jest config. You can add it und
383
410
  }
384
411
  ```
385
412
 
386
- ### Using React Navigation
387
-
388
- If you are using React Navigation, you can hide the splash screen once the navigation container and all children have finished mounting by using the `onReady` function.
389
-
390
- ```js
391
- import React from "react";
392
- import { NavigationContainer } from "@react-navigation/native";
393
- import RNBootSplash from "react-native-bootsplash";
394
-
395
- function App() {
396
- return (
397
- <NavigationContainer onReady={() => RNBootSplash.hide()}>
398
- {/* content */}
399
- </NavigationContainer>
400
- );
401
- }
402
- ```
403
-
404
413
  ## 🕵️‍♂️ Comparison with [react-native-splash-screen](https://github.com/crazycodeboy/react-native-splash-screen)
405
414
 
406
415
  - If `react-native-splash-screen` encourages you to display an image over your application, `react-native-bootsplash` way-to-go is to design your launch screen using platforms tools.
@@ -12,7 +12,6 @@ import androidx.core.splashscreen.SplashScreen;
12
12
  import androidx.core.splashscreen.SplashScreenViewProvider;
13
13
 
14
14
  import com.facebook.common.logging.FLog;
15
- import com.facebook.react.bridge.LifecycleEventListener;
16
15
  import com.facebook.react.bridge.Promise;
17
16
  import com.facebook.react.bridge.ReactApplicationContext;
18
17
  import com.facebook.react.bridge.ReactContextBaseJavaModule;
@@ -25,7 +24,7 @@ import java.util.Timer;
25
24
  import java.util.TimerTask;
26
25
 
27
26
  @ReactModule(name = RNBootSplashModule.NAME)
28
- public class RNBootSplashModule extends ReactContextBaseJavaModule implements LifecycleEventListener {
27
+ public class RNBootSplashModule extends ReactContextBaseJavaModule {
29
28
 
30
29
  public static final String NAME = "RNBootSplash";
31
30
  private static final int ANIMATION_DURATION = 220;
@@ -39,15 +38,13 @@ public class RNBootSplashModule extends ReactContextBaseJavaModule implements Li
39
38
  @Nullable
40
39
  private static SplashScreen mSplashScreen = null;
41
40
 
42
- private static final RNBootSplashQueue<RNBootSplashTask> mTaskQueue = new RNBootSplashQueue<>();
41
+ private static final RNBootSplashQueue<Promise> mPromiseQueue = new RNBootSplashQueue<>();
43
42
  private static Status mStatus = Status.HIDDEN;
44
- private static boolean mIsAppInForeground = true;
45
43
  private static boolean mShouldFade = false;
46
44
  private static boolean mShouldKeepOnScreen = true;
47
45
 
48
46
  public RNBootSplashModule(ReactApplicationContext reactContext) {
49
47
  super(reactContext);
50
- reactContext.addLifecycleEventListener(this);
51
48
  }
52
49
 
53
50
  @Override
@@ -96,95 +93,66 @@ public class RNBootSplashModule extends ReactContextBaseJavaModule implements Li
96
93
  });
97
94
  }
98
95
 
99
- @Override
100
- public void onHostDestroy() {
101
- mIsAppInForeground = false;
102
- }
103
-
104
- @Override
105
- public void onHostPause() {
106
- mIsAppInForeground = false;
107
- }
108
-
109
- @Override
110
- public void onHostResume() {
111
- mIsAppInForeground = true;
112
- shiftNextTask();
113
- }
96
+ private void clearPromiseQueue() {
97
+ while (!mPromiseQueue.isEmpty()) {
98
+ Promise promise = mPromiseQueue.shift();
114
99
 
115
- private void shiftNextTask() {
116
- if (mStatus != Status.TRANSITIONING && mIsAppInForeground) {
117
- RNBootSplashTask task = mTaskQueue.shift();
118
-
119
- if (task != null) {
120
- hideWithTask(task);
121
- }
100
+ if (promise != null)
101
+ promise.resolve(true);
122
102
  }
123
103
  }
124
104
 
125
- private void waitAndRetry() {
126
- final Timer timer = new Timer();
127
-
128
- timer.schedule(new TimerTask() {
129
- @Override
130
- public void run() {
131
- shiftNextTask();
132
- timer.cancel();
133
- }
134
- }, 250);
135
- }
136
-
137
- private void hideWithTask(final RNBootSplashTask task) {
138
- final Activity activity = getReactApplicationContext().getCurrentActivity();
139
- final boolean fade = task.getFade();
140
- final Promise promise = task.getPromise();
141
-
105
+ private void hideAndResolveAll(final boolean fade) {
142
106
  if (mSplashScreen == null || mStatus == Status.HIDDEN) {
143
- promise.resolve(true);
144
- shiftNextTask();
107
+ clearPromiseQueue();
145
108
  return;
146
109
  }
147
110
 
148
111
  UiThreadUtil.runOnUiThread(new Runnable() {
149
112
  @Override
150
113
  public void run() {
114
+ final Activity activity = getReactApplicationContext().getCurrentActivity();
115
+
151
116
  if (activity == null || activity.isFinishing()) {
152
- waitAndRetry(); // Wait for activity to be ready
153
- return;
154
- }
117
+ // Wait for activity to be ready
118
+ final Timer timer = new Timer();
155
119
 
156
- if (fade) {
157
- mStatus = Status.TRANSITIONING;
158
- }
120
+ timer.schedule(new TimerTask() {
121
+ @Override
122
+ public void run() {
123
+ hideAndResolveAll(fade);
124
+ timer.cancel();
125
+ }
126
+ }, 250);
127
+ } else {
128
+ if (fade) {
129
+ mStatus = Status.TRANSITIONING;
130
+ }
159
131
 
160
- mShouldFade = fade;
161
- mShouldKeepOnScreen = false;
132
+ mShouldFade = fade;
133
+ mShouldKeepOnScreen = false;
162
134
 
163
- final Timer timer = new Timer();
135
+ final Timer timer = new Timer();
164
136
 
165
- // We cannot rely on setOnExitAnimationListener
166
- // See https://issuetracker.google.com/issues/197906327
167
- timer.schedule(new TimerTask() {
168
- @Override
169
- public void run() {
170
- mStatus = Status.HIDDEN;
171
- timer.cancel();
172
- promise.resolve(true);
173
- shiftNextTask();
174
- }
175
- }, ANIMATION_DURATION);
137
+ // We cannot rely on setOnExitAnimationListener
138
+ // See https://issuetracker.google.com/issues/197906327
139
+ timer.schedule(new TimerTask() {
140
+ @Override
141
+ public void run() {
142
+ mStatus = Status.HIDDEN;
143
+ timer.cancel();
144
+ clearPromiseQueue();
145
+ }
146
+ }, ANIMATION_DURATION);
147
+ }
176
148
  }
177
149
  });
178
150
  }
179
151
 
180
152
  @ReactMethod
181
153
  public void hide(final boolean fade, final Promise promise) {
182
- if (mSplashScreen == null || mStatus == Status.HIDDEN) {
183
- promise.resolve(true);
184
- } else {
185
- mTaskQueue.push(new RNBootSplashTask(fade, promise));
186
- shiftNextTask();
187
- }
154
+ mPromiseQueue.push(promise);
155
+ hideAndResolveAll(fade);
188
156
  }
189
157
 
190
158
  @ReactMethod
@@ -1,16 +1,6 @@
1
1
  #import <React/RCTBridgeModule.h>
2
2
  #import <React/RCTRootView.h>
3
3
 
4
- @interface RNBootSplashTask : NSObject
5
-
6
- @property (nonatomic, readonly) BOOL fade;
7
- @property (nonatomic, readonly, strong) RCTPromiseResolveBlock _Nonnull resolve;
8
-
9
- - (instancetype _Nonnull)initWithFade:(BOOL)fade
10
- resolver:(RCTPromiseResolveBlock _Nonnull)resolve;
11
-
12
- @end
13
-
14
4
  @interface RNBootSplash : NSObject <RCTBridgeModule>
15
5
 
16
6
  + (void)initWithStoryboard:(NSString * _Nonnull)storyboardName
@@ -3,24 +3,9 @@
3
3
  #import <React/RCTBridge.h>
4
4
  #import <React/RCTUtils.h>
5
5
 
6
- static NSMutableArray<RNBootSplashTask *> *_taskQueue = nil;
6
+ static NSMutableArray<RCTPromiseResolveBlock> *_resolverQueue = nil;
7
7
  static RCTRootView *_rootView = nil;
8
8
  static bool _isTransitioning = false;
9
- static bool _shouldPreventInit = false;
10
-
11
- @implementation RNBootSplashTask
12
-
13
- - (instancetype)initWithFade:(BOOL)fade
14
- resolver:(RCTPromiseResolveBlock _Nonnull)resolve {
15
- if (self = [super init]) {
16
- _fade = fade;
17
- _resolve = resolve;
18
- }
19
-
20
- return self;
21
- }
22
-
23
- @end
24
9
 
25
10
  @implementation RNBootSplash
26
11
 
@@ -48,13 +33,13 @@ RCT_EXPORT_MODULE();
48
33
  UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle:nil];
49
34
  UIView *loadingView = [[storyboard instantiateInitialViewController] view];
50
35
 
51
- if (_shouldPreventInit)
52
- return;
36
+ if (_resolverQueue != nil)
37
+ return; // hide has already been called, abort init
53
38
 
54
39
  [_rootView setLoadingView:loadingView];
55
40
 
56
41
  [[NSNotificationCenter defaultCenter] addObserver:self
57
- selector:@selector(onJavaScriptDidLoad:)
42
+ selector:@selector(onJavaScriptDidLoad)
58
43
  name:RCTJavaScriptDidLoadNotification
59
44
  object:nil];
60
45
 
@@ -62,21 +47,10 @@ RCT_EXPORT_MODULE();
62
47
  selector:@selector(onJavaScriptDidFailToLoad)
63
48
  name:RCTJavaScriptDidFailToLoadNotification
64
49
  object:nil];
65
-
66
- [[NSNotificationCenter defaultCenter] addObserver:self
67
- selector:@selector(shiftNextTask)
68
- name:UIApplicationDidBecomeActiveNotification
69
- object:nil];
70
50
  }
71
51
 
72
- + (void)onJavaScriptDidLoad:(NSNotification *)notification {
73
- [[NSNotificationCenter defaultCenter] removeObserver:self
74
- name:RCTJavaScriptDidLoadNotification
75
- object:nil];
76
-
77
- [[NSNotificationCenter defaultCenter] removeObserver:self
78
- name:RCTJavaScriptDidFailToLoadNotification
79
- object:nil];
52
+ + (void)onJavaScriptDidLoad {
53
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
80
54
  }
81
55
 
82
56
  + (void)onJavaScriptDidFailToLoad {
@@ -91,39 +65,36 @@ RCT_EXPORT_MODULE();
91
65
  + (void)removeLoadingView {
92
66
  if (![self isHidden]) {
93
67
  _rootView.loadingView.hidden = YES;
68
+
94
69
  [_rootView.loadingView removeFromSuperview];
95
70
  _rootView.loadingView = nil;
96
71
  }
97
72
  }
98
73
 
99
- + (void)ensureTaskQueue {
100
- if (_taskQueue == nil)
101
- _taskQueue = [[NSMutableArray alloc] init];
102
- }
103
-
104
- + (void)shiftNextTask {
105
- [self ensureTaskQueue];
74
+ - (void)clearResolverQueue {
75
+ while ([_resolverQueue count] > 0) {
76
+ RCTPromiseResolveBlock resolve = [_resolverQueue objectAtIndex:0];
77
+ [_resolverQueue removeObjectAtIndex:0];
106
78
 
107
- if ([_taskQueue count] > 0 &&
108
- !_isTransitioning &&
109
- [[UIApplication sharedApplication] applicationState] != UIApplicationStateBackground) {
110
- RNBootSplashTask *task = [_taskQueue objectAtIndex:0];
111
- [_taskQueue removeObjectAtIndex:0];
112
-
113
- [self hideWithTask:task];
79
+ resolve(@(true));
114
80
  }
115
81
  }
116
82
 
117
- + (void)hideWithTask:(RNBootSplashTask *)task {
118
- if ([self isHidden]) {
119
- task.resolve(@(true));
120
- return [self shiftNextTask];
121
- }
83
+ RCT_REMAP_METHOD(hide,
84
+ hideWithFade:(BOOL)fade
85
+ resolver:(RCTPromiseResolveBlock)resolve
86
+ rejecter:(RCTPromiseRejectBlock)reject) {
87
+ if (_resolverQueue == nil)
88
+ _resolverQueue = [[NSMutableArray alloc] init];
89
+
90
+ [_resolverQueue addObject:resolve];
122
91
 
123
- if (!task.fade) {
124
- [self removeLoadingView];
125
- task.resolve(@(true));
126
- return [self shiftNextTask];
92
+ if ([RNBootSplash isHidden] || RCTRunningInAppExtension())
93
+ return [self clearResolverQueue];
94
+
95
+ if (!fade) {
96
+ [RNBootSplash removeLoadingView];
97
+ return [self clearResolverQueue];
127
98
  }
128
99
 
129
100
  dispatch_async(dispatch_get_main_queue(), ^{
@@ -139,31 +110,13 @@ RCT_EXPORT_MODULE();
139
110
  [_rootView.loadingView removeFromSuperview];
140
111
  _rootView.loadingView = nil;
141
112
 
142
- task.resolve(@(true));
143
113
  _isTransitioning = false;
144
114
 
145
- return [self shiftNextTask];
115
+ return [self clearResolverQueue];
146
116
  }];
147
117
  });
148
118
  }
149
119
 
150
- RCT_REMAP_METHOD(hide,
151
- hideWithFade:(BOOL)fade
152
- resolver:(RCTPromiseResolveBlock)resolve
153
- rejecter:(RCTPromiseRejectBlock)reject) {
154
- _shouldPreventInit = true;
155
-
156
- if ([RNBootSplash isHidden] || RCTRunningInAppExtension())
157
- return resolve(@(true));
158
-
159
- RNBootSplashTask *task = [[RNBootSplashTask alloc] initWithFade:fade
160
- resolver:resolve];
161
-
162
- [RNBootSplash ensureTaskQueue];
163
- [_taskQueue addObject:task];
164
- [RNBootSplash shiftNextTask];
165
- }
166
-
167
120
  RCT_REMAP_METHOD(getVisibilityStatus,
168
121
  getVisibilityStatusWithResolver:(RCTPromiseResolveBlock)resolve
169
122
  rejecter:(RCTPromiseRejectBlock)reject) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-bootsplash",
3
- "version": "4.1.2",
3
+ "version": "4.1.3",
4
4
  "license": "MIT",
5
5
  "description": "Display a bootsplash on your app starts. Hide it when you want.",
6
6
  "author": "Mathieu Acthernoene <zoontek@gmail.com>",
@@ -1,25 +0,0 @@
1
- package com.zoontek.rnbootsplash;
2
-
3
- import androidx.annotation.NonNull;
4
-
5
- import com.facebook.react.bridge.Promise;
6
-
7
- public class RNBootSplashTask {
8
-
9
- private final boolean mFade;
10
- @NonNull private final Promise mPromise;
11
-
12
- public RNBootSplashTask(final boolean fade, @NonNull final Promise promise) {
13
- mFade = fade;
14
- mPromise = promise;
15
- }
16
-
17
- public boolean getFade() {
18
- return mFade;
19
- }
20
-
21
- @NonNull
22
- public Promise getPromise() {
23
- return mPromise;
24
- }
25
- }