处理 TV 硬件

TV 硬件与其他 Android 设备截然不同。电视不包含其他 Android 设备上的一些硬件功能,例如触摸屏、摄像头和 GPS 接收器。电视还完全依赖于辅助硬件设备:用户必须使用遥控器或游戏手柄才能与电视应用互动。(如需了解各种输入法,请参阅管理电视控制器。)

在构建电视应用时,请仔细考虑电视硬件的硬件限制和要求。检查您的应用是否在 TV 上运行,并处理不受支持的硬件功能。

检查 TV 设备

如果您要构建一款可在 TV 设备和其他设备上运行的应用,则可能需要检查应用在何种设备上运行,并调整应用的操作。例如,如果您有一款可通过 Intent 启动的应用,请检查设备属性,以确定是启动面向 TV 的 activity 还是启动手机 activity。

如需确定您的应用是否在 TV 设备上运行,建议使用 PackageManager.hasSystemFeature 方法检查设备是否在电视模式下运行。以下示例代码展示了如何检查应用是否在电视设备上运行:

Kotlin

const val TAG = "DeviceTypeRuntimeCheck"

val isTelevision = packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
if (isTelevision) {
    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";

boolean isTelevision = getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
if (isTelevision) {
    Log.d(TAG, "Running on a TV Device");
} else {
    Log.d(TAG, "Running on a non-TV Device");
}

处理不支持的硬件功能

根据应用的设计和功能,您或许能够解决某些硬件功能不可用的问题。本部分讨论了通常不适用于 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
麦克风 android.hardware.microphone
传感器 android.hardware.sensor
纵向屏幕 android.hardware.screen.portrait

注意:某些电视控制器配有麦克风,但与此处所述的麦克风硬件功能说明不同。完全支持控制器麦克风。

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

声明电视的硬件要求

Android 应用可以在应用清单中声明硬件功能要求,以确保不会安装在不提供这些功能的设备上。如果您要扩展现有应用以在电视上使用,请仔细检查应用的清单,看看是否有任何硬件要求声明可能会阻止应用安装到电视设备上。

如果您的应用使用了电视不支持的硬件功能(例如触摸屏或摄像头),但该应用不使用这些功能也可运行,请修改应用的清单,指明这些功能并非该应用必需的功能。以下清单代码段演示了如何声明您的应用不需要电视设备上不提供的硬件功能,但在非电视设备上会使用这些功能:

<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"/>
<!-- Some TV devices have an ethernet connection only -->
<uses-feature android:name="android.hardware.wifi"
        android:required="false"/>

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

所有要在电视设备上使用的应用都必须声明不需要触摸屏功能,如电视应用使用入门中所述。如果您的应用通常会使用电视设备不支持的一项或多项功能,请在清单中将这些功能的 android:required 属性设置更改为 false。

注意:通过将硬件功能的值设置为 true 来声明该功能为必需功能,会阻止您的应用安装在电视设备上或显示在 Android TV 主屏幕启动器中。

注意隐含硬件功能的权限

某些 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 或更低版本)

ACCESS_WIFI_STATE
CHANGE_WIFI_STATE

android.hardware.wifi

部分电视设备仅支持以太网连接。

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

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

将硬件功能设为可选后,您必须在运行时检查这些功能是否可用,然后调整应用的行为。下一部分将讨论如何检查硬件功能,并建议了一些更改应用行为的方法。

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

检查硬件功能

Android 框架可以告知您运行应用的设备上是否不提供硬件功能。使用 hasSystemFeature(String) 方法在运行时检查特定功能。此方法接受一个字符串参数,用于指定要检查的功能。

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

Kotlin

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

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

Java

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

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

触摸屏

大多数电视设备都没有触摸屏或指针输入功能,完全依赖方向键 (D-pad) 遥控器进行导航。TV 应用必须始终支持方向键遥控器。

如需详细了解如何使用适合电视的控件正确支持导航,请参阅电视导航。

声明触控支持

某些电视设备支持指针遥控器和触摸屏显示器。您的应用可以支持点击、悬停和滚动互动(就像在移动设备上一样),以便在支持这些互动的设备上提供更好的体验。

如果您的应用支持触控模式,您可以在 AndroidManifest.xml 中的 <application> 或 <activity> 元素内添加设置为 true 的 android.software.leanback.supports_touch <property> 元素,从而为整个应用或单个 activity 声明触控支持:

<application ...>
    <property
        android:name="android.software.leanback.supports_touch"
        android:value="true|false" />
    ...
</application>

注意:在支持指向遥控器(例如空中鼠标或触控板)的设备上,启用此功能会启用光标和触摸模式,而不是依赖于平台兼容性模拟。activity 级声明会替换该 activity 的应用级声明。省略此属性默认为 false。

相机

虽然电视通常没有摄像头,但您仍然可以在电视上提供与摄影相关的应用。例如,如果您有一款可拍摄、查看和编辑照片的应用,则可以针对电视停用其拍照功能,但仍允许用户查看甚至编辑照片。如果您决定让相机相关应用在电视上运行,请在应用清单中添加以下功能声明:

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

如果您允许应用在没有相机的情况下运行,请向应用添加代码,以检测相机功能是否可用,并对应用的运行进行调整。以下代码示例演示了如何检测是否存在相机:

Kotlin

// Check whether 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 whether 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

电视是固定式室内设备,没有内置全球定位系统 (GPS) 接收器。如果您的应用使用位置信息,您仍然可以让用户搜索位置信息,或使用静态位置信息提供程序,例如在电视设备设置期间配置的邮政编码。

Kotlin

// Request a static location from the location manager.
val locationManager = this.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val location = locationManager.getLastKnownLocation("static")
if (location == null) {
    Log.e(TAG, "Location is null")
    return
}

// Attempt to get postal code from the static location object.
val geocoder = Geocoder(this)
val address: Address? =
        try {
            geocoder.getFromLocation(location.latitude, location.longitude, 1)?.firstOrNull()
                    ?.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 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("Postal code", address.getPostalCode());

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

在低功耗模式下暂停播放

某些电视设备支持在用户关闭设备时进入低功耗模式。设备不会关机,而是会停用显示屏,并让 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 生命周期。