Merge pull request #236 from thoblr/master
Added possibility to play video in background and when app is inactive.
This commit is contained in:
commit
24c24cd962
36
RCTVideo.m
36
RCTVideo.m
@ -40,6 +40,8 @@ static NSString *const playbackRate = @"rate";
|
|||||||
BOOL _paused;
|
BOOL _paused;
|
||||||
BOOL _repeat;
|
BOOL _repeat;
|
||||||
BOOL _playbackStalled;
|
BOOL _playbackStalled;
|
||||||
|
BOOL _playInBackground;
|
||||||
|
BOOL _playWhenInactive;
|
||||||
NSString * _resizeMode;
|
NSString * _resizeMode;
|
||||||
BOOL _fullscreenPlayerPresented;
|
BOOL _fullscreenPlayerPresented;
|
||||||
UIViewController * _presentingViewController;
|
UIViewController * _presentingViewController;
|
||||||
@ -61,12 +63,19 @@ static NSString *const playbackRate = @"rate";
|
|||||||
_progressUpdateInterval = 250;
|
_progressUpdateInterval = 250;
|
||||||
_controls = NO;
|
_controls = NO;
|
||||||
_playerBufferEmpty = YES;
|
_playerBufferEmpty = YES;
|
||||||
|
_playInBackground = false;
|
||||||
|
_playWhenInactive = false;
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
selector:@selector(applicationWillResignActive:)
|
selector:@selector(applicationWillResignActive:)
|
||||||
name:UIApplicationWillResignActiveNotification
|
name:UIApplicationWillResignActiveNotification
|
||||||
object:nil];
|
object:nil];
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(applicationDidEnterBackground:)
|
||||||
|
name:UIApplicationDidEnterBackgroundNotification
|
||||||
|
object:nil];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
selector:@selector(applicationWillEnterForeground:)
|
selector:@selector(applicationWillEnterForeground:)
|
||||||
name:UIApplicationWillEnterForegroundNotification
|
name:UIApplicationWillEnterForegroundNotification
|
||||||
@ -123,15 +132,26 @@ static NSString *const playbackRate = @"rate";
|
|||||||
|
|
||||||
- (void)applicationWillResignActive:(NSNotification *)notification
|
- (void)applicationWillResignActive:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
if (!_paused) {
|
if (_playInBackground || _playWhenInactive || _paused) return;
|
||||||
[_player pause];
|
|
||||||
[_player setRate:0.0];
|
[_player pause];
|
||||||
|
[_player setRate:0.0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationDidEnterBackground:(NSNotification *)notification
|
||||||
|
{
|
||||||
|
if (_playInBackground) {
|
||||||
|
// Needed to play sound in background. See https://developer.apple.com/library/ios/qa/qa1668/_index.html
|
||||||
|
[_playerLayer setPlayer:nil];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationWillEnterForeground:(NSNotification *)notification
|
- (void)applicationWillEnterForeground:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
[self applyModifiers];
|
[self applyModifiers];
|
||||||
|
if (_playInBackground) {
|
||||||
|
[_playerLayer setPlayer:_player];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Progress
|
#pragma mark - Progress
|
||||||
@ -403,6 +423,16 @@ static NSString *const playbackRate = @"rate";
|
|||||||
_resizeMode = mode;
|
_resizeMode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setPlayInBackground:(BOOL)playInBackground
|
||||||
|
{
|
||||||
|
_playInBackground = playInBackground;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setPlayWhenInactive:(BOOL)playWhenInactive
|
||||||
|
{
|
||||||
|
_playWhenInactive = playWhenInactive;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setPaused:(BOOL)paused
|
- (void)setPaused:(BOOL)paused
|
||||||
{
|
{
|
||||||
if (paused) {
|
if (paused) {
|
||||||
|
@ -48,6 +48,8 @@ RCT_EXPORT_VIEW_PROPERTY(paused, BOOL);
|
|||||||
RCT_EXPORT_VIEW_PROPERTY(muted, BOOL);
|
RCT_EXPORT_VIEW_PROPERTY(muted, BOOL);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(controls, BOOL);
|
RCT_EXPORT_VIEW_PROPERTY(controls, BOOL);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(volume, float);
|
RCT_EXPORT_VIEW_PROPERTY(volume, float);
|
||||||
|
RCT_EXPORT_VIEW_PROPERTY(playInBackground, BOOL);
|
||||||
|
RCT_EXPORT_VIEW_PROPERTY(playWhenInactive, BOOL);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(rate, float);
|
RCT_EXPORT_VIEW_PROPERTY(rate, float);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(seek, float);
|
RCT_EXPORT_VIEW_PROPERTY(seek, float);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(currentTime, float);
|
RCT_EXPORT_VIEW_PROPERTY(currentTime, float);
|
||||||
|
@ -71,6 +71,8 @@ Under `.addPackage(new MainReactPackage())`:
|
|||||||
paused={false} // Pauses playback entirely.
|
paused={false} // Pauses playback entirely.
|
||||||
resizeMode="cover" // Fill the whole screen at aspect ratio.
|
resizeMode="cover" // Fill the whole screen at aspect ratio.
|
||||||
repeat={true} // Repeat forever.
|
repeat={true} // Repeat forever.
|
||||||
|
playInBackground={false} // Audio continues to play when app entering background.
|
||||||
|
playWhenInactive={false} // [iOS] Video continues to play when control or notification center are shown.
|
||||||
onLoadStart={this.loadStart} // Callback when video starts to load
|
onLoadStart={this.loadStart} // Callback when video starts to load
|
||||||
onLoad={this.setDuration} // Callback when video loads
|
onLoad={this.setDuration} // Callback when video loads
|
||||||
onProgress={this.setTime} // Callback every ~250ms with currentTime
|
onProgress={this.setTime} // Callback every ~250ms with currentTime
|
||||||
@ -90,6 +92,10 @@ var styles = StyleSheet.create({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Play in background on iOS
|
||||||
|
|
||||||
|
To enable audio to play in background on iOS the audio session needs to be set to `AVAudioSessionCategoryPlayback`. See [Apple documentation][3].
|
||||||
|
|
||||||
## Static Methods
|
## Static Methods
|
||||||
|
|
||||||
`seek(seconds)`
|
`seek(seconds)`
|
||||||
@ -120,6 +126,7 @@ Seeks the video to the specified time (in seconds). Access using a ref to the co
|
|||||||
|
|
||||||
[1]: https://github.com/brentvatne/react-native-login/blob/56c47a5d1e23781e86e19b27e10427fd6391f666/App/Screens/UserInfoScreen.js#L32-L35
|
[1]: https://github.com/brentvatne/react-native-login/blob/56c47a5d1e23781e86e19b27e10427fd6391f666/App/Screens/UserInfoScreen.js#L32-L35
|
||||||
[2]: https://github.com/brentvatne/react-native-video/tree/master/Examples/VideoPlayer
|
[2]: https://github.com/brentvatne/react-native-video/tree/master/Examples/VideoPlayer
|
||||||
|
[3]: https://developer.apple.com/library/ios/qa/qa1668/_index.html
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
2
Video.js
2
Video.js
@ -222,6 +222,8 @@ Video.propTypes = {
|
|||||||
muted: PropTypes.bool,
|
muted: PropTypes.bool,
|
||||||
volume: PropTypes.number,
|
volume: PropTypes.number,
|
||||||
rate: PropTypes.number,
|
rate: PropTypes.number,
|
||||||
|
playInBackground: PropTypes.bool,
|
||||||
|
playWhenInactive: PropTypes.bool,
|
||||||
controls: PropTypes.bool,
|
controls: PropTypes.bool,
|
||||||
currentTime: PropTypes.number,
|
currentTime: PropTypes.number,
|
||||||
onLoadStart: PropTypes.func,
|
onLoadStart: PropTypes.func,
|
||||||
|
@ -9,13 +9,14 @@ import java.util.Map;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import com.facebook.react.bridge.Arguments;
|
import com.facebook.react.bridge.Arguments;
|
||||||
import com.facebook.react.bridge.WritableMap;
|
import com.facebook.react.bridge.WritableMap;
|
||||||
|
import com.facebook.react.bridge.LifecycleEventListener;
|
||||||
import com.facebook.react.uimanager.ThemedReactContext;
|
import com.facebook.react.uimanager.ThemedReactContext;
|
||||||
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||||
import com.yqritc.scalablevideoview.ScalableType;
|
import com.yqritc.scalablevideoview.ScalableType;
|
||||||
import com.yqritc.scalablevideoview.ScalableVideoView;
|
import com.yqritc.scalablevideoview.ScalableVideoView;
|
||||||
|
|
||||||
public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnPreparedListener, MediaPlayer
|
public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnPreparedListener, MediaPlayer
|
||||||
.OnErrorListener, MediaPlayer.OnBufferingUpdateListener, MediaPlayer.OnCompletionListener {
|
.OnErrorListener, MediaPlayer.OnBufferingUpdateListener, MediaPlayer.OnCompletionListener, LifecycleEventListener {
|
||||||
|
|
||||||
public enum Events {
|
public enum Events {
|
||||||
EVENT_LOAD_START("onVideoLoadStart"),
|
EVENT_LOAD_START("onVideoLoadStart"),
|
||||||
@ -73,6 +74,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
|
|||||||
private boolean mMuted = false;
|
private boolean mMuted = false;
|
||||||
private float mVolume = 1.0f;
|
private float mVolume = 1.0f;
|
||||||
private float mRate = 1.0f;
|
private float mRate = 1.0f;
|
||||||
|
private boolean mPlayInBackground = false;
|
||||||
|
|
||||||
private boolean mMediaPlayerValid = false; // True if mMediaPlayer is in prepared, started, or paused state.
|
private boolean mMediaPlayerValid = false; // True if mMediaPlayer is in prepared, started, or paused state.
|
||||||
private int mVideoDuration = 0;
|
private int mVideoDuration = 0;
|
||||||
@ -83,6 +85,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
|
|||||||
|
|
||||||
mThemedReactContext = themedReactContext;
|
mThemedReactContext = themedReactContext;
|
||||||
mEventEmitter = themedReactContext.getJSModule(RCTEventEmitter.class);
|
mEventEmitter = themedReactContext.getJSModule(RCTEventEmitter.class);
|
||||||
|
themedReactContext.addLifecycleEventListener(this);
|
||||||
|
|
||||||
initializeMediaPlayerIfNeeded();
|
initializeMediaPlayerIfNeeded();
|
||||||
setSurfaceTextureListener(this);
|
setSurfaceTextureListener(this);
|
||||||
@ -248,6 +251,10 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
|
|||||||
// setRateModifier(mRate);
|
// setRateModifier(mRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPlayInBackground(final boolean playInBackground) {
|
||||||
|
mPlayInBackground = playInBackground;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPrepared(MediaPlayer mp) {
|
public void onPrepared(MediaPlayer mp) {
|
||||||
mMediaPlayerValid = true;
|
mMediaPlayerValid = true;
|
||||||
@ -324,4 +331,19 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
|
|||||||
super.onAttachedToWindow();
|
super.onAttachedToWindow();
|
||||||
setSrc(mSrcUriString, mSrcType, mSrcIsNetwork, mSrcIsAsset);
|
setSrc(mSrcUriString, mSrcType, mSrcIsNetwork, mSrcIsAsset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onHostPause() {
|
||||||
|
if (mMediaPlayer != null && !mPlayInBackground) {
|
||||||
|
mMediaPlayer.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onHostResume() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onHostDestroy() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ public class ReactVideoViewManager extends SimpleViewManager<ReactVideoView> {
|
|||||||
public static final String PROP_VOLUME = "volume";
|
public static final String PROP_VOLUME = "volume";
|
||||||
public static final String PROP_SEEK = "seek";
|
public static final String PROP_SEEK = "seek";
|
||||||
public static final String PROP_RATE = "rate";
|
public static final String PROP_RATE = "rate";
|
||||||
|
public static final String PROP_PLAY_IN_BACKGROUND = "playInBackground";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@ -106,4 +107,9 @@ public class ReactVideoViewManager extends SimpleViewManager<ReactVideoView> {
|
|||||||
public void setRate(final ReactVideoView videoView, final float rate) {
|
public void setRate(final ReactVideoView videoView, final float rate) {
|
||||||
videoView.setRateModifier(rate);
|
videoView.setRateModifier(rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = PROP_PLAY_IN_BACKGROUND, defaultBoolean = false)
|
||||||
|
public void setPlayInBackground(final ReactVideoView videoView, final boolean playInBackground) {
|
||||||
|
videoView.setPlayInBackground(playInBackground);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user