处理 TV 硬件

TV 硬件与其他 Android 设备截然不同。TV 不提供其他 Android 设备上提供的一些硬件功能,如触摸屏、相机和 GPS 接收器。此外,TV 还完全依赖于辅助硬件设备。用户必须使用遥控器或游戏手柄才能与 TV 应用进行交互。构建 TV 应用时,您必须仔细考虑在 TV 硬件上运行应用的硬件限制和要求。

本课介绍如何检查您的应用是否正在 TV 上运行,以及如何处理不支持的硬件功能。要了解各种输入法,请参阅管理 TV 控制器

检查 TV 设备

如果您在构建一款在 TV 设备和其他设备上都能运行的应用,可能需要检查您的应用正在什么类型的设备上运行,并相应调整应用的工作方式。例如,如果您的一款应用可通过 Intent 启动,则您的应用应通过检查设备属性来确定它是应该启动面向 TV 的 Activity 还是手机 Activity。

要确定您的应用是否正在 TV 设备上运行,推荐的做法是使用 UiModeManager.getCurrentModeType() 方法来检查该设备是否正在电视模式下运行。以下示例代码向您展示了如何检查您的应用是否正在 TV 设备上运行:

Kotlin

    const val TAG = "DeviceTypeRuntimeCheck"

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

Java

    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");
    }
    

处理不支持的硬件功能

根据应用的设计和功能,您或许能够解决某些硬件功能无法使用的问题。本部分介绍哪些硬件功能通常不适用于 TV,以及如何检测缺少的硬件功能,并就这些功能的替代方案提供了建议。

不支持的 TV 硬件功能

TV 的用途不同于其他设备,因此它们没有其他 Android 设备通常具备的硬件功能。因此,Android 系统在 TV 设备上不支持以下功能:

硬件 Android 功能描述符
触摸屏 android.hardware.touchscreen
触摸屏模拟器 android.hardware.faketouch
电话 android.hardware.telephony
相机 android.hardware.camera
近距离无线通信 (NFC) android.hardware.nfc
GPS android.hardware.location.gps
麦克风 [1] android.hardware.microphone
传感器 android.hardware.sensor
纵向屏幕 android.hardware.screen.portrait

[1] 某些 TV 控制器具有麦克风,但与此处所述的麦克风硬件功能并不相同。控制器麦克风是完全受支持的。

如需查看功能、子功能及其描述符的完整列表,请参阅功能参考

声明对 TV 的硬件要求

Android 应用可以在应用清单中声明硬件功能要求,以确保用户不会将其安装在不提供这些功能的设备上。如果您要扩展现有应用以便在 TV 上使用,请仔细检查应用的清单中是否声明了任何可能会导致该应用无法安装在 TV 设备上的硬件要求。

如果您的应用使用 TV 上不具备的硬件功能(如触摸屏或相机),但不使用这些功能仍可运行,请修改应用的清单,以指明这些并非应用必需的功能。以下清单代码段展示了如何声明 TV 设备上不具备的硬件功能并非您的应用必需的功能,尽管您的应用可能会在 TV 以外的其他设备上使用这些功能:

    <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"/>
    

注意:某些功能具有子功能,比如 android.hardware.camera.front,如功能参考中所述。请务必将您的应用中也使用的任何子功能标记为 required="false"

所有用于 TV 设备的应用都必须声明触摸屏功能并非必需功能,如 TV 应用使用入门中所述。如果您的应用正常情况下使用上面列出的一项或多项功能,请在清单中将这些功能的 android:required 属性设置更改为 false

注意:如果将硬件功能的值设为 true 来将其声明为必需功能,就会导致您的应用无法安装在 TV 设备上或出现在 Android TV 主屏幕启动器中。

在您决定使硬件功能成为应用的可选功能后,必须在运行时检查这些功能的可用性,然后相应调整应用的行为。下一部分介绍如何检查硬件功能,并就更改应用行为的方法提供了一些建议。

如需详细了解如何在清单中过滤和声明功能,请参阅 uses-feature 指南。

声明隐含硬件功能的权限

某些 uses-permission 清单声明隐含硬件功能。此行为意味着,在您的应用清单中请求某些权限可能会导致您的应用无法在 TV 设备上安装和使用。下列通常请求的权限会形成隐式硬件功能要求:

权限 隐含的硬件功能
RECORD_AUDIO android.hardware.microphone
CAMERA android.hardware.camera
android.hardware.camera.autofocus
ACCESS_COARSE_LOCATION

android.hardware.location

android.hardware.location.network(仅限目标 API 级别 20 或更低级别。)

ACCESS_FINE_LOCATION

android.hardware.location

android.hardware.location.gps(仅限目标 API 级别 20 或更低级别。)

如需查看隐含硬件功能要求的权限请求的完整列表,请参阅 uses-feature 指南。如果您的应用请求上面列出的某项功能,请在清单中为这项隐含的硬件功能添加 uses-feature 声明,指明它并非必需功能 (android:required="false")。

注意:如果您的应用以 Android 5.0(API 级别 21)或更高版本为目标平台且使用 ACCESS_COARSE_LOCATIONACCESS_FINE_LOCATION 权限,那么即使 TV 设备没有网卡或 GPS 接收器,用户仍然可以在 TV 设备上安装您的应用。

检查硬件功能

如果运行您的应用的设备不具备某些硬件功能,Android 框架可以告诉您。您可以使用 hasSystemFeature(String) 方法在运行时检查特定功能。此方法带有一个字符串参数,用于指定您要检查的功能。

以下代码示例演示了如何在运行时检测硬件功能的可用性:

Kotlin

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

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

Java

    // 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 都没有触摸屏,因此 Android 没有为 TV 设备提供触摸屏交互支持。而且,使用触摸屏与观看环境并不协调,因为用户就坐位置与显示屏距离大约 3 米左右。请确保您的界面元素和文本不要求或暗示使用触摸屏。

在 TV 设备上,您应该通过支持使用 TV 遥控器上的方向键进行导航,将您的应用设计为采用这种交互模式。如需详细了解如何正确支持使用 TV 易用型遥控器进行导航,请参阅创建 TV 导航

相机

尽管 TV 通常不配备相机,但您仍然可以在 TV 上提供与摄影有关的应用。例如,如果您有一款拍摄、查看和编辑照片的应用,您可以在 TV 上停用其照片拍摄功能,同时仍允许用户查看甚至编辑照片。如果您决定让相机相关应用能够在 TV 上使用,请在应用清单中添加以下功能声明:

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

如果您想让应用能够在没有相机的情况下运行,请为您的应用添加一段代码,用于检测相机功能是否可用并相应调整应用的工作方式。以下代码示例演示了如何检测是否存在相机:

Kotlin

    // Check if the camera hardware feature is available.
    if (packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
        Log.d("Camera test", "Camera available!")
    } else {
        Log.d("Camera test", "No camera available. View and edit features only.")
    }
    

Java

    // Check if the camera hardware feature is available.
    if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
        Log.d("Camera test", "Camera available!");
    } else {
        Log.d("Camera test", "No camera available. View and edit features only.");
    }
    

GPS

TV 是位置固定的室内设备,并未内置全球定位系统 (GPS) 接收器。如果您的应用使用位置信息,您仍可允许用户搜寻位置,或者使用静态位置提供程序,如在 TV 设备设置期间配置的邮政编码。

Kotlin

    // Request a static location from the location manager
    val locationManager = this.getSystemService(Context.LOCATION_SERVICE) as LocationManager
    val location: Location = locationManager.getLastKnownLocation("static")

    // Attempt to get postal or zip code from the static location object
    val geocoder = Geocoder(this)
    val address: Address? =
            try {
                geocoder.getFromLocation(location.latitude, location.longitude, 1)[0]
                        .apply {
                            Log.d(TAG, postalCode)
                        }
            } catch (e: IOException) {
                Log.e(TAG, "Geocoder error", e)
                null
            }
    

Java

    // Request a static location from the location manager
    LocationManager locationManager = (LocationManager) this.getSystemService(
            Context.LOCATION_SERVICE);
    Location location = locationManager.getLastKnownLocation("static");

    // Attempt to get postal or zip code from the static location object
    Geocoder geocoder = new Geocoder(this);
    Address address = null;
    try {
      address = geocoder.getFromLocation(location.getLatitude(),
              location.getLongitude(), 1).get(0);
      Log.d("Zip code", address.getPostalCode());

    } catch (IOException e) {
      Log.e(TAG, "Geocoder error", e);
    }
    

在低功耗模式下暂停播放

某些 TV 设备在用户关闭设备时支持低功耗模式。设备不会关闭,而是停用显示屏并使 Android TV 在后台运行。在此模式下仍会启用音频输出,因此当设备处于低功耗模式时,您的应用应停止当前正在播放的任何内容。

要避免在低功耗模式下播放,请替换 onStop() 并停止当前正在播放的任何内容:

Kotlin

    override fun onStop() {
        // App-specific method to stop playback
        stopPlayback()
        super.onStop()
    }
    

Java

    @Override
    public void onStop() {
      // App-specific method to stop playback
      stopPlayback();
      super.onStop();
    }
    

当用户重新打开电源时,如果您的应用是正在运行的前台应用,系统会调用 onStart()。如需详细了解如何启动和停止 Activity,请参阅 Activity 生命周期