Issue
I've been trying to figure out a way to execute a function when the user performs a magnification gesture to enter a YouTube video into full screen. Ive tried a few different approaches to enter full screen and none have worked.
Here is what I've tried:
webView.evaluateJavaScript("document.querySelector('.iframe-container iframe').requestFullscreen()") { object, error in
print(error?.localizedDescription ?? "")
}
webView.evaluateJavaScript("document.getElementById('player').contentDocument.getElementsByClassName('video-stream')[0].webkitEnterFullScreen()") { object, error in
print(error?.localizedDescription ?? "")
}
And here is my html:
private func loadInitialContent(web: WKWebView) {
let embedHTML = """
<style>
body {
margin: 0;
background-color: black;
}
.iframe-container iframe {
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>
<div class="iframe-container">
<div id="player"></div>
</div>
<script>
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
var isPlaying = false;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
width: '100%',
videoId: 'es5Ct9flpIg',
playerVars: { 'playsinline': 1, 'controls': 0},
events: {
'onStateChange': function(event) {
if (event.data === YT.PlayerState.ENDED) {
player.seekTo(0);
player.playVideo();
}
}
}
});
}
</script>
"""
web.scrollView.isScrollEnabled = false
web.loadHTMLString(embedHTML, baseURL: nil)
}
Solution
In order to programmatically control YouTube playback and handle full screen mode, I would recommend utilizing YouTube's Iframe API which provides a series of events and functions to control the YouTube player. Given that you have already integrated the YouTube Iframe API in your HTML, you can use the player
object to control the video playback and other settings.
Note that JavaScript does not have the ability to force a full-screen mode without a user gesture due to security and usability issues. Browsers restrict this to maintain a user's control over the browsing experience. (See Element: requestFullscreen()
method).
However, what you can do is ensure that the YouTube player enters full-screen mode when a user clicks on the full-screen button in the YouTube player controls. For this, you should update your playerVars
in the YT.Player
initialization to allow controls and remove the 'playsinline' parameter or set it to 0, like so:
playerVars: { 'playsinline': 0, 'controls': 1 }
By setting 'playsinline': 0
, you should see the video enter full-screen mode when played on iOS devices.
If you want to perform an action when the user changes the video to full-screen mode, you may listen to onFullscreenChange
event, but this needs to be supported by the browser and may not work on all browsers.
While you can set up your YouTube iframe to facilitate entering full-screen mode more naturally, triggering full screen programmatically without a direct user action seems to remain restricted as of now.
This action to enter full screen will be the result of a magnification gesture. I don't want to use YouTubes fullscreen button. Is there another way to override that button and instead use a magnification gesture that causes a function in the embed HTML to execute?
I tried keeping the '
playsinline: 1
', then when the user executes the magnification gesture, swift executeswebView.evaluateJavaScript("changePlayInline()", completionHandler: nil)
. ThechangePlayInline()
function calls thisplayer.getOptions().playsinline = 0;
But this doesn't work.
I think changing the playsinline
parameter dynamically after the player has been created does not work because it is a setting that is defined upon the player's initialization and cannot be updated dynamically.
To achieve entering full screen through a magnification gesture, you would need to create a custom gesture recognizer in Swift which, upon recognizing a magnification gesture, triggers a JavaScript function to toggle the fullscreen mode of the YouTube video player.
One potential solution could involve reloading the player with the updated playsinline
parameter when the magnification gesture is detected:
- Create a custom gesture recognizer in your Swift code to detect the magnification gesture.
- Once the magnification gesture is detected, call a JavaScript function using
webView.evaluateJavaScript
. - In the JavaScript function, reload the YouTube player with the
playsinline
parameter set to0
to enable fullscreen mode.
let magnificationGesture = UIPinchGestureRecognizer(target: self, action: #selector(didMagnify(_:)))
webView.addGestureRecognizer(magnificationGesture)
@objc func didMagnify(_ gesture: UIPinchGestureRecognizer) {
if gesture.state == .ended {
webView.evaluateJavaScript("enterFullscreenMode()", completionHandler: nil)
}
}
In your HTML/JavaScript:
function enterFullscreenMode() {
player.destroy(); // Destroy the current player instance
player = new YT.Player('player', {
width: '100%',
videoId: 'es5Ct9flpIg',
playerVars: { 'playsinline': 0, 'controls': 0},
events: {
'onStateChange': function(event) {
if (event.data === YT.PlayerState.ENDED) {
player.seekTo(0);
player.playVideo();
}
}
}
});
}
That would destroy the existing player and creates a new one with the updated playsinline
parameter, effectively entering fullscreen mode.
But... this would result in the video reloading, and potentially creating a non-seamless experience for the user. It is a limitation imposed by the inability to change the playsinline
parameter dynamically.
This surely works, but as you said reloads the video first. You mentioned in your answer using the
requestFullscreen()
method.Would this be a possible approach to enter full screen without reloading the video? I tried using it but have had no luck.
Yes, using the requestFullscreen
method could potentially allow entering full screen mode without reloading the video. However, due to browser security policies, programmatically triggering fullscreen through JavaScript generally requires it to be initiated by a user action (like a click event).
Given that you are detecting a magnification gesture in Swift, and then attempting to execute the requestFullscreen
method through a JavaScript execution, the browser may block it, interpreting it as not initiated by a user action.
Despite these restrictions, you could still try executing requestFullscreen
on the video element directly. To do this, you will first need to get a reference to the correct DOM element representing the YouTube video player, and then call the requestFullscreen
method on it.
@objc func didMagnify(_ gesture: UIPinchGestureRecognizer) {
if gesture.state == .ended {
webView.evaluateJavaScript("document.querySelector('iframe').requestFullscreen();", completionHandler: nil)
}
}
If the above approach does not work, it would most likely be due to the browser's restrictions on programmatically entering full screen without a direct user action within the webpage.
To circumvent this, a different approach could involve creating a custom "full screen" experience where you effectively mimic full screen behavior by adjusting the CSS of your iframe to occupy the entire view. That would not technically be full screen, but it might be a sufficient workaround to create a more immersive viewing experience without reloading the video.
Answered By - VonC
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.