I am new to swift and mobile development. I am writing a React Native app for tvOS and I need to implement the JWPlayerTVKit SDK in swift, as the react-native-jw-media-player does not support tvOS and I already have built the react native iOS version of it.
I have managed to have the video play, however it feels like the process of handling the player stops, while the video keeps playing. Basically, the player should have controls (play, pause, time scroll, etc.) which do not appear and the event jwplayerIsReady doesn't get fired.
I am assuming that the thread that interacts with the video player dies when I have added a 20s delay after the player is configured. For 20seconds the player controls are visible and the player events respond as expected. After 20seconds, the video keeps playing, with sound, but the controls become unavailable.
Here is my code:
bridging-header.h
#import "React/RCTBridgeModule.h"
#import "React/RCTViewManager.h"
JWPlayerViewManager.m
#import "React/RCTViewManager.h"
@interface RCT_EXTERN_MODULE(JWPlayerViewManager, RCTViewManager)
@end
JWPlayerViewManager.swift
import Foundation
import React
@objc(JWPlayerViewManager)
class JWPlayerViewManager: RCTViewManager {
override func view() -> UIView! {
let viewController = JWPlayerViewController()
let containerView = UIViewController()
containerView.addChild(viewController)
containerView.view.addSubview(viewController.view)
return viewController.view
}
override static func requiresMainQueueSetup() -> Bool {
return true
}
}
JWPlayerViewController.swift
import UIKit
import JWPlayerTVKit
class JWPlayerViewController: JWCinematicViewController {
override func viewDidLoad() {
super.viewDidLoad()
do {
JWPlayerKitLicense.setLicenseKey("123123123");
// Last, configure the player
player.configurePlayer(with: try setUpPlayer())
// I have managed to see the controls and the ready, visible events to fire after I have added this piece of code
// note: without self.player.play() the controls and the events do not work either
DispatchQueue.main.asyncAfter(deadline: .now() + 20) {
self.player.play()
print("play")
}
} catch {
// Handle builder failure
print(error)
}
}
/**
Set up the player with a simple configuration.
*/
private func setUpPlayer() throws -> JWPlayerConfiguration {
let videoSource1 = try JWVideoSourceBuilder()
.file(URL(string:"https://cdn.jwplayer.com/videos/123.mp4")!)
.label("270p")
.defaultVideo(false)
.build()
let videoSource2 = try JWVideoSourceBuilder()
.file(URL(string:"https://cdn.jwplayer.com/videos/456.mp4")!)
.label("720p")
.defaultVideo(true)
.build()
let mediaTrack = try JWCaptionTrackBuilder()
.file(URL(string:"https://cdn.jwplayer.com/tracks/123.srt")!)
.label("eng")
.defaultTrack(true)
.build()
// First, build a player item with the stream URL
let item = try JWPlayerItemBuilder()
.title("My Title")
.description("My description.")
.videoSources([videoSource1, videoSource2])
.mediaTracks([mediaTrack])
.build()
// Second, build a player configuration using the player item
return try JWPlayerConfigurationBuilder()
.playlist([item])
.autostart(false)
.build()
}
override func controlBarVisibilityChanged(isVisible: Bool) {
print("control bar")
print((isVisible) ? "visible" : "not visible")
}
override func jwplayer(_ player: JWPlayer, isVisible: Bool) {
print("isVisible")
}
// Player is ready
override func jwplayerIsReady(_ player: JWPlayer) {
super.jwplayerIsReady(player)
print("player is ready")
}
App.tsx
import { Dimensions, requireNativeComponent, View } from 'react-native';
const JWPlayerView = requireNativeComponent('JWPlayerView', null);
const App = () => {
return (
<View style={{ flex: 1 }}>
<JWPlayerView
style={{
flex: 1,
backgroundColor: '#ff0000',
height: Dimensions.get('window').width,
}}
/>
</View>
);
};
export default App;
Please any advice is very welcomed. I am coming from a web development background, so perhaps I am misunderstanding some principles here. Thank you very much for your help!