開發電視輸入服務

電視輸入服務代表媒體串流來源,可讓你透過 將傳統電視時尚視為頻道和節目。使用電視輸入服務 家長監護、節目指南資訊和內容分級。電視輸入服務正常運作 Android 系統 TV 應用程式這個應用程式最終能控制及呈現頻道內容 在電視上觀看系統 TV 應用程式是專為裝置開發,不可變動 第三方應用程式想進一步瞭解電視輸入架構 (TIF) 這個架構及其元件 電視輸入架構

使用 TIF 輔助程式庫建立電視輸入服務

TIF 輔助程式庫是一種架構 實作常見的電視輸入服務功能。原始設備製造商 (OEM) 會使用此功能來建構 僅適用於 Android 5.0 (API 級別 21) 至 Android 7.1 (API 級別 25) 的管道。

更新專案

TIF 隨附程式庫可供原始設備製造商 (OEM) 使用, androidtv-sample-inputs Cloud Storage 也提供目錄同步處理功能如需在應用程式中加入程式庫的範例,請參閱該存放區。

在資訊清單中宣告電視輸入服務

應用程式必須提供與 TvInputService 相容的 以及系統存取應用程式的服務TIF 隨附程式庫提供 BaseTvInputService 類別, 提供了 TvInputService 的預設實作 以及可供自訂的部分建立 BaseTvInputService 的子類別。 並將資訊清單中的子類別宣告為服務

在資訊清單宣告中,指定 「BIND_TV_INPUT」權限以便 服務,將電視輸入裝置連接到系統。系統服務 就會執行繫結 BIND_TV_INPUT權限。 系統電視應用程式將要求傳送至電視輸入服務 透過 TvInputManager 介面取得。

在您的服務宣告中,加入意圖篩選器: 要對「TvInputService」執行的動作 意圖。另外,請將服務中繼資料宣告為獨立的 XML 資源。 顯示服務宣告、意圖篩選器和服務中繼資料宣告 在以下範例中:

<service android:name=".rich.RichTvInputService"
    android:label="@string/rich_input_label"
    android:permission="android.permission.BIND_TV_INPUT">
    <!-- Required filter used by the system to launch our account service. -->
    <intent-filter>
        <action android:name="android.media.tv.TvInputService" />
    </intent-filter>
    <!-- An XML file which describes this input. This provides pointers to
    the RichTvInputSetupActivity to the system/TV app. -->
    <meta-data
        android:name="android.media.tv.input"
        android:resource="@xml/richtvinputservice" />
</service>

在個別的 XML 檔案中定義服務中繼資料。「服務」 中繼資料 XML 檔案必須包含設定介面,用於說明電視輸入裝置 執行初始設定和管道掃描作業中繼資料檔案也應包含 ,說明使用者能否錄製內容。如要 如要瞭解如何在應用程式中支援錄製內容,請參閱 支援內容錄製

服務中繼資料檔案位於 XML 資源目錄中 ,而且必須與您在 資訊清單。使用上述範例的資訊清單項目,您會執行下列動作 在 res/xml/richtvinputservice.xml 中建立 XML 檔案,並使用 以下內容:

<?xml version="1.0" encoding="utf-8"?>
<tv-input xmlns:android="http://schemas.android.com/apk/res/android"
  android:canRecord="true"
  android:setupActivity="com.example.android.sampletvinput.rich.RichTvInputSetupActivity" />

定義管道並建立設定活動

您的電視輸入服務必須定義至少一個要讓使用者觀看的頻道 透過系統 TV 應用程式存取你必須註冊自己的頻道 然後將設定活動提供給系統資料庫 在找不到應用程式的頻道時叫用。

首先,允許應用程式讀取及寫入系統 Electronic 節目規劃指南 (EPG):其中的資料包括可觀看的頻道和節目 以便傳達給使用者為了讓應用程式可以執行這些動作,並與 裝置重新啟動後,請在應用程式資訊清單中加入下列元素:

<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED "/>

請加入下列元素,確保您的應用程式會顯示在 Google Play 商店是可在 Android TV 中提供內容頻道的應用程式:

<uses-feature
    android:name="android.software.live_tv"
    android:required="true" />

接著,請建立擴充 EpgSyncJobService 的類別 類別透過這個抽象類別,您可以輕鬆建立工作服務 建立與更新系統資料庫中的頻道。

在子類別中,在 getChannels()。如果頻道來自 XMLTV 檔案, 請使用 XmlTvParser 類別。否則產生 使用 Channel.Builder 類別透過程式輔助方式管道。

系統會針對每個管道呼叫 getProgramsForChannel() 需要在特定時間範圍內可檢視的節目清單時 該頻道。傳回 物件的 Program 物件清單 頻道。使用 XmlTvParser 類別從 上傳 XMLTV 檔案,或是使用 Program.Builder 類別。

針對每個 Program 物件,使用 InternalProviderData 物件來設定程式資訊,例如 節目的影片類型只有少數計畫需要 希望頻道循環播放 InternalProviderData.setRepeatable() 方法,值為 設定節目相關資訊時請true

實作工作服務後,請將服務新增至應用程式資訊清單:

<service
    android:name=".sync.SampleJobService"
    android:permission="android.permission.BIND_JOB_SERVICE"
    android:exported="true" />

最後建立設定活動。您的設定活動應該要提供相關方式 同步頻道和節目資料。其中一個方法是讓使用者 透過活動中的使用者介面應用程式也可能自動幫你處理 活動開始時。設定活動需要同步管道和 程式資訊,應用程式應啟動工作服務:

Kotlin

val inputId = getActivity().intent.getStringExtra(TvInputInfo.EXTRA_INPUT_ID)
EpgSyncJobService.cancelAllSyncRequests(getActivity())
EpgSyncJobService.requestImmediateSync(
        getActivity(),
        inputId,
        ComponentName(getActivity(), SampleJobService::class.java)
)

Java

String inputId = getActivity().getIntent().getStringExtra(TvInputInfo.EXTRA_INPUT_ID);
EpgSyncJobService.cancelAllSyncRequests(getActivity());
EpgSyncJobService.requestImmediateSync(getActivity(), inputId,
        new ComponentName(getActivity(), SampleJobService.class));

使用 requestImmediateSync() 方法進行同步處理 選擇工作服務使用者必須等待同步處理作業完成,因此您應該 盡量縮短要求期

使用 setUpPeriodicSync() 方法提供工作服務 定期在背景同步處理頻道與節目資料:

Kotlin

EpgSyncJobService.setUpPeriodicSync(
        context,
        inputId,
        ComponentName(context, SampleJobService::class.java)
)

Java

EpgSyncJobService.setUpPeriodicSync(context, inputId,
        new ComponentName(context, SampleJobService.class));

TIF 附屬程式庫提供了 requestImmediateSync(),可讓您指定 只需幾毫秒即可同步處理頻道資料預設方式會同步處理一小時的 指派的管道資料

TIF 隨附程式庫也提供 setUpPeriodicSync(),可讓您指定 要同步處理的管道資料,以及定期同步作業的發生頻率。 預設方法每 12 小時會同步處理 48 小時的頻道資料。

如要進一步瞭解頻道資料和電子節目表,請參閱 使用頻道資料

處理調整要求和媒體播放

使用者選取特定頻道時,系統電視應用程式會使用 「Session」,由您的應用程式建立,訂閱至要求的頻道 並播放內容TIF 輔助程式庫提供 您能擴充的類別,處理來自系統的頻道和工作階段呼叫。

您的 BaseTvInputService 子類別會建立工作階段來處理 調整要求覆寫 onCreateSession() 方法時,建立從 BaseTvInputService.Session 類別,然後呼叫 改為執行新工作階段。super.sessionCreated()。在下列項目中 例如,onCreateSession() 會傳回 這個 RichTvInputSessionImpl 物件 BaseTvInputService.Session:

Kotlin

override fun onCreateSession(inputId: String): Session =
        RichTvInputSessionImpl(this, inputId).apply {
            setOverlayViewEnabled(true)
        }

Java

@Override
public final Session onCreateSession(String inputId) {
    RichTvInputSessionImpl session = new RichTvInputSessionImpl(this, inputId);
    session.setOverlayViewEnabled(true);
    return session;
}

當使用者使用系統 TV 應用程式開始觀看你的其中一個頻道時, 系統會呼叫工作階段的 onPlayChannel() 方法。覆寫 此方法。 就能開始播放。

接著,系統會取得目前排定的程式,並呼叫 工作階段的 onPlayProgram() 方法,指定程式 資訊及開始時間,以毫秒為單位。使用 開始播放程式的 TvPlayer 介面。

媒體播放器程式碼應導入 TvPlayer 來處理 特定播放事件TvPlayer 類別會處理功能 例如時間移轉控制項,且不會增加 BaseTvInputService 實作。

在工作階段的 getTvPlayer() 方法中,傳回 導入 TvPlayer 的媒體播放器 電視輸入服務範例應用程式會導入採用 ExoPlayer

使用電視輸入架構建立電視輸入服務

如果電視輸入服務無法使用 TIF 輔助程式庫,您就需要 來實作下列元件:

您還需要執行下列操作:

  1. 在資訊清單中宣告電視輸入服務, 於「聲明電視輸入服務 資訊清單
  2. 建立服務中繼資料檔案。
  3. 建立並註冊您的頻道和計劃資訊。
  4. 建立設定活動。

定義電視輸入服務

針對服務,您可以擴充 TvInputService 類別。A 罩杯 TvInputService 實作為 將服務繫結至「繫結服務」 是繫結至該用戶端的用戶端。服務生命週期方法 實作方法如圖 1 所示

onCreate() 方法會初始化並啟動 HandlerThread,提供與 UI 執行緒分開的程序執行緒 處理系統導向的動作在以下範例中,onCreate() 方法會初始化 CaptioningManager 並準備處理 ACTION_BLOCKED_RATINGS_CHANGEDACTION_PARENTAL_CONTROLS_ENABLED_CHANGED 項動作這些 動作是指使用者變更家長監護設定時觸發的系統意圖,以及 封鎖的評分清單會有異動。

Kotlin

override fun onCreate() {
    super.onCreate()
    handlerThread = HandlerThread(javaClass.simpleName).apply {
        start()
    }
    dbHandler = Handler(handlerThread.looper)
    handler = Handler()
    captioningManager = getSystemService(Context.CAPTIONING_SERVICE) as CaptioningManager

    setTheme(android.R.style.Theme_Holo_Light_NoActionBar)

    sessions = mutableListOf<BaseTvInputSessionImpl>()
    val intentFilter = IntentFilter().apply {
        addAction(TvInputManager.ACTION_BLOCKED_RATINGS_CHANGED)
        addAction(TvInputManager.ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED)
    }
    registerReceiver(broadcastReceiver, intentFilter)
}

Java

@Override
public void onCreate() {
    super.onCreate();
    handlerThread = new HandlerThread(getClass()
      .getSimpleName());
    handlerThread.start();
    dbHandler = new Handler(handlerThread.getLooper());
    handler = new Handler();
    captioningManager = (CaptioningManager)
      getSystemService(Context.CAPTIONING_SERVICE);

    setTheme(android.R.style.Theme_Holo_Light_NoActionBar);

    sessions = new ArrayList<BaseTvInputSessionImpl>();
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(TvInputManager
      .ACTION_BLOCKED_RATINGS_CHANGED);
    intentFilter.addAction(TvInputManager
      .ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED);
    registerReceiver(broadcastReceiver, intentFilter);
}

圖 1:TvInputService 生命週期。

詳情請參閱 控管內容,進一步瞭解如何處理遭封鎖的內容及提供 家長監護。請參閱 TvInputManager,進一步瞭解有哪些系統驅動動作, 建議你在電視輸入服務中處理相關問題

TvInputService 會建立一個 實作 Handler.CallbackTvInputService.Session 處理玩家狀態變更取代為 onSetSurface(), TvInputService.Session 使用 Surface 設定 影片內容請參閱「將玩家與途徑整合」一文。 ,進一步瞭解如何使用 Surface 轉譯影片。

TvInputService.Session 會處理 onTune() 事件,並通知系統 TV 應用程式內容變更, 內容中繼資料。如需這些 notify() 方法的說明,請參閱 控制內容處理音軌選取作業 其他部分

定義設定活動

系統 TV 應用程式會配合您為電視輸入裝置定義的設定活動。 設定活動為必要項目,且必須為系統資料庫提供至少一筆頻道記錄。 系統電視應用程式找不到電視輸入來源的頻道時,會叫用設定活動。

設定活動會向系統電視應用程式說明,透過電視提供的頻道 方法如下一堂課所示 建立 和更新頻道資料

其他參考資料