Android TV開發(fā)之準備工作

從事Android TV應用開發(fā)有一段日子了,今天開始講述如何利用Google提供的Leanback庫實現(xiàn)Android TV開發(fā),歡迎感興趣的朋友一起交流。
其實TV應用使用的結(jié)構(gòu)與手機和平板電腦的應用相同,這也意味著您可以根據(jù)自身對 Android 應用的既有知識創(chuàng)建新的 TV 應用,也可以擴展現(xiàn)有應用,使其支持 TV 設(shè)備。不過,TV 與手機和平板電腦設(shè)備在用戶交互模式上差異很大。首先就是操控方式的改變,從觸摸變成了遙控器;其次就是距離的變化。為了讓您的應用在 TV 設(shè)備上取得成功,您必須設(shè)計新的布局,使用戶能在距離電視 10 英尺的地方輕松看清楚屏幕內(nèi)容,并且只需使用方向鍵和選擇按鈕便可完成導航。

設(shè)置TV項目

本部分介紹如何將現(xiàn)有 Android 應用改造成能在 TV 設(shè)備上運行,或創(chuàng)建新應用。如果您已有 Android 應用,那么添加 Android TV 支持后,您就能在現(xiàn)有的應用架構(gòu)基礎(chǔ)上設(shè)計適用于 TV 的界面。

申明TVActivity

目標平臺為 TV 設(shè)備的應用必須在其清單中聲明 TV 啟動器 Activity。它使用 CATEGORY_LEANBACK_LAUNCHER intent 過濾器來執(zhí)行此操作。此過濾器可將您的應用標識為支持 TV 平臺,并讓 Google Play 將其識別為 TV 應用。當用戶在其 TV 主屏幕上選擇您的應用時,此 intent 可確定要啟動的 Activity。

<application
      android:banner="@drawable/banner" >
      ...
      <activity
        android:name="com.example.android.MainActivity"
        android:label="@string/app_name" >

        <intent-filter>
          <action android:name="android.intent.action.MAIN" />
          <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
      </activity>

      <activity
        android:name="com.example.android.TvActivity"
        android:label="@string/app_name"
        android:theme="@style/Theme.Leanback">

        <intent-filter>
          <action android:name="android.intent.action.MAIN" />
          <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
        </intent-filter>

      </activity>
    </application> 

本例中的第二個 Activity 清單條目將該 Activity 指定為要在 TV 設(shè)備上啟動的 Activity。如果手機和TV都是用MainActivity作為啟動頁面的話,可以直接增加帶有CATEGORY_LEANBACK_LAUNCHER的intent-filter標簽,代碼如下:

<application
      android:banner="@drawable/banner" >
      ...
      <activity
        android:name="com.example.android.MainActivity"
        android:label="@string/app_name" >

        <intent-filter>
          <action android:name="android.intent.action.MAIN" />
          <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>

        <intent-filter>
          <action android:name="android.intent.action.MAIN" />
          <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
        </intent-filter>
      </activity>
    </application> 

注意:如果您不在應用中包含 CATEGORY_LEANBACK_LAUNCHER intent 過濾器,那么用戶在 TV 設(shè)備上運行 Google Play 時將看不到您的應用。此外,如果您的應用沒有此過濾器,那么當您使用開發(fā)者工具將其加載到 TV 設(shè)備上時,該應用不會出現(xiàn)在 TV 界面中。

聲明 Leanback 支持

聲明您的應用使用 Android TV 所要求的 Leanback 界面。如果您要開發(fā)一款在移動設(shè)備(手機、穿戴式設(shè)備、平板電腦等)以及 Android TV 上都可運行的應用,請將 required 屬性值設(shè)為 false。如果您將 required 屬性值設(shè)為 true,您的應用將只能在使用 Leanback 界面的設(shè)備上運行。

    <manifest>
        <uses-feature android:name="android.software.leanback"
            android:required="false" />
        ...
    </manifest>

將觸摸屏聲明為非必備條件

目標平臺為 TV 設(shè)備的應用不依賴于觸摸屏進行輸入。為明確這一點,您的 TV 應用的清單必須聲明 android.hardware.touchscreen 功能為非必備功能。此設(shè)置會將您的應用標識為能夠在 TV 設(shè)備上工作,這也是您的應用在 Google Play 中被視為 TV 應用的必要條件。以下代碼示例展示了如何添加此清單聲明:

    <manifest>
        <uses-feature android:name="android.hardware.touchscreen"
                  android:required="false" />
        ...
    </manifest>

注意:您必須在應用清單中聲明觸摸屏并非必要條件(如本示例代碼中所示),否則您的應用將不會出現(xiàn)在 TV 設(shè)備上的 Google Play 中。

提供主屏幕橫幅

如果應用包含 Leanback 啟動器 intent 過濾器,那么它必須針對每種本地化語言提供一張主屏幕橫幅圖片。橫幅是顯示在主屏幕的應用和游戲行中的應用啟動點。如需向您的應用添加橫幅,請在清單中描述橫幅,如下所示:

    <application
        ...
        android:banner="@drawable/banner" >

        ...
    </application>

您可以將 android:banner 屬性與 <application>標記一起使用,為所有應用 Activity 提供默認橫幅,也可以將其與 <activity>標記一起使用,為特定 Activity 提供橫幅。橫幅應該是 xhdpi 資源,尺寸為 320 x 180 像素。文本必須包含在圖片中。
如果您的應用支持多種語言,對于帶文本的橫幅,您必須針對支持的每種語言提供單獨的版本。

更改啟動器顏色

當 TV 應用啟動時,系統(tǒng)會顯示動畫,就像一個不斷膨脹的實心圓。要自定義此動畫的顏色,請將 TV 應用或 Activity 的 android:colorPrimary 屬性設(shè)為特定顏色。此外,還應將另外兩個過渡重疊屬性設(shè)為 true,如主題背景資源 XML 文件中的以下代碼段所示:

    <resources>
        <style ... >
          <item name="android:colorPrimary">@color/primary</item>
          <item name="android:windowAllowReturnTransitionOverlap">true</item>
          <item name="android:windowAllowEnterTransitionOverlap">true</item>
        </style>
    </resources>

添加TV庫

Jetpack 包含用于 TV 應用的androidx軟件包庫。這些庫為 TV 設(shè)備提供了 API 和界面微件。

  • androidx.leanback.app
  • androidx.leanback.database
  • androidx.leanback.graphics
  • androidx.leanback.media
  • androidx.leanback.preference
  • androidx.leanback.system
  • androidx.leanback.widget
  • androidx.leanback.widget.picker

處理TV硬件

TV 硬件與其他 Android 設(shè)備截然不同。TV 不提供其他 Android 設(shè)備上提供的一些硬件功能,如觸摸屏、相機和 GPS 接收器。此外,TV 還完全依賴于輔助硬件設(shè)備。用戶必須使用遙控器或游戲手柄才能與 TV 應用進行交互。構(gòu)建 TV 應用時,您必須仔細考慮在 TV 硬件上運行應用的硬件限制和要求。

檢查TV設(shè)備

如果您在開發(fā)一款在 TV 設(shè)備和其他設(shè)備上都能運行的應用,可能需要檢查運行您的應用的設(shè)備類型,并相應調(diào)整應用的工作方式。例如,如果您開發(fā)的應用可通過 Intent 啟動,您的應用應通過檢查設(shè)備屬性來確定它是應該啟動面向 TV 的 Activity 還是手機 Activity。
如需確定您的應用是否正在 TV 設(shè)備上運行,推薦的做法是使用 UiModeManager.getCurrentModeType() 方法來檢查該設(shè)備是否正在電視模式下運行。以下示例代碼向您展示了如何檢查您的應用是否正在 TV 設(shè)備上運行:

    public static final String TAG = "DeviceTypeRuntimeCheck";

    UiModeManager uiModeManager = (UiModeManager) getSystemService(UI_MODE_SERVICE);
    if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
        Log.d(TAG, "Running on a TV Device");
    } else {
        Log.d(TAG, "Running on a non-TV Device");
    }

上述的API只能用于判斷系統(tǒng)是基于Android TV源碼編譯生成的ROM,那對于那些Android TV或者機頂盒是基于手機或者平板模式修改而來的應該怎么判斷呢?彩蛋在篇尾?。。?/em>

處理不支持的硬件功能

根據(jù)應用的設(shè)計和功能,您或許能夠解決某些硬件功能無法使用的問題。本部分介紹哪些硬件功能通常不適用于 TV,以及如何檢測缺少的硬件功能,并就這些功能的替代方案提供了建議。

不支持的 TV 硬件功能

TV 的用途不同于其他設(shè)備,因此它們沒有其他 Android 設(shè)備通常具備的硬件功能。因此,Android 系統(tǒng)在 TV 設(shè)備上不支持以下功能:

  • 觸摸屏android.hardware.touchscreen
  • 觸摸屏模擬器 android.hardware.faketouch
  • 電話 android.hardware.telephony
  • 相機 android.hardware.camera
  • 近距離無線通信 (NFC) android.hardware.nfc
  • GPS android.hardware.location.gps
  • 麥克風 android.hardware.microphone
  • 傳感器 android.hardware.sensor
  • 縱向屏幕 android.hardware.screen.portrait

聲明對 TV 的硬件要求

Android 應用可以在應用清單中聲明硬件功能要求,以確保用戶不會將其安裝在不提供這些功能的設(shè)備上。如果您要擴展現(xiàn)有應用以便在 TV 上使用,請仔細檢查應用的清單中是否聲明了任何可能會導致該應用無法安裝在 TV 設(shè)備上的硬件要求。

如果您的應用使用了 TV 上不提供的硬件功能(如觸摸屏或相機),但不使用這些功能仍可運行,請修改應用的清單文件,以指明這些功能并非應用必需的功能。以下這段清單文件代碼演示了如何聲明您的應用不要求具備 TV 設(shè)備上不提供的硬件功能,盡管您的應用可能會在非 TV 設(shè)備上使用這些功能:

    <uses-feature android:name="android.hardware.touchscreen"
            android:required="false"/>
    <uses-feature android:name="android.hardware.faketouch"
            android:required="false"/>
    <uses-feature android:name="android.hardware.telephony"
            android:required="false"/>
    <uses-feature android:name="android.hardware.camera"
            android:required="false"/>
    <uses-feature android:name="android.hardware.nfc"
            android:required="false"/>
    <uses-feature android:name="android.hardware.location.gps"
            android:required="false"/>
    <uses-feature android:name="android.hardware.microphone"
            android:required="false"/>
    <uses-feature android:name="android.hardware.sensor"
            android:required="false"/>

注意:如果將硬件功能的值設(shè)為 true 來將其聲明為必需功能,就會導致您的應用無法安裝在 TV 設(shè)備上或出現(xiàn)在 Android TV 主屏幕啟動器中。

檢查硬件功能

如果運行您的應用的設(shè)備不具備某些硬件功能,Android 框架可以告訴您。您可以使用 hasSystemFeature(String) 方法在運行時檢查特定功能。此方法帶有一個字符串參數(shù),用于指定您要檢查的功能。
以下代碼示例演示了如何在運行時檢測硬件功能的可用性:

    // Check if the telephony hardware feature is available.
    if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
        Log.d("HardwareFeatureTest", "Device can make phone calls");
    }

    // Check if android.hardware.touchscreen feature is available.
    if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) {
        Log.d("HardwareFeatureTest", "Device has a touch screen.");
    }

TV導航和焦點處理

在 TV 設(shè)備上,用戶通過遙控器設(shè)備上的控件進行導航,即使用方向鍵或箭頭鍵來導航。這種類型的控件將移動限定在上、下、左、右四個方向。如需構(gòu)建一款針對 TV 優(yōu)化的出色應用,您提供的導航架構(gòu)必須能讓用戶快速學會如何利用這些有限的控件在您的應用內(nèi)導航。
Android 框架會自動處理布局元素之間的方向?qū)Ш剑虼四ǔo需對應用執(zhí)行任何額外的操作。不過,您應該對通過方向鍵控制器導航進行全面測試,以發(fā)現(xiàn)任何導航問題。請遵循以下準則來測試您應用的導航系統(tǒng)是否能夠在 TV 設(shè)備上與方向鍵很好地搭配使用:

  • 確保用戶可使用方向鍵控制器導航到屏幕上的所有可見控件。
  • 對于獲得焦點的滾動列表,請確??墒褂梅较蜴I的向上鍵和向下鍵滾動列表,并可使用 Enter 鍵選擇列表中的項目。驗證用戶是否可選擇列表中的元素,以及選擇元素時是否列表仍會滾動。
  • 確??丶g的切換簡單明了并且可以預測。

Android 框架會根據(jù)布局中可聚焦元素的相對位置自動應用方向?qū)Ш郊軜?gòu)。您應使用方向鍵控制器在您的應用內(nèi)測試生成的導航架構(gòu)。測試后,如果您決定希望用戶以特定方式在布局中導航,可以為控件設(shè)置顯式方向?qū)Ш健?br> 注意:只有在系統(tǒng)應用的默認順序不太奏效時,才應使用這些屬性來修改導航順序。
下表列出了 Android 界面微件的所有可用導航屬性:

  • nextFocusDown : 定義當用戶向下導航時下一個獲得焦點的視圖。
  • nextFocusLeft :定義當用戶向左導航時下一個獲得焦點的視圖。
  • nextFocusRight : 定義當用戶向右導航時下一個獲得焦點的視圖。
  • nextFocusUp : 定義當用戶向上導航時下一個獲得焦點的視圖。
    以下代碼示例展示了如何定義下一個獲得 TextView 布局對象焦點的控件:
    <TextView android:id="@+id/Category1"
            android:nextFocusDown="@+id/Category2"\>

明確的焦點和選擇

應用的導航架構(gòu)能否在 TV 設(shè)備上發(fā)揮作用取決于用戶判定屏幕上獲得焦點的界面元素方面的便利性。如果您不能明確指示獲得焦點的項目(因此也就無法明確指示用戶可以采取操作的項目),用戶可能很快就會因失望而退出您的應用。出于同一原因,在您的應用啟動后或者處于閑置狀態(tài)的任何時間,必須始終有獲得焦點的項目可供用戶采取操作。
Android 提供了[可繪制對象狀態(tài)列表資源StateList]來實現(xiàn)針對獲得焦點的控件和選定控件的突出顯示。以下代碼示例演示了如何通過為按鈕啟用視覺行為來指示用戶已導航到該控件而且隨后還選擇了它:

    <!-- res/drawable/button.xml -->
    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_pressed="true"
              android:drawable="@drawable/button_pressed" /> <!-- pressed -->
        <item android:state_focused="true"
              android:drawable="@drawable/button_focused" /> <!-- focused -->
        <item android:state_hovered="true"
              android:drawable="@drawable/button_focused" /> <!-- hovered -->
        <item android:drawable="@drawable/button_normal" /> <!-- default -->
    </selector>

以下布局 XML 示例代碼會將上一狀態(tài)列表可繪制對象應用于 Button

    <Button
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:background="@drawable/button" />

UiModeManager只能判斷系統(tǒng)是基于標準的Android TV框架編譯得到的設(shè)備是不是TV設(shè)備,而對于系統(tǒng)是采用手機或者平板框架編譯得到的設(shè)備是無效的。那我們該怎么處理呢?解決方案如下:

// Check if android.hardware.touchscreen feature is available.
        boolean isTouchScreen = getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
        boolean isFakeScreen = getPackageManager().hasSystemFeature(PackageManager.FEATURE_FAKETOUCH);

        UiModeManager uiModeManager = (UiModeManager) getSystemService(UI_MODE_SERVICE);
        boolean isTvDevice = uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION;
        Log.d(TAG, "isFakeScreen:" + isFakeScreen);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
            if (isTvDevice) {
                isTvModel = !isFakeScreen;
            } else {
                isTvModel = (isTouchScreen != isFakeScreen);
            }
            isTvModel = isTvModel && (uiModeManager.getCurrentModeType() != Configuration.UI_MODE_TYPE_WATCH); //TV mode不是手表模式
        } else {
            if (isTvDevice) {
                isTvModel = !isFakeScreen;
            } else {
                isTvModel = (isTouchScreen != isFakeScreen);
            }
        }

這里基本是根據(jù)是觸摸來決定是不是TV設(shè)備,雖然同時取了FEATURE_TOUCHSCREENFEATURE_FAKETOUCH兩個屬性,但是經(jīng)過測試發(fā)現(xiàn)FEATURE_FAKETOUCH會更準確。

到此,我們已經(jīng)做好了開發(fā)Android TV應用的準備工作,包括如何申明TV啟動頁、添加TV橫幅、添加Leanback支持等。接下來讓我們具體學習如何開發(fā)一款TV應用吧!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容