如何让 YouTube 原生播放器在 WebView2 中允许全屏?

问题描述 投票:0回答:1

我使用 WebView2 浏览器允许播放某些 YouTube 视频,但全屏选项不可用。
我写的代码如下。我对编码非常陌生,我可能弄错了。
您需要的任何更多信息我都愿意提供。

public partial class HowToViewSites: CMBaseDialog
{
    private dynamic player;

    public HowToViewSites()
    {
        InitializeComponent();
        InitializeWebView2();
    }

    private async void InitializeWebView2()
    {
       
        await webView21.EnsureCoreWebView2Async(null);

        webView21.CoreWebView2.Settings.IsScriptEnabled = true;

        webView21.CoreWebView2InitializationCompleted += WebView2_CoreWebView2InitializationCompleted;                     
        
        string htmlContent = @"
            <html>
            <head>
            <!-- Include the YouTube iframe API script using HTTPS -->
            <script src='https://www.youtube.com/iframe_api'></script>
            </head>
            <body>
            <!-- Embed the YouTube video with enablejsapi parameter over HTTPS -->
            <iframe id='player' type='text/html' width='840' height='560'
                src='https://www.youtube.com/embed/QgMnE1No_6A?enablejsapi=1'
                frameborder='0'></iframe>

            <!-- JavaScript code to handle fullscreen changes -->
            <script>
             // Initialize the YouTube iframe API when the script is loaded
            function onYouTubeIframeAPIReady() {
            player = new YT.Player('player', {
            events: {
                    'onReady': onPlayerReady,
                    'onStateChange': onPlayerStateChange
                    }
                });
            }

            function onPlayerReady(event) {
            // Player is ready
            // You can control playback and perform other actions here
            }

            function onPlayerStateChange(event) {
            // Player state has changed (e.g., video started, paused, etc.)
            // Check if the player is in fullscreen mode
                var isFullscreen = document.fullscreenElement === player.getIframe();

                if (isFullscreen) {
            // Trigger the player's native fullscreen mode
                external.RequestFullscreen();
                } else {
            // Exit fullscreen
                external.ExitFullscreen();
             }
            }

            document.addEventListener('fullscreenchange', function () {
            console.log('Fullscreen change event triggered');
            window.chrome.webview.postMessage('fullscreenchange');
            });
            </script>
            </body>
            </html>
        ";
        webView21.NavigateToString(htmlContent);

        webView21.CoreWebView2.Settings.IsWebMessageEnabled = true;
        webView21.WebMessageReceived += CoreWebView2_WebMessageReceived;            
    }

    private async void WebView2_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e)
    {
        if (e.IsSuccess)
        {
            // No need to manually call onYouTubeIframeAPIReady here
        }
        else
        {
            MessageBox.Show("WebView2 initialization failed.");
        }
    }

    private void CoreWebView2_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs e)
    {
        string message = e.TryGetWebMessageAsString();
        if (message == "enteredFullscreen")
        {
            RequestFullscreen();
        }
        else if (message == "exitedFullscreen")
        {
            ExitFullscreen();
        }
    }
            
    public void RequestFullscreen()
    {
        this.BeginInvoke(new Action(() =>
        {
            this.FormBorderStyle = FormBorderStyle.None;
            this.WindowState = FormWindowState.Maximized;
            this.TopMost = true;
            
            player.playVideo();
        }));
    }

    public void ExitFullscreen()
    {
        this.BeginInvoke(new Action(() =>
        {
            this.FormBorderStyle = FormBorderStyle.Sizable;
            this.WindowState = FormWindowState.Normal;
            this.TopMost = false;
            
            player.pauseVideo();
        }));
    }
}

非常感谢您抽出时间来帮助我。

c# winforms youtube media-player webview2
1个回答
1
投票

一些注意事项:

  • WebView2 初始化未正确执行。你真的应该等待你的
    InitializeWebView2()
    方法应该返回
    Task

    您可以重写
    OnLoad()
    方法(或订阅
    Load
    事件),使其异步,然后等待
    InitializeWebView2()
  • [WebView2].CoreWebView2InitializationComplete 需要在调用之前订阅
    .EnsureCoreWebView2Async()
  • WebView2 控件已经知道 HTML 元素何时请求全屏布局。引发 ContainsFullScreenElementChanged 事件以通知状态更改。然后,您检查 ContainsFullScreenElement 的设置并采取相应措施

我建议不要直接使用 IFrame 来嵌入视频。
YouTube 播放器已经具备此功能:它可以根据您传递给其构造函数的 ID,使用 IFrame 元素替换元素,并使用您在创建播放器时设置的属性进行配置。
例如,这允许调用 JavaScript 函数来停止/暂停/恢复播放。您可以使用 ExecuteScriptAsync() 方法来完成此操作。
您还可以在播放器的

enablejsapi = 1
属性中设置
playerVars

这允许复制/获取视频的地址:

This is the one you posted:  
https://www.youtube.com/watch?v=QgMnE1No_6A

且仅使用其

videoId
-
QgMnE1No_6A
- 初始化播放器

这也启用了播放器的全屏按钮。
如果使用 IFrame,则必须设置一个属性:

<iframe allowfullscreen="allowfullscreen" [...] >  </iframe>

请注意,我已重命名了控件

webView
(没有原因,就是这样:)

public partial class HowToViewSites: CMBaseDialog
{
    public HowToViewSites() => InitializeComponent();

    protected override async void OnLoad(EventArgs e) {
        base.OnLoad(e);
        await InitializeWebView2();

        var videoSource = new Uri("https://www.youtube.com/watch?v=QgMnE1No_6A");
        var videoId = videoSource.Query.Substring(videoSource.Query.LastIndexOf("=") + 1);
        webView.NavigateToString(GetHTMLContent(videoId, new Size(840, 560)));
    }

    private async Task InitializeWebView2()
    {
       // See the docs about CoreWebView2EnvironmentOptions, you may need it
       // when your application is deployed. Now it's just set to defaults
        var options = new CoreWebView2EnvironmentOptions(null, null, "", false);
        var env = await CoreWebView2Environment.CreateAsync("", null, options);

        webView.CoreWebView2InitializationCompleted += WebView2_CoreWebView2InitializationCompleted;
        await webView.EnsureCoreWebView2Async(env);
    }

    private void WebView2_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e) {
        if (e.IsSuccess) {
            webView.CoreWebView2.Settings.IsWebMessageEnabled = true;
            webView.CoreWebView2.Settings.IsScriptEnabled = true;

            webView.WebMessageReceived += async (o, a) => {
                string message = a.TryGetWebMessageAsString();
                switch (message) {
                    case "Player initialized":
                        // Starts the playback after the YT Player has been initialized
                        await Task.Delay(200);
                        await webView.ExecuteScriptAsync("ResumeVideo()");
                        break;
                    default:
                        Debug.WriteLine(message);
                        break;
                }
            };

            webView.CoreWebView2.ContainsFullScreenElementChanged += (o, a) => {
                RequestFullscreen(webView.CoreWebView2.ContainsFullScreenElement);
            };
        }
        else {
            MessageBox.Show("Core WebView component initialization failed");
            Application.ExitThread();
        }
    }

    public void RequestFullscreen(bool isFullScreen) {
        FormBorderStyle = isFullScreen ? FormBorderStyle.None : FormBorderStyle.Sizable;
        WindowState = isFullScreen ? FormWindowState.Maximized : FormWindowState.Normal;
    }
}

我更改了 HTML 和 JavaScript,因此您可以使用视频 ID 初始化播放器以及指定大小的页面:

private string GetHTMLContent(string videoId, Size videoSize) {
    var sb = new StringBuilder(@"
        <html>
        <head>
            <!-- Include the YouTube iframe API script using HTTPS -->
            <script src='https://www.youtube.com/iframe_api'></script>
            <script>
            var player;
            function onYouTubeIframeAPIReady() {
                player = new YT.Player('playerframe', {
                events: {
                    'onReady': onPlayerReady
                },
                videoId: '[VIDEO-ID]',
                height: '[VIDEO-HEIGHT]',
                width: '[VIDEO-WIDTH]',
                playerVars : {
                    'enablejsapi' : 1
                }});
            }

            function StopVideo() { player.stopVideo(); }
            function PauseVideo() { player.pauseVideo(); }
            function ResumeVideo() { player.playVideo(); }

            function onPlayerReady(event) {
                // Player is ready
                window.chrome.webview.postMessage('Player initialized');
            }
            </script>
        </head>
        <body>
            <!-- Element replaced with an IFrame when the YouType Player is initialized -->
            <div id='playerframe'></div>
        </body>
        </html>
    ");

    sb = sb.Replace("[VIDEO-ID]", videoId)
           .Replace("[VIDEO-HEIGHT]", videoSize.Height.ToString())
           .Replace("[VIDEO-WIDTH]", videoSize.Width.ToString());

    return sb.ToString();
}

现在,如果您想与播放器交互,只需调用 ExecuteScriptAsync() 来执行您设置的函数即可。现在,您可以开始/停止/恢复回报:

await webView.ExecuteScriptAsync("StopVideo()");
await webView.ExecuteScriptAsync("PauseVideo()");
await webView.ExecuteScriptAsync("ResumeVideo()");
© www.soinside.com 2019 - 2024. All rights reserved.