支援網頁應用程式

1. 總覽

Google Cast 標誌

本程式碼研究室將說明如何調整現有的網路影片應用程式,以便在支援 Google Cast 的裝置上投放內容。

什麼是 Google Cast?

Google Cast 可讓使用者將行動裝置中的內容投放到電視上。這樣一來,使用者就能將行動裝置當做遙控器,用來在電視上播放媒體內容。

Google Cast SDK 可讓您擴充應用程式,藉此控制電視或音效系統。Cast SDK 可讓您根據 Google Cast 設計檢查清單,新增必要的使用者介面元件。

我們提供 Google Cast 設計檢查清單,讓所有支援的平台的使用者更容易享有 Cast 使用者體驗。

我們要構建什麼內容?

完成本程式碼研究室後,您會擁有 Chrome 網路影片應用程式,可將影片投放到 Google Cast 裝置。

課程內容

  • 如何將 Google Cast SDK 新增至影片範例應用程式。
  • 如何新增用於選取 Google Cast 裝置的投放按鈕。
  • 如何連線至投放裝置及啟動媒體接收器。
  • 如何投放影片。
  • 如何整合 Cast Connect

軟硬體需求

  • 最新版的 Google Chrome 瀏覽器。
  • HTTPS 代管服務,例如 Firebase 託管ngrok
  • 支援網際網路連線的 Google Cast 裝置,例如 ChromecastAndroid TV
  • 具備 HDMI 輸入端的電視或螢幕。
  • 你必須要有 Chromecast (支援 Google TV) 才能測試 Cast Connect 整合功能,但你也可以選擇使用程式碼研究室來進行其他程式碼研究室。如果您尚未擁有,可以略過本教學課程的新增 Cast Connect 支援步驟。

功能

  • 您必須具備網站開發相關知識。
  • 你也必須瞭解先前的電視相關知識 :)

您要如何使用這個教學課程?

僅讀完整內容 閱讀並完成練習

針對網頁應用程式的建構體驗,您會給予什麼評價?

新手 中級 有效率

您對觀看電視的體驗有什麼評價?

新手 中級 有效率

2. 取得範例程式碼

您可以將所有程式碼範例下載到電腦上...

解壓縮下載的 ZIP 檔案。

3. 執行範例應用程式

Google Chrome 標誌

首先,讓我們來看看已完成的範例應用程式。這款應用程式是基本的影片播放器。使用者可以從清單中選取影片,然後在裝置上本機播放影片,或是將影片投放到 Google Cast 裝置。

為了使用已完成,需要託管您的應用程式。

如果您沒有可用伺服器,可以使用 Firebase 託管ngrok

執行伺服器

您選擇的服務設定完成後,請前往 app-done 並啟動伺服器。

在瀏覽器中,造訪您所代管範例的 https 網址。

  1. 你應該會看到影片應用程式。
  2. 按一下「投放」按鈕,然後選取你的 Google Cast 裝置。
  3. 選取影片,按一下播放按鈕。
  4. 影片就會在 Google Cast 裝置上開始播放。

影片在投放裝置上播放的圖片

按一下影片元素中的暫停按鈕,即可暫停接收接收器中的影片。按一下影片元素中的播放按鈕,即可繼續播放影片。

按一下「投放」按鈕,即可停止將內容投放到 Google Cast 裝置。

在繼續操作之前,請先停止伺服器。

4. 準備起始專案

影片在投放裝置上播放的圖片

我們需要為你下載的啟動應用程式新增 Google Cast 支援。以下是本程式碼研究室會使用的一些 Google Cast 術語:

  • 傳送者應用程式是在行動裝置或筆記型電腦上執行,
  • 「接收器」應用程式會在 Google Cast 裝置上執行。

您現在可以用自己慣用的文字編輯器,在入門專案上進行建構:

  1. 從程式碼範例下載中選取 資料夾圖示app-start 目錄。
  2. 使用伺服器執行應用程式,並探索 UI。

請注意,當您執行本程式碼研究室時,必須依服務重新在伺服器上重新託管範例。

應用程式設計

應用程式會從遠端網路伺服器擷取影片清單,並提供清單讓使用者瀏覽。使用者選取影片後,即可在行動裝置上查看詳細資料或播放影片。

應用程式是由 index.html 和主要控制器 (CastVideos.js.) 定義的主要檢視畫面

index.html

這個 HTML 檔案會宣告網頁應用程式的所有 UI。

有幾個部分的位置是 div#main_video,其中包含了影片元素。與影片 div 有關,我們定義了 div#media_control,以定義影片元素的所有控制項。下方的 media_info 會顯示顯示影片的詳細資料。最後,carousel div 顯示 div 中的影片清單。

index.html 檔案也會啟動 Cast SDK,並指示 CastVideos 函式載入。

填入這些元素的內容,大多都是在 CastVideos.js 內定義、插入及控制。我們來看看

CastVideos.js

這個指令碼會管理 Cast Video 網頁應用程式的所有邏輯。影片清單及其在 CastVideos.js 中定義的相關中繼資料都包含在名為 mediaJSON 的物件中。

並分為以下幾個主要部分,分別負責在本機和遠端管理和播放影片。整體而言,這是相當直接的網頁應用程式。

CastPlayer 是管理整個應用程式、設定播放器、選取媒體,以及將事件繫結至 PlayerHandler 的主要類別。CastPlayer.prototype.initializeCastPlayer 是設定所有 Cast 功能的方法。CastPlayer.prototype.switchPlayer 會在本機和遠端玩家之間切換狀態。CastPlayer.prototype.setupLocalPlayerCastPlayer.prototype.setupRemotePlayer 會初始化本機和遠端玩家。

PlayerHandler 是負責管理媒體播放的類別。還有許多其他方法能管理媒體和播放。

常見問題

5. 新增「投放」按鈕

支援 Cast 的應用程式圖片

支援投放功能的應用程式會在影片元素中顯示「投放」按鈕。按一下「投放」按鈕,即可顯示可讓使用者選取的投放裝置清單。如果使用者在本機裝置上播放內容,選取投放裝置就會在該投放裝置上開始或繼續播放。在投放期間,您隨時可以點選「投放」按鈕,並停止將應用程式投放到投放裝置。如在應用程式 Google Cast 設計檢查清單中所述,使用者必須能在應用程式的任何畫面中連線至或中斷與投放裝置的連線。

設定

範例專案需要和已完成範例應用程式相同的依附元件和設定,但這次會託管 app-start 的內容。

在瀏覽器中,造訪託管範例的 https 網址。

請記住,當您進行變更時,就必須依服務重新在伺服器上重新託管範例。

初始化

Cast 架構有全域單例模式物件 CastContext,可以協調所有架構的活動。此物件必須在應用程式的生命週期中盡早初始化,通常會從指派給 window['__onGCastApiAvailable'] 的回呼中呼叫,而該方法會在 Cast SDK 載入後呼叫,以供使用。在這種情況下,系統會在 CastPlayer.prototype.initializeCastPlayer 中呼叫 CastContext,後者會從上述回呼進行呼叫。

初始化 CastContext 時,必須提供 options JSON 物件。這個類別包含會影響架構行為的選項。其中最重要的是接收端應用程式 ID,用於篩選可用的投放裝置清單,只顯示能夠執行指定應用程式的裝置,以及在投放工作階段開始時啟動接收器應用程式。

開發自己的支援 Cast 應用程式時,您必須註冊為 Cast 開發人員,並取得應用程式的應用程式 ID。在本程式碼研究室中,我們會使用範例應用程式 ID。

body 區段最結尾,將下列程式碼新增至 index.html

<script type="text/javascript" src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>

將下列程式碼新增至 index.html,以初始化 CastVideos 應用程式,以及初始化 CastContext

<script src="CastVideos.js"></script>
<script type="text/javascript">
var castPlayer = new CastPlayer();
window['__onGCastApiAvailable'] = function(isAvailable) {
  if (isAvailable) {
    castPlayer.initializeCastPlayer();
  }
};
</script>

現在,我們需要在 CastVideos.js 中新增方法,對應至我們剛才在 index.html 中呼叫的方法。讓我們新增名為 initializeCastPlayer 的新方法,用來設定 CastContext 的選項,並初始化新的 RemotePlayerRemotePlayerControllers

/**
 * This method sets up the CastContext, and a few other members
 * that are necessary to play and control videos on a Cast
 * device.
 */
CastPlayer.prototype.initializeCastPlayer = function() {

    var options = {};

    // Set the receiver application ID to your own (created in
    // the Google Cast Developer Console), or optionally
    // use the chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID
    options.receiverApplicationId = 'C0868879';

    // Auto join policy can be one of the following three:
    // ORIGIN_SCOPED - Auto connect from same appId and page origin
    // TAB_AND_ORIGIN_SCOPED - Auto connect from same appId, page origin, and tab
    // PAGE_SCOPED - No auto connect
    options.autoJoinPolicy = chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED;

    cast.framework.CastContext.getInstance().setOptions(options);

    this.remotePlayer = new cast.framework.RemotePlayer();
    this.remotePlayerController = new cast.framework.RemotePlayerController(this.remotePlayer);
    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.IS_CONNECTED_CHANGED,
        this.switchPlayer.bind(this)
    );
};

最後,我們必須建立 RemotePlayerRemotePlayerController 的變數:

var CastPlayer = function() {
  //...
  /* Cast player variables */
  /** @type {cast.framework.RemotePlayer} */
  this.remotePlayer = null;
  /** @type {cast.framework.RemotePlayerController} */
  this.remotePlayerController = null;
  //...
};

投放按鈕

CastContext 初始化後,我們必須新增「投放」按鈕,才能選取投放裝置。Cast SDK 提供名為 google-cast-launcher 的投放按鈕元件,ID 為「castbutton"」。您只需在 media_control 區段中新增 button,就能將 ID 新增至應用程式的影片元素。

以下是按鈕元素的外觀:

<google-cast-launcher id="castbutton"></google-cast-launcher>

media_control 區段中將下列程式碼新增至 index.html

<div id="media_control">
  <div id="play"></div>
  <div id="pause"></div>
  <div id="progress_bg"></div>
  <div id="progress"></div>
  <div id="progress_indicator"></div>
  <div id="fullscreen_expand"></div>
  <div id="fullscreen_collapse"></div>
  <google-cast-launcher id="castbutton"></google-cast-launcher>
  <div id="audio_bg"></div>
  <div id="audio_bg_track"></div>
  <div id="audio_indicator"></div>
  <div id="audio_bg_level"></div>
  <div id="audio_on"></div>
  <div id="audio_off"></div>
  <div id="duration">00:00:00</div>
</div>

現在請重新整理 Chrome 瀏覽器中的頁面。你應該會在影片元素中看到「投放」按鈕,點選後就會看到區域網路的「投放」裝置清單。裝置探索設定是由 Chrome 瀏覽器自動管理。選取投放裝置後,系統便會在投放裝置上載入範例應用程式。

系統尚未支援媒體播放功能,因此目前無法在投放裝置上播放影片。按一下「投放」按鈕即可停止投放。

6. 投放影片內容

支援 Cast 裝置選項選單的圖片

也會擴充範例應用程式,以便在投放裝置上從遠端播放影片。為此,我們必須監聽 Cast 架構產生的各種事件。

正在投放媒體

整體而言,如要在投放裝置上播放媒體,請按照下列步驟操作:

  1. 透過 Cast SDK 建立 MediaInfo JSON 物件,用於建立媒體項目模型。
  2. 使用者連線至投放裝置,以便啟動接收器應用程式。
  3. MediaInfo 物件載入接收器並播放內容。
  4. 追蹤媒體狀態。
  5. 根據使用者互動情形,將播放指令傳送至接收器。

步驟 1 是將一個物件對應至另一個物件;MediaInfo 是 Cast SDK 能解讀的,而 mediaJSON 是應用程式針對媒體項目封裝的功能,我們可以輕鬆將 mediaJSON 對應至 MediaInfo。我們已完成上一節的步驟 2。步驟 3 可以使用 Cast SDK 輕鬆完成。

範例應用程式 CastPlayer 已在 switchPlayer 方法中區分本機與遠端播放:

if (cast && cast.framework) {
  if (this.remotePlayer.isConnected) {
    //...

在這個程式碼研究室中,您不一定要瞭解所有範例播放器邏輯的運作方式。不過請注意,您必須修改應用程式的媒體播放器,才能得知本機和遠端的播放情形。

目前,本機玩家始終無法確定本機投放狀態的狀態,因此這類遊戲一律會持續在本機播放狀態。我們需要根據 Cast 架構發生的狀態轉換來更新 UI。舉例來說,如果我們開始投放內容,必須停止本機播放作業並停用部分控制項。同樣地,如果使用這個檢視控制器時停止投放,則必須改用本機播放。為了處理音訊,我們必須監聽 Cast 架構產生的各種事件。

投放工作階段管理

Cast 架構結合了投放裝置的步驟、啟動 (或加入現有工作階段)、連線至接收器應用程式,以及視情況初始化媒體控制管道 (如果適用的話)。媒體控制管道是 Cast 架構如何傳送及接收接收器的媒體播放相關訊息。

當使用者從「投放」按鈕選取裝置時,「投放」工作階段將自動啟動,並在使用者中斷連線時停止。由於網路問題,也會重新連線至接收器工作階段,也會由 Cast 架構自動處理。

投放工作階段是由 CastSession 管理,你可以透過 cast.framework.CastContext.getInstance().getCurrentSession() 存取。EventListener 回呼可用來監控工作階段事件,例如建立、暫停、繼續和終止。

在目前的應用程式中,系統會在 setupRemotePlayer 方法中處理所有工作階段和狀態管理。讓我們在應用程式裡,將下列程式碼新增到 CastVideos.js 開始設定:

/**
 * Set the PlayerHandler target to use the remote player
 */
CastPlayer.prototype.setupRemotePlayer = function () {
    var castSession = cast.framework.CastContext.getInstance().getCurrentSession();

    this.playerHandler.setTarget(playerTarget);

    // Setup remote player volume right on setup
    // The remote player may have had a volume set from previous playback
    if (this.remotePlayer.isMuted) {
        this.playerHandler.mute();
    }
    var currentVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
    var p = document.getElementById('audio_bg_level');
    p.style.height = currentVolume + 'px';
    p.style.marginTop = -currentVolume + 'px';

    this.hideFullscreenButton();

    this.playerHandler.play();
};

我們仍需繫結回呼中的所有事件,並處理所有產生的事件。這種做法相當簡單,所以我們現在來看看這一點:

/**
 * Set the PlayerHandler target to use the remote player
 */
CastPlayer.prototype.setupRemotePlayer = function () {
    var castSession = cast.framework.CastContext.getInstance().getCurrentSession();

    // Add event listeners for player changes which may occur outside sender app
    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.IS_PAUSED_CHANGED,
        function() {
            if (this.remotePlayer.isPaused) {
                this.playerHandler.pause();
            } else {
                this.playerHandler.play();
            }
        }.bind(this)
    );

    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.IS_MUTED_CHANGED,
        function() {
            if (this.remotePlayer.isMuted) {
                this.playerHandler.mute();
            } else {
                this.playerHandler.unMute();
            }
        }.bind(this)
    );

    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.VOLUME_LEVEL_CHANGED,
        function() {
            var newVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
            var p = document.getElementById('audio_bg_level');
            p.style.height = newVolume + 'px';
            p.style.marginTop = -newVolume + 'px';
        }.bind(this)
    );

    // This object will implement PlayerHandler callbacks with
    // remotePlayerController, and makes necessary UI updates specific
    // to remote playback
    var playerTarget = {};

    playerTarget.play = function () {
        if (this.remotePlayer.isPaused) {
            this.remotePlayerController.playOrPause();
        }

        var vi = document.getElementById('video_image');
        vi.style.display = 'block';
        var localPlayer = document.getElementById('video_element');
        localPlayer.style.display = 'none';
    }.bind(this);

    playerTarget.pause = function () {
        if (!this.remotePlayer.isPaused) {
            this.remotePlayerController.playOrPause();
        }
    }.bind(this);

    playerTarget.stop = function () {
         this.remotePlayerController.stop();
    }.bind(this);

    playerTarget.getCurrentMediaTime = function() {
        return this.remotePlayer.currentTime;
    }.bind(this);

    playerTarget.getMediaDuration = function() {
        return this.remotePlayer.duration;
    }.bind(this);

    playerTarget.updateDisplayMessage = function () {
        document.getElementById('playerstate').style.display = 'block';
        document.getElementById('playerstatebg').style.display = 'block';
        document.getElementById('video_image_overlay').style.display = 'block';
        document.getElementById('playerstate').innerHTML =
            this.mediaContents[ this.currentMediaIndex]['title'] + ' ' +
            this.playerState + ' on ' + castSession.getCastDevice().friendlyName;
    }.bind(this);

    playerTarget.setVolume = function (volumeSliderPosition) {
        // Add resistance to avoid loud volume
        var currentVolume = this.remotePlayer.volumeLevel;
        var p = document.getElementById('audio_bg_level');
        if (volumeSliderPosition < FULL_VOLUME_HEIGHT) {
            var vScale =  this.currentVolume * FULL_VOLUME_HEIGHT;
            if (volumeSliderPosition > vScale) {
                volumeSliderPosition = vScale + (pos - vScale) / 2;
            }
            p.style.height = volumeSliderPosition + 'px';
            p.style.marginTop = -volumeSliderPosition + 'px';
            currentVolume = volumeSliderPosition / FULL_VOLUME_HEIGHT;
        } else {
            currentVolume = 1;
        }
        this.remotePlayer.volumeLevel = currentVolume;
        this.remotePlayerController.setVolumeLevel();
    }.bind(this);

    playerTarget.mute = function () {
        if (!this.remotePlayer.isMuted) {
            this.remotePlayerController.muteOrUnmute();
        }
    }.bind(this);

    playerTarget.unMute = function () {
        if (this.remotePlayer.isMuted) {
            this.remotePlayerController.muteOrUnmute();
        }
    }.bind(this);

    playerTarget.isMuted = function() {
        return this.remotePlayer.isMuted;
    }.bind(this);

    playerTarget.seekTo = function (time) {
        this.remotePlayer.currentTime = time;
        this.remotePlayerController.seek();
    }.bind(this);

    this.playerHandler.setTarget(playerTarget);

    // Setup remote player volume right on setup
    // The remote player may have had a volume set from previous playback
    if (this.remotePlayer.isMuted) {
        this.playerHandler.mute();
    }
    var currentVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
    var p = document.getElementById('audio_bg_level');
    p.style.height = currentVolume + 'px';
    p.style.marginTop = -currentVolume + 'px';

    this.hideFullscreenButton();

    this.playerHandler.play();
};

正在載入媒體

在 Cast SDK 中,RemotePlayerRemotePlayerController 提供了一組便利的 API,可用於管理接收器的遠端媒體播放作業。對於支援媒體播放的 CastSession,SDK 會自動建立 RemotePlayerRemotePlayerController 的執行個體。只要分別建立 cast.framework.RemotePlayercast.framework.RemotePlayerController 的執行個體,即可存取程式碼研究室,如這些程式碼研究室所示。

接下來,我們需要建立 MediaInfo 物件,以便 SDK 處理並傳入要求,以便在接收器上載入目前選取的影片。在 setupRemotePlayer 加入以下程式碼,即可執行此操作:

/**
 * Set the PlayerHandler target to use the remote player
 */
CastPlayer.prototype.setupRemotePlayer = function () {
    //...

    playerTarget.load = function (mediaIndex) {
        console.log('Loading...' + this.mediaContents[mediaIndex]['title']);
        var mediaInfo = new chrome.cast.media.MediaInfo(
            this.mediaContents[mediaIndex]['sources'][0], 'video/mp4');

        mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata();
        mediaInfo.metadata.metadataType = chrome.cast.media.MetadataType.GENERIC;
        mediaInfo.metadata.title = this.mediaContents[mediaIndex]['title'];
        mediaInfo.metadata.images = [
            {'url': MEDIA_SOURCE_ROOT + this.mediaContents[mediaIndex]['thumb']}];

        var request = new chrome.cast.media.LoadRequest(mediaInfo);
        castSession.loadMedia(request).then(
            this.playerHandler.loaded.bind(this.playerHandler),
            function (errorCode) {
                this.playerState = PLAYER_STATE.ERROR;
                console.log('Remote media load error: ' +
                    CastPlayer.getErrorMessage(errorCode));
            }.bind(this));
    }.bind(this);

    //...
};

現在請新增方法,在本機和遠端播放之間切換:

/**
 * This is a method for switching between the local and remote
 * players. If the local player is selected, setupLocalPlayer()
 * is run. If there is a cast device connected we run
 * setupRemotePlayer().
 */
CastPlayer.prototype.switchPlayer = function() {
    this.stopProgressTimer();
    this.resetVolumeSlider();
    this.playerHandler.stop();
    this.playerState = PLAYER_STATE.IDLE;
    if (cast && cast.framework) {
        if (this.remotePlayer.isConnected) {
            this.setupRemotePlayer();
            return;
        }
    }
    this.setupLocalPlayer();
};

最後,請新增處理任何投放錯誤訊息的方法:

/**
 * Makes human-readable message from chrome.cast.Error
 * @param {chrome.cast.Error} error
 * @return {string} error message
 */
CastPlayer.getErrorMessage = function(error) {
  switch (error.code) {
    case chrome.cast.ErrorCode.API_NOT_INITIALIZED:
      return 'The API is not initialized.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.CANCEL:
      return 'The operation was canceled by the user' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.CHANNEL_ERROR:
      return 'A channel to the receiver is not available.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.EXTENSION_MISSING:
      return 'The Cast extension is not available.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.INVALID_PARAMETER:
      return 'The parameters to the operation were not valid.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.RECEIVER_UNAVAILABLE:
      return 'No receiver was compatible with the session request.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.SESSION_ERROR:
      return 'A session could not be created, or a session was invalid.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.TIMEOUT:
      return 'The operation timed out.' +
        (error.description ? ' :' + error.description : '');
  }
};

現在請執行應用程式。連線至你的投放裝置並開始播放影片。您應該會看到接收器正在播放影片。

7. 新增 Cast Connect 支援服務

Cast Connect 程式庫可讓現有傳送端應用程式透過 Cast 通訊協定與 Android TV 應用程式進行通訊。Cast Connect 是以 Cast 基礎架構為建構基礎,並以 Android TV 應用程式做為接收器。

依附元件

  • Chrome 瀏覽器 M87 以上版本

設定與 Android 接收器相容

如要啟動 Android TV 應用程式 (也稱為 Android 接收器),我們必須在 CastOptions 物件中將 androidReceiverCompatible 旗標設為 true。

將下列程式碼新增至 initializeCastPlayer 函式中的 CastVideos.js

var options = {};
...
options.androidReceiverCompatible = true;

cast.framework.CastContext.getInstance().setOptions(options);

設定啟動憑證

在傳送者端,您可以指定 CredentialsData 來代表加入會議的使用者。credentials 是使用者定義的字串,前提是您的電視業者能夠理解。只有在啟動或加入時,CredentialsData 才會傳送到您的 Android TV 應用程式中。如果你在重新連上網路時再設定一次,該裝置並不會傳送至 Android TV 應用程式。

如要設定啟動憑證,則必須在設定啟動選項後隨時定義 CredentialsData

將下列程式碼新增至 CastVideos.js 函式中的 initializeCastPlayer 函式:

cast.framework.CastContext.getInstance().setOptions(options);
...
let credentialsData = new chrome.cast.CredentialsData("{\"userId\": \"abc\"}");
cast.framework.CastContext.getInstance().setLaunchCredentialsData(credentialsData);
...

在載入要求中設定憑證

如果您的 Web Receiver 應用程式和 Android TV 應用程式處理 credentials 的方式不同,您可能需要個別定義憑證。如要解決這個問題,請在 CastVideos.js setupRemotePlayer 函式的 playerTarget.load 中加入下列程式碼:

...
var request = new chrome.cast.media.LoadRequest(mediaInfo);
request.credentials = 'user-credentials';
request.atvCredentials = 'atv-user-credentials';
...

視傳送者的投放應用程式而定,SDK 現在會自動處理目前工作階段使用的憑證。

正在測試 Cast Connect

在 Chromecast (支援 Google TV) 上安裝 Android TV APK 的步驟:

  1. 找出 Android TV 裝置的 IP 位址。這個選項通常位於「設定」>「網路和網際網路」>「裝置所連線的網路名稱」之下。右側會顯示詳細資料和網路上的 IP 位址。
  2. 使用裝置的 IP 位址,透過終端機透過 ADB 連線至裝置:
$ adb connect <device_ip_address>:5555
  1. 在終端機視窗中,前往頂層程式碼研究室,從本程式碼研究室開始下載的程式碼研究室範例。例如:
$ cd Desktop/chrome_codelab_src
  1. 執行下列指令,將這個資料夾中的 .apk 檔案安裝至 Android TV:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
  1. 現在,在 Android TV 裝置的「您的應用程式」選單中,您應該會看到以「投放影片」為您的應用程式的名稱。
  2. 使用「投放」圖示執行更新的網站寄件者程式碼,並透過 Android TV 裝置建立投放工作階段,或從 Chrome 瀏覽器的下拉式選單中選取 Cast..。系統隨即會在 Android 接收器上啟動 Android TV 應用程式,並讓你使用 Android TV 遙控器控製播放內容。

8. 恭喜

現在您已經瞭解如何在 Chrome 網頁應用程式中使用 Cast SDK 小工具來啟用影片應用程式,

詳情請參閱網路寄件者開發人員指南。