diff --git a/android/src/main/java/org/devio/rn/splashscreen/SplashScreen.java b/android/src/main/java/org/devio/rn/splashscreen/SplashScreen.java index d8ec6e5d..9c1e808e 100644 --- a/android/src/main/java/org/devio/rn/splashscreen/SplashScreen.java +++ b/android/src/main/java/org/devio/rn/splashscreen/SplashScreen.java @@ -32,8 +32,14 @@ public class SplashScreen { private static WeakReference mActivity; private static boolean isVideoActive = false; private static boolean isImageActive = false; + private static VideoView lastVideoView = null; + private static Runnable videoPauseRunnable = null; - public static void showVideo(Activity activity) { + public static void showVideo(final Activity activity) { + showVideo(activity, Arguments.createMap()); + } + + public static void showVideo(final Activity activity, final ReadableMap options) { if (activity == null) return; if (mSplashDialog != null) return; if (isImageActive || isVideoActive) return; @@ -81,11 +87,25 @@ public void run() { videoView.setVideoPath(videoPath); videoView.start(); + lastVideoView = videoView; + + int pauseAfterMs = options.hasKey("pauseAfterMs") ? options.getInt("pauseAfterMs") : 0; + if (pauseAfterMs > 0) { + videoPauseRunnable = new Runnable() { + @Override + public void run() { + if (lastVideoView != null) { + lastVideoView.pause(); + } + } + }; + videoView.postDelayed(videoPauseRunnable, pauseAfterMs); + } + if (!mSplashDialog.isShowing()) { mSplashDialog.show(); } - videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { @@ -97,8 +117,27 @@ public void onCompletion(MediaPlayer mp) { }); } + public static void removeVideoPauseOption(Activity activity) { + if (isImageActive) return; + if (lastVideoView == null || videoPauseRunnable == null) return; + + lastVideoView.removeCallbacks(videoPauseRunnable); + videoPauseRunnable = null; + } + + public static void resumeVideo(Activity activity) { + if (isImageActive) return; + if (lastVideoView == null) return; + removeVideoPauseOption(activity); + + lastVideoView.start(); + } + public static void hideVideo(Activity activity) { if (isImageActive) return; + + removeVideoPauseOption(activity); + lastVideoView = null; _hide(activity, Arguments.createMap()); } diff --git a/android/src/main/java/org/devio/rn/splashscreen/SplashScreenModule.java b/android/src/main/java/org/devio/rn/splashscreen/SplashScreenModule.java index 8b9ab455..6a25e817 100644 --- a/android/src/main/java/org/devio/rn/splashscreen/SplashScreenModule.java +++ b/android/src/main/java/org/devio/rn/splashscreen/SplashScreenModule.java @@ -56,9 +56,14 @@ public void hide(ReadableMap options) { SplashScreen.hide(getCurrentActivity(), options); } + @ReactMethod + public void showVideo(ReadableMap options) { + SplashScreen.showVideo(getCurrentActivity(), options); + } + @ReactMethod public void showVideo() { - SplashScreen.showVideo(getCurrentActivity()); + showVideo(Arguments.createMap()); } @ReactMethod @@ -70,4 +75,14 @@ public void hideVideo() { public void setBackgroundColor(String color) { SplashScreen.setBackgroundColor(getCurrentActivity(), color); } + + @ReactMethod + public void removeVideoPauseOption() { + SplashScreen.removeVideoPauseOption(getCurrentActivity()); + } + + @ReactMethod + public void resumeVideo() { + SplashScreen.resumeVideo(getCurrentActivity()); + } } diff --git a/index.android.js b/index.android.js index cbaca989..1ef7e26e 100644 --- a/index.android.js +++ b/index.android.js @@ -17,8 +17,10 @@ const Wrapper = { ...SplashScreen, show: (opts = {}) => SplashScreen.show(opts), hide: (opts = {}) => SplashScreen.hide(opts), - showVideo: () => SplashScreen.showVideo(), + showVideo: (opts = {}) => SplashScreen.showVideo(opts), hideVideo: () => SplashScreen.hideVideo(), + resumeVideo: () => SplashScreen.resumeVideo(), + removeVideoPauseOption: () => SplashScreen.removeVideoPauseOption(), } export default Wrapper diff --git a/index.ios.js b/index.ios.js index 74906924..2d7c19ad 100755 --- a/index.ios.js +++ b/index.ios.js @@ -18,8 +18,10 @@ const Wrapper = { // no opts supported show: () => SplashScreen.show(), hide: () => SplashScreen.hide(), - showVideo: () => SplashScreen.showVideo(), + showVideo: (opts) => SplashScreen.showVideo(opts), hideVideo: () => SplashScreen.hideVideo(), + resumeVideo: () => SplashScreen.resumeVideo(), + removeVideoPauseOption: () => SplashScreen.removeVideoPauseOption(), } export default Wrapper diff --git a/ios/RNSplashScreen.h b/ios/RNSplashScreen.h index 70953c71..8551b303 100644 --- a/ios/RNSplashScreen.h +++ b/ios/RNSplashScreen.h @@ -13,5 +13,8 @@ + (void)show; + (void)hide; + (void)showVideo; ++ (void)showVideo:(NSDictionary *)config; + (void)hideVideo; ++ (void)resumeVideo; ++ (void)removeVideoPauseOption; @end diff --git a/ios/RNSplashScreen.m b/ios/RNSplashScreen.m index cb2cb06e..c6452083 100644 --- a/ios/RNSplashScreen.m +++ b/ios/RNSplashScreen.m @@ -13,6 +13,8 @@ static bool showing = false; static bool showingVideo = false; +static AVPlayer *lastPlayer = nil; +static id videoPauseObserver = nil; @implementation RNSplashScreen - (dispatch_queue_t)methodQueue{ @@ -25,6 +27,10 @@ - (dispatch_queue_t)methodQueue{ NSString* RNSplashScreenOverlayName = @"splashscreenVideo"; + (void)showVideo { + [RNSplashScreen showVideo:(NSDictionary *)@{}]; +} + ++ (void)showVideo:(NSDictionary *)config { if (showingVideo || showing) return; NSString *videoPath=[[NSBundle mainBundle] pathForResource:@"splashscreen" ofType:@"mp4"]; @@ -35,10 +41,25 @@ + (void)showVideo { NSURL *videoURL = [NSURL fileURLWithPath:videoPath]; AVPlayer *player = [AVPlayer playerWithURL:videoURL]; - playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; + lastPlayer = player; + __weak AVPlayer *_player = player; + + NSNumber *pauseAfterMs = config[@"pauseAfterMs"]; + if (pauseAfterMs != nil) { + videoPauseObserver = [player addBoundaryTimeObserverForTimes: @[[NSValue valueWithCMTime:CMTimeMake([pauseAfterMs intValue], 1000)]] + queue:NULL // main queue + usingBlock:^() { + if (_player == nil) { + return; + } + _player.rate = 0; + [_player pause]; + }]; + } AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player]; playerLayer.frame = rootView.bounds; + playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; [playerLayer setName:RNSplashScreenOverlayName]; [rootView.layer addSublayer:playerLayer]; @@ -51,7 +72,9 @@ + (void)showVideo { } + (void) hideVideo { + if (showing) return; UIView *rootView = UIApplication.sharedApplication.keyWindow.subviews.lastObject; + [RNSplashScreen removeVideoPauseOption]; for (CALayer *layer in rootView.layer.sublayers) { if ([[layer name] isEqualToString:RNSplashScreenOverlayName]) { @@ -61,12 +84,30 @@ + (void) hideVideo { } } showingVideo = false; + lastPlayer = nil; } + (void) hideVideo:(AVPlayerItem*)playerItem { [self hideVideo]; } ++ (void)resumeVideo { + if (showing) return; + if (lastPlayer == nil) return; + [RNSplashScreen removeVideoPauseOption]; + + lastPlayer.rate = 1; + [lastPlayer play]; +} + ++ (void)removeVideoPauseOption { + if (showing) return; + if (videoPauseObserver == nil || lastPlayer == nil) return; + + [lastPlayer removeTimeObserver:videoPauseObserver]; + videoPauseObserver = nil; +} + + (void)show { if (showingVideo || showing) return; @@ -80,6 +121,7 @@ + (void)show { } + (void)hide { + if (showingVideo) return; // let's try to hide, even if showing == false, ...just in case UIImageView *imageView = (UIImageView *)[UIApplication.sharedApplication.keyWindow.subviews.lastObject viewWithTag:RNSplashScreenOverlayTag]; @@ -129,4 +171,12 @@ + (NSString *)launchImageNameForOrientation:(UIDeviceOrientation)orientation { [RNSplashScreen showVideo]; } +RCT_EXPORT_METHOD(resumeVideo) { + [RNSplashScreen resumeVideo]; +} + +RCT_EXPORT_METHOD(removeVideoPauseOption) { + [RNSplashScreen removeVideoPauseOption]; +} + @end