UWP - Add Youtube video in the WebView

説明如何在 WebView 加入 Youtube 影片,并且避開一些可能的問題。

通常開發 App 要整合 Youtube 的影片時通常會使用 <MyToolkit for .NET>,

該元件已經包裝好方便開發人員衹需要給予影片的 Id 跟需要的畫質就可以直接取得 URL 提供給 MediaElement 播放。

這個元件相當方便,如果遇到客戶不允許或是擔心 Youtube 又改了機制造成影片無法取得的情形(需要等待更新),我會比較建議您改用 WebView 的方式來開發。

現在 Edge 支援 HTML5,使用 WebView 載入 Youtube 又可以避開因爲 App 沒有辦法讓 Google 收取廣告而强迫下架的問題。

 

那麽,要將 Youtube 影片加入 WebView 中有幾種做法:

1. 建立一個網站,寫一個完整的 html 檔案 + iframe

這個做法的目的是爲了讓 App 直接去播放 Youtube 内容時常會遇到一些授權的問題。

因此,藉由架設一個網站裏面放一個網頁裏面有一個 iframe 可以播放 Youtube URL 就可以簡單播放。如下:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">

        <iframe width="420" height="345" runat="server" id="iframeControl" 
                src="https://www.youtube.com/embed/pOWHClN5D78?enablejsapi=1&origin=https://localhost"></iframe>
    </form>
</body>
</html>

 

2. 直接使用 Youtube API 提供的 Javascript API

<!DOCTYPE html>
<html>
  <body>
    <!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
    <div id="player"></div>

    <script>
      // 2. This code loads the IFrame Player API code asynchronously.
      var tag = document.createElement('script');

      tag.src = "https://www.youtube.com/iframe_api";
      var firstScriptTag = document.getElementsByTagName('script')[0];
      firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

      // 3. This function creates an <iframe> (and YouTube player)
      //    after the API code downloads.
      var player;
      function onYouTubeIframeAPIReady() {
        player = new YT.Player('player', {
          height: '390',
          width: '640',
          videoId: '@YUBID',
          events: {
            'onReady': onPlayerReady,
            'onStateChange': onPlayerStateChange
          }
        });
      }

      // 4. The API will call this function when the video player is ready.
      function onPlayerReady(event) {
        event.target.playVideo();
      }

      // 5. The API calls this function when the player's state changes.
      //    The function indicates that when playing a video (state=1),
      //    the player should play for six seconds and then stop.
      var done = false;
      function onPlayerStateChange(event) {
        if (event.data == YT.PlayerState.PLAYING && !done) {
          setTimeout(stopVideo, 6000);
          done = true;
        }
      }
      function stopVideo() {
        player.stopVideo();
      }
    </script>
  </body>
</html>

可以直接將上述的 HTML 寫到一個檔案,藉由 NavigateToString 來寫入,但是要記得更換videoId 參數,如下範例:

 private async Task<string> ReadHTML(string id, string fileName)
 {
    StorageFile htmlFile = await Package.Current.InstalledLocation.GetFileAsync($"Assets\\{fileName}");
    string htmlFragment = await FileIO.ReadTextAsync(htmlFile);
    htmlFile = null;
    // 將 @YUBID 換成真的 YouTube 影片 Id
    htmlFragment = htmlFragment.Replace("@YUBID", id);
    return htmlFragment;
}

 

3. 使用 HttpRequestMessage 指定好 Youtube 影片的 URL 指定給 WebView

這個方式是最簡單也是比較容易成功的方式,一樣可以避開 Youtube 影片授權的問題。如下:

private void SetWebViewYoutubeUrl(string youtube)
{
    string url = $"{youtube}?origin=https://www.google.com";
    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(url));

    // Referer 一定要設定才能正確播放有授權限制的影片
    request.Headers.Referer = new Uri("http://a9jlvideoservice.azurewebsites.net/youtube.aspx");

    webViewControl.NavigateWithHttpRequestMessage(request);
}

這樣的做法有幾個目的:

  • 設定 origin 讓 Youtube 知道這個影片從哪裏播放
  • Referer 是我從方法1 推論出來的結果,其效果同 origin 爲了就是讓 Youtube 知道是個合法播放器

 

上述的這些做法都可以做到,特別要注意的是在 Youtube Player Parameter 的部分有幾個説明:

  • Embed a player using the IFrame Player API
Parameters Supported players Description
autoplay HTML5 This parameter specifies whether the initial video will automatically start to play when the player loads. Supported values are 0 or 1. The default value is 0.
enablejsapi HTML5 Setting the parameter's value to 1 enables the player to be controlled via IFrame or JavaScript Player API calls. The default value is 0, which means that the player cannot be controlled using those APIs.

For more information on the IFrame API and how to use it, see the IFrame API documentation. (The JavaScript Player API has already been deprecated.)
origin HTML5 This parameter provides an extra security measure for the IFrame API and is only supported for IFrame embeds. If you are using the IFrame API, which means you are setting the enablejsapi parameter value to 1, you should always specify your domain as the origin parameter value.

======

這篇主要是把開發過程遇到的問題,再經過實驗之後所整理出來的小筆記。

希望對預計在 App 裏面加入 YouTube 影片的人有所幫助,謝謝。

 

References: