I am planning to use jwplayer in react-native. As of now there is no working jwplayer react-native plugin available on Github, so i am working on a Native module that will render jwplayer in react-native.
I am able to render video in react-native using a native module and also able to play video and able to receive play, pause other events in react-native.
But I have a problem with fullscreen mode(it is working properly in non-fullscreen mode) When I click JwPlayer fullscreen button then app screen goes to black and come back after video complete. During the blackout, I am able to hear audio but a video is not visible on mode.
Here is a code:
JavascriptBridgeJsFile
import React, { Component } from 'react'
import { requireNativeComponent } from 'react-native'
export default class JwPlayerWrapperView extends Component {
setNativeProps = nativeProps => {
if (this._root) {
this._root.setNativeProps(nativeProps);
}
}
render() {
return <JwPlayerWrapper
ref={e => (this._root = e)}
{...this.props}
onFullScreen={event =>
this.props.onFullScreen && this.props.onFullScreen(event.nativeEvent)
}
/>
}
}
const JwPlayerWrapper = requireNativeComponent('JwPlayerWrapper', JwPlayerWrapperView)
JwPlayerWrapper.h
#import <UIKit/UIKit.h>
#import <React/RCTBridge.h>
#import <JWPlayer_iOS_SDK/JWPlayerController.h>
#import <React/UIView+React.h>
@class RCTEventDispatcher;
@interface JwPlayerWrapper : UIView
// Define view properties here with @property
@property(nonatomic, strong) JWPlayerController *player;
@property(nonatomic, assign) NSString *playList;
@property (nonatomic, assign) NSString *exampleProp;
@property (nonatomic, copy) RCTDirectEventBlock onFullScreen;
// Initializing with the event dispatcher allows us to communicate with JS
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
@end
JwPlayerWrapper.m
#import <Foundation/Foundation.h>
#import "JwPlayerWrapper.h"
#import <JWPlayer_iOS_SDK/JWPlayerController.h>
// import RCTEventDispatcher
#if __has_include(<React/RCTEventDispatcher.h>)
#import <React/RCTEventDispatcher.h>
#elif __has_include("RCTEventDispatcher.h")
#import "RCTEventDispatcher.h"
#else
//#import "React/RCTEventDispatcher.h" // Required when used as a Pod in a Swift project
#endif
@interface JwPlayerWrapper () <JWPlayerDelegate>
@end
@implementation JwPlayerWrapper : UIView {
RCTEventDispatcher *_eventDispatcher;
JWConfig *config;
}
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
{
if ((self = [super init])) {
_eventDispatcher = eventDispatcher;
config = [[JWConfig alloc] init];
config.file = @"https://content.jwplatform.com/manifests/yp34SRmf.m3u8";
config.controls = YES; //default
config.playbackRateControls = TRUE;
config.audioSwitchingEnabled = TRUE;
config.stretching = TRUE;
config.displayDescription = @"This is sample video description";
config.displayTitle = @"Cycling is good for health";
self.player = [[JWPlayerController alloc] initWithConfig:config];
self.player.delegate = self;
}
return self;
}
-(void)layoutSubviews
{
[super layoutSubviews];
self.player.forceFullScreenOnLandscape = YES;
self.player.forceLandscapeOnFullScreen = YES;
self.player.view.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin|UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleWidth;
self.player.view.frame = self.bounds;
self.player.view.frame = CGRectMake(0, 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds));
[self setAutoresizesSubviews:TRUE];
[self addSubview:self.player.view];
}
- (void)onFullscreen:(JWEvent<JWFullscreenEvent> *)event
{
// NSLog(@"-=======================================ON FULLSCREEN x EVENT '%d'---------------------", event.fullscreen);
if(self.onFullScreen)
{
self.onFullScreen(@{@"fullScreen":@(event.fullscreen)});
}
}
@end
JwPlayerWrapperManager.h
// import RCTViewManager
#if __has_include(<React/RCTViewManager.h>)
#import <React/RCTViewManager.h>
#elif __has_include(“RCTViewManager.h”)
#import “RCTViewManager.h”
#else
#import “React/RCTViewManager.h” // Required when used as a Pod in a Swift project
#endif
// Subclass your view manager off the RCTViewManager
// http://facebook.github.io/react-native/docs/native-components-ios.html#ios-mapview-example
@interface JwPlayerWrapperManager : RCTViewManager
@end
JwPlayerWrapperManager.m
#import <Foundation/Foundation.h>
#import "JwPlayerWrapper.h"
#import "JwPlayerWrapperManager.h"
#import <React/RCTUIManager.h>
// import RCTBridge
#if __has_include(<React/RCTBridge.h>)
#import <React/RCTBridge.h>
#elif __has_include(“RCTBridge.h”)
#import “RCTBridge.h”
#else
#import “React/RCTBridge.h” // Required when used as a Pod in a Swift project
#endif
@implementation JwPlayerWrapperManager
@synthesize bridge = _bridge;
// Export a native module
// https://facebook.github.io/react-native/docs/native-modules-ios.html
RCT_EXPORT_MODULE();
// Return the native view that represents your React component
- (UIView *)view
{
return [[JwPlayerWrapper alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
}
- (dispatch_queue_t)methodQueue {
return _bridge.uiManager.methodQueue;
}
RCT_EXPORT_VIEW_PROPERTY(exampleProp, NSString)
RCT_EXPORT_VIEW_PROPERTY(onFullScreen, RCTDirectEventBlock);
// Export constants
// https://facebook.github.io/react-native/releases/next/docs/native-modules-ios.html#exporting-constants
- (NSDictionary *)constantsToExport
{
return @{
@"EXAMPLE": @"example"
};
}
@end
AppDelegate.m
#import "AppDelegate.h"
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSURL *jsCodeLocation;
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"JwPlayerDemo"
initialProperties:nil
launchOptions:launchOptions];
// rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
rootView.backgroundColor = [UIColor colorWithRed:0.00 green:0.00 blue:0.00 alpha:1.0];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
@end
app.js
import React, { Component } from 'react';
import { StyleSheet, View, Dimensions } from 'react-native';
import JwPlayerWrapperView from './JwPlayerWrapper/JwPlayerWrapperNativeView'
let {
width,
height
} = Dimensions.get("window");
const videoWidth = width
const videoHeight = width / (16 / 9)
export default class App extends Component {
state = {
widthX: videoWidth,
heightX: videoHeight,
fullScreen: false
}
onFullScreen = (event) => {
console.log('onFullScreen: ', event.fullScreen)
this.setState({ fullScreen: event.fullScreen })
if (event.fullScreen) {
this.setState({
heightX: width,
widthX: height,
fullScreen: true
})
} else {
this.setState({
heightX: videoHeight,
widthX: videoWidth,
fullScreen: false
})
}
}
render() {
const { heightX, widthX } = this.state
return (
<View style={styles.container}>
<JwPlayerWrapperView
ref={ref => (this.player = ref)}
style={{ height: heightX, width: widthX }}
onFullScreen={this.onFullScreen}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
}
});
When app in portrait mode and if you click a fullscreen button of player then it will blackout screen. I don't what things need to do to make is fullscreen I am not having any ios native development experience.
Version details
react-native:0.55.1
PODS: - JWPlayer-SDK (3.1.4)
Here is a video link which shows what is happening: LINK
Thanks in advance.
onFullscreen
why do you setheightX: width, widthX: height,
? – Velda