Android 4.3 API

API 级别:18

Android 4.3 (JELLY_BEAN_MR2) 是对 Jelly Bean 版本的更新,为用户和应用提供了新功能 开发者。本文档介绍了 新 API。

作为应用开发者,您应下载 Android 4.3 系统映像 和 SDK 平台(位于 SDK 管理器中)作为 问题。如果您没有运行 Android 4.3 的设备 使用 Android 4.3 系统测试您的应用 映像,以在 Android 模拟器上测试您的应用。 然后,针对 Android 4.3 平台构建应用,以便开始使用 最新的 API。

更新目标 API 级别

为了更好地针对运行 Android 4.3 的设备优化您的应用, 您应将 targetSdkVersion 设置为 "18",将其安装在 Android 4.3 系统映像上; 然后发布包含此更改的更新

您可以在使用 Android 4.3 中的 API 的同时,通过添加 条件,在执行之前检查系统 API 级别 您的minSdkVersion不支持的 API。 要详细了解如何保持向后兼容性,请阅读支持不同 平台版本

Android 支持库中还提供了各种 API,允许您实现 旧版本平台上的新功能

如需详细了解 API 级别的工作原理,请参阅什么是 API 水平?

重要的行为变更

如果您之前发布过 Android 应用,请注意您的应用可能 会受到 Android 4.3 变更的影响。

如果您的应用使用隐式 intent...

您的应用在受限个人资料环境中可能会出现异常。

受限个人资料环境中的用户可能不会 提供所有可用的标准 Android 应用例如,受限个人资料可能具有 网络浏览器和相机应用已停用。因此,您的应用不应对哪些应用 因为如果您在调用 startActivity() 时未使用 验证应用是否能够处理 Intent; 您的应用可能会在受限个人资料中崩溃。

使用隐式 intent 时,您应始终通过调用 resolveActivity()queryIntentActivities() 来验证应用是否可以处理 intent。例如:

Kotlin

val intent = Intent(Intent.ACTION_SEND)
...
if (intent.resolveActivity(packageManager) != null) {
    startActivity(intent)
} else {
    Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show()
}

Java

Intent intent = new Intent(Intent.ACTION_SEND);
...
if (intent.resolveActivity(getPackageManager()) != null) {
    startActivity(intent);
} else {
    Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show();
}

如果您的应用依赖于账号...

您的应用在受限个人资料环境中可能会出现异常。

默认情况下,受限个人资料环境中的用户无权访问用户账号。 如果您的应用依赖于 Account,则应用可能会崩溃或行为 在受限个人资料中使用时会出现意外。

如果您想彻底阻止受限个人资料使用您的应用 应用依赖于敏感的账号信息,请在清单的 <application> 中指定 android:requiredAccountType 属性 元素。

如果您想允许受限个人资料(即使他们无法取得使用权限)继续使用您的应用 自己创建账号,那么您可以停用需要使用账号的应用功能 或允许受限个人资料访问主要用户创建的账号。有关 请参阅本节 支持受限个人资料中的账号

如果您的应用使用 VideoView...

您的视频在 Android 4.3 设备上可能会变小。

在以前的 Android 版本中,VideoView widget 错误地 计算出 layout_heightlayout_width"wrap_content" 值,使其与 "match_parent" 的值相同。因此,虽然之前使用 "wrap_content" 设置高度或宽度,但可能已经提供了您所需的视频布局, 否则,在 Android 4.3 及更高版本的设备上,视频可能会小得多。要解决此问题,请将 与"match_parent""wrap_content",并验证你的视频在 Android 4.3 及更低版本。

受限个人资料

在 Android 平板电脑上,用户现在可以根据主要用户创建受限个人资料。 用户创建受限个人资料后,可以启用限制,例如哪些应用 具体数据Android 4.3 中的一组新 API 还允许您构建 您开发的应用的限制设置。例如,通过使用新 API,您可以 当您的应用在移动应用中运行时, 受限个人资料环境

供用户控制您制定的限制的界面由系统的 “Settings”应用。若要向用户显示应用的限制设置,请执行以下操作: 您必须通过创建用于接收 ACTION_GET_RESTRICTION_ENTRIES intent 的 BroadcastReceiver 来声明应用提供的限制。系统会调用此 intent 来查询 然后构建界面以允许主要用户执行以下操作: 为每个受限个人资料管理限制。

在以下内容的 onReceive() 方法中, BroadcastReceiver,则必须为应用提供的每个限制创建一个 RestrictionEntry。每个 RestrictionEntry 都定义了限制标题、说明和 以下数据类型:

然后,将所有 RestrictionEntry 对象放入 ArrayList 中,并将其作为 EXTRA_RESTRICTIONS_LIST extra。

系统在“设置”应用中为应用的限制创建界面,并保存每个界面 使用您为每个 RestrictionEntry 提供的唯一密钥进行限制 对象。当用户打开您的应用时,您可以通过以下方式查询任何当前限制: 正在调用 getApplicationRestrictions()。 这将返回一个 Bundle,其中包含每个限制的键值对 使用 RestrictionEntry 对象定义的事件。

如果要提供无法通过布尔值、单个 和多选值,那么您可以创建一个 Activity,在该 Activity 中,用户可以指定 并允许用户通过限制设置打开相应 activity。在 广播接收器,请添加 EXTRA_RESTRICTIONS_INTENT extra 在结果 Bundle 中找到。此 extra 必须指定 Intent 指示要启动的 Activity 类(使用 putParcelable() 方法使用 intent 传递 EXTRA_RESTRICTIONS_INTENT)。 当主要用户进入您的 activity 以设置自定义限制时,您的 然后,activity 必须使用 EXTRA_RESTRICTIONS_LISTEXTRA_RESTRICTIONS_BUNDLE 键,具体取决于您是否指定 RestrictionEntry 对象或键值对。

支持受限个人资料中的账号

添加到主要用户的任何账号都可以用于受限个人资料,但 默认情况下,您无法通过 AccountManager API 访问账号。 如果您在受限模式下尝试添加AccountManager账号 则您会收到失败结果。由于存在这些限制,您有以下限制: 三个选项:

  • 允许通过受限个人资料访问所有者账号。

    要从受限个人资料访问账号,您必须将 android:restrictedAccountType 属性添加到 <application> 标记中:

    <application ...
        android:restrictedAccountType="com.example.account.type" >
    

    注意:启用此属性后, 从受限个人资料访问主要用户账号的应用权限。因此,您应该允许 仅当应用显示的信息不会泄露个人身份信息时 个人身份信息 (PII) 的。主服务器 用户,您的应用会向其账号授予受限个人资料,因此应明确告知用户 账号访问权限对于应用的功能非常重要。如果可能的话,您还应该 为主要用户提供足够的限制控制功能,从而确定对账号的访问权限 。

  • 在无法修改账号时停用某些功能。

    如果您想使用账号,但实际上并不需要为应用的主要功能提供账号 ,您可以检查账号是否可用,并在不可用时停用某些功能。 您应首先检查是否有可用的现有账号。如果没有,则查询 您可以通过调用 getUserRestrictions() 来创建新账号,并在结果中查看 DISALLOW_MODIFY_ACCOUNTS extra。如果值为 true, 则您应停用应用中需要访问账号的所有功能。 例如:

    Kotlin

    val um = context.getSystemService(Context.USER_SERVICE) as UserManager
    val restrictions: Bundle = um.userRestrictions
    if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) {
        // cannot add accounts, disable some functionality
    }
    

    Java

    UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
    Bundle restrictions = um.getUserRestrictions();
    if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) {
        // cannot add accounts, disable some functionality
    }
    

    注意:在这种情况下,您需要声明 任何新属性。

  • 在无法访问私人账号时停用您的应用。

    您的应用不可提供给受限个人资料使用,因为这是出于以下原因: 应用依赖于账号中的敏感个人信息(以及受限个人资料 目前无法添加新账号),请添加 将 android:requiredAccountType 属性添加到 <application> 标记:

    <application ...
        android:requiredAccountType="com.example.account.type" >
    

    例如,Gmail 应用使用此属性为受限个人资料、 因为受限个人资料无法访问所有者的个人电子邮件地址。

  • 无线和连接

    蓝牙低功耗(智能支持)

    Android 现通过 android.bluetooth 中的新 API 支持低功耗蓝牙 (LE)。 借助这些新 API,您可以构建能够与低功耗蓝牙通信的 Android 应用 心率监测仪和计步器等外围设备。

    因为蓝牙 LE 是一项硬件功能,并非所有 则您必须在清单文件中声明 <uses-feature> "android.hardware.bluetooth_le" 的元素:

    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
    

    如果您已熟悉 Android 的传统蓝牙 API,请注意使用 Bluetooth LE API 有一些差异。最重要的是,现在您应该将 BluetoothManager 类用于一些高级操作 例如获取 BluetoothAdapter、获取已连接 以及检查设备状态。例如,现在您应通过以下方式获取 BluetoothAdapter:

    Kotlin

    val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
    bluetoothAdapter = bluetoothManager.adapter
    

    Java

    final BluetoothManager bluetoothManager =
            (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
    bluetoothAdapter = bluetoothManager.getAdapter();
    

    如需发现蓝牙 LE 外围设备,请对 BluetoothAdapter 调用 startLeScan(),并向其传递实现 BluetoothAdapter.LeScanCallback 接口的实现。当蓝牙 适配器检测到蓝牙 LE 外围设备时,您的 BluetoothAdapter.LeScanCallback 实现会收到对 onLeScan() 方法。这个 方法会为您提供一个 BluetoothDevice 对象,该对象表示 检测到的设备、设备的 RSSI 值以及包含设备 广告记录。

    如果您只想扫描特定类型的外围设备,则可以改为调用 startLeScan() 并加入 UUID 对象数组,以指定应用支持的 GATT 服务。

    注意:您只能扫描蓝牙 LE 设备 使用之前的 API 扫描传统蓝牙设备。您不能同时扫描 LE 和传统 LE 同时支持蓝牙设备。

    然后,如需连接到蓝牙 LE 外围设备,请在相应设备上调用 connectGatt() BluetoothDevice 对象,向其传递一个实现 BluetoothGattCallback。您的 BluetoothGattCallback 实现会收到有关连接的回调 设备状态和其他事件。现在是onConnectionStateChange() 回调,当该方法将 STATE_CONNECTED 作为新状态传递时,您可以开始与设备通信。

    如要在设备上访问蓝牙功能,您的应用还必须请求特定 蓝牙用户权限。如需更多信息,请参阅蓝牙低功耗 API 指南。

    WLAN 仅扫描模式

    在尝试识别用户的位置时,Android 可能会使用 Wi-Fi 来帮助确定 通过扫描附近的接入点确定位置信息。不过,用户通常会关闭 Wi-Fi, 节约电量,导致位置数据不太准确。Android 现在包含一个 仅扫描模式,允许设备 Wi-Fi 扫描接入点以帮助获取位置信息 从而大大减少电池用量。

    如果您希望获取用户的位置,但 Wi-Fi 当前处于关闭状态,您可以请求 用户可通过使用 ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE 操作调用 startActivity() 以启用 Wi-Fi 仅扫描模式。

    Wi-Fi 配置

    借助新的 WifiEnterpriseConfig API,面向企业的服务 为受管设备自动配置 Wi-Fi。

    快速回复来电

    从 Android 4.0 开始,我们推出了一项名为“快速回复”的功能,使用户可以对传入的 通过即时短信进行通话,而无需接听来电或解锁设备。 在此之前,这些快速消息始终由默认“短信”应用处理。现在,任何应用 可以通过创建一个 Service 来声明处理这些消息的能力 ,并使用针对 ACTION_RESPOND_VIA_MESSAGE 的 intent 过滤器。

    当用户使用快速回复来响应来电时,“电话”应用会发送 包含 URI 的 ACTION_RESPOND_VIA_MESSAGE intent 用于描述接收方(调用方)和 EXTRA_TEXT extra 替换为用户想要发送的消息。当您的服务收到 intent 时,它应该会传递 消息并立即停止自身运行(您的应用不应显示 activity)。

    为了接收此 intent,您必须声明 SEND_RESPOND_VIA_MESSAGE 权限。

    多媒体

    MediaExtractor 和 MediaCodec 增强功能

    Android 现在可让您更轻松地编写自己的动态自适应 符合 ISO/IEC 23009-1 标准的 HTTP (DASH) 播放器流式传输 使用 MediaCodecMediaExtractor 中的现有 API。这些 API 的底层框架已更新,可支持 解析碎片化的 MP4 文件,但您的应用仍负责解析 MPD 元数据 并将各个流传递给 MediaExtractor

    如果要将 DASH 用于加密内容,请注意 getSampleCryptoInfo() 方法会返回描述每个加密媒体结构的 MediaCodec.CryptoInfo 元数据 示例。此外,getPsshInfo() 方法已添加到 MediaExtractor,以便您可以访问 DASH 媒体的 PSSH 元数据。 此方法会返回 UUID 对象到字节的映射,其中 UUID,用于指定加密方案,字节是数据专属 架构。

    媒体数字版权管理

    新的 MediaDrm 类提供模块化的数字版权解决方案 管理 (DRM) 来实现媒体内容的管理,以便将 DRM 问题与媒体播放分开。对于 例如,这种 API 分离可让您播放 Widevine 加密内容,而无需 以便使用 Widevine 媒体格式。此 DRM 解决方案还支持 DASH 通用加密,因此您可以 可以对您的流媒体内容使用各种数字版权管理方案。

    您可以使用 MediaDrm 获取不透明的键请求消息并处理 从服务器发送密钥响应消息,以获取和配置许可。您的应用 负责处理与服务器的网络通信;MediaDrm 类仅提供生成和处理消息的功能。

    MediaDrm API 旨在与 Android 4.1(API 级别 16)中引入的 MediaCodec API; 包括 MediaCodec(用于处理内容编码和解码)、MediaCrypto(用于处理加密的内容)和 MediaExtractor 用于提取内容以及对内容进行多路复用。

    您必须先构建 MediaExtractorMediaCodec 对象。然后,您就可以访问 UUID,通常来自内容中的元数据,并使用它来构建 MediaDrm 对象的实例及其构造函数。

    通过 Surface 进行视频编码

    Android 4.1(API 级别 16)为低层级 API 添加了 MediaCodec 类 媒体内容的编码和解码。对视频进行编码时,Android 4.1 要求您 带有 ByteBuffer 数组的媒体,但 Android 4.3 现在允许您使用 Surface 作为编码器的输入。例如,你可以将输入 或从现有视频文件导入,也可以使用从 OpenGL ES 生成的帧。

    如需使用 Surface 作为编码器的输入,请先为 MediaCodec 调用 configure()。 然后,调用 createInputSurface() 以接收 Surface,然后您就可以在其上流式传输媒体内容。

    例如,您可以将给定的 Surface 用作 OpenGL 的窗口 传递给 eglCreateWindowSurface()。然后,在渲染 Surface 时,调用 eglSwapBuffers() 以将帧传递给 MediaCodec

    如需开始编码,请对 MediaCodec 调用 start()。完成后,调用 signalEndOfInputStream() 终止编码,并对release() Surface

    媒体多路复用

    新的 MediaMuxer 类支持在一个音频流之间实现多路复用 一个视频流这些 API 是 MediaExtractor 的对应项 Android 4.2 中添加了用于对媒体进行去复用(多路复用)媒体的类。

    MediaMuxer.OutputFormat 中定义了支持的输出格式。目前, MP4 是唯一受支持的输出格式,MediaMuxer 目前支持 一次只能有一个音频流和/或一个视频串流。

    MediaMuxer 主要与 MediaCodec 配合使用 因此您可以通过 MediaCodec 执行视频处理,然后保存 通过 MediaMuxer 将内容输出为 MP4 文件。您还可以将 MediaMuxerMediaExtractor 结合使用,以执行 媒体编辑功能,而无需编码或解码。

    RemoteControlClient 的播放进度和调试

    在 Android 4.0(API 级别 14)中,RemoteControlClient 已添加到 从远程控制客户端启用媒体播放控件,例如 锁定屏幕。Android 4.3 现在可让此类控制器显示播放内容 位置和用于拖动播放的控件。如果您已经为自己的 媒体应用与 RemoteControlClient API 相关联,那么您可以允许播放 通过实现两个新接口来轻松擦除数据

    首先,您必须启用 FLAG_KEY_MEDIA_POSITION_UPDATE 标志,方法是将该标志传递给 setTransportControlsFlags()

    然后,实现以下两个新接口:

    RemoteControlClient.OnGetPlaybackPositionListener
    这包括用于请求当前位置的 onGetPlaybackPosition() 回调 。
    RemoteControlClient.OnPlaybackPositionUpdateListener
    其中包括 onPlaybackPositionUpdate() 回调, 当用户使用 遥控器界面。

    使用新位置更新播放内容时,请调用 setPlaybackState() 以指示 新的播放状态、位置和速度

    定义这些接口后,您可以通过调用 setOnGetPlaybackPositionListener()RemoteControlClient 设置这些接口, setPlaybackPositionUpdateListener()

    图形

    对 OpenGL ES 3.0 的支持

    Android 4.3 添加了 Java 接口和对 OpenGL ES 3.0 的原生支持。主要的新功能 包括:

    • 加速高级视觉效果
    • 将高质量 ETC2/EAC 纹理压缩作为标准功能
    • 新版 GLSL ES 着色语言,支持整数和 32 位浮点
    • 高级纹理渲染
    • 对纹理大小和渲染缓冲区格式进行更广泛的标准化

    Android 上 OpenGL ES 3.0 的 Java 接口随 GLES30 一起提供。 使用 OpenGL ES 3.0 时,务必使用 <uses-feature> 标记和 android:glEsVersion 属性。例如:

    <manifest>
        <uses-feature android:glEsVersion="0x00030000" />
        ...
    </manifest>
    

    请务必通过调用 setEGLContextClientVersion() 来指定 OpenGL ES 上下文, 传递 3 作为版本。

    有关使用 OpenGL ES 的详细信息,包括如何检查设备是否支持 在运行时使用 OpenGL ES 版本,请参阅 OpenGL ES API 指南。

    针对可绘制对象的 Mipmapping

    使用 mipmap 作为位图或可绘制对象的源是一种提供 以及各种不同的比例尺度,这对于 在动画播放过程中缩放的图片。

    Android 4.2(API 级别 17)在 Bitmap 中添加了对 mipmap 的支持 类 - 完成上述操作后,Android 会交换 Bitmap 中的 mip 图片。 提供了 mipmap 源代码并启用了 setHasMipMap()。现在,在 Android 4.3 中,您还可以为 BitmapDrawable 对象启用 mipmap,方法是提供 mipmap 资源和 在位图资源文件中设置 android:mipMap 属性,或通过调用 hasMipMap() 进行设置。

    界面

    查看叠加层

    新的 ViewOverlay 类在顶部提供一个透明层 一个 View,您可以在其中添加视觉内容,并且不会影响 布局层次结构您可以通过调用 getOverlay() 获取任何 ViewViewOverlay。叠加层 始终与其主视图(创建它的视图)具有相同的大小和位置, 这样你就可以添加显示在主视图前,但不能扩展内容 托管视图的边界

    在创建映像时,使用 ViewOverlay 特别有用 提供动画效果,例如将视图滑出容器或在屏幕上移动项目 而不会影响视图层次结构不过,由于叠加层的可用区域是 (如果您要为向外移动的视图添加动画效果) 则必须使用父视图中的叠加层,该叠加层具有所需 布局边界。

    为 widget 视图(如 Button)创建叠加层时,您需要 可通过调用 Drawable 对象向叠加层添加 add(Drawable)。如果针对布局视图(例如 RelativeLayout)调用 getOverlay(), 返回的对象是 ViewGroupOverlay。通过 ViewGroupOverlay 类是一个子类 (总共 ViewOverlay),您还可以添加View 调用 add(View) 来传递对象。

    注意:您添加到叠加层中的所有可绘制对象和视图 都只能是可见的它们无法接收焦点事件或输入事件。

    例如,以下代码通过将视图放置到右边以动画方式显示视图。 ,然后在该视图上执行平移动画:

    Kotlin

    val view: View? = findViewById(R.id.view_to_remove)
    val container: ViewGroup? = view?.parent as ViewGroup
    
    container?.apply {
        overlay.add(view)
        ObjectAnimator.ofFloat(view, "translationX", right.toFloat())
                .start()
    }
    

    Java

    View view = findViewById(R.id.view_to_remove);
    ViewGroup container = (ViewGroup) view.getParent();
    container.getOverlay().add(view);
    ObjectAnimator anim = ObjectAnimator.ofFloat(view, "translationX", container.getRight());
    anim.start();
    

    光学边界布局

    对于包含九宫格背景图片的视图,您现在可以指定它们 与相邻视图对齐的您可以输入背景图片的边界 而不是“剪辑”视图边界。

    例如,图 1 和图 2 显示的布局相同,但图 1 中的版本为 使用裁剪边界(默认行为),而图 2 则使用光学边界。由于 用于按钮和相框的九宫格图像边缘有内边距, 在使用裁剪边界时,这些标签与文本或文本之间不会显示。

    注意:图 1 和图 2 中的屏幕截图包含 布局边界"已启用开发者设置。对于每个视图,红线表示 边界,蓝线表示裁剪边界,粉色表示外边距。

    图 1. 使用裁剪边界进行布局(默认)。

    图 2. 使用光学边界进行布局。

    如需根据视图的光学边界对齐视图,请在其中一个父布局中将 android:layoutMode 属性设置为 "opticalBounds"。例如:

    <LinearLayout android:layoutMode="opticalBounds" ... >
    

    图 3. Holo 按钮九宫格的放大视图 光学边界

    为此,应用于视图背景的九宫格图像必须指定 9-patch 文件底部和右侧的红色线条表示光学边界(如 如图 3 所示)。红线表示需要减去的区域 裁剪边界,保留图片的光学边界。

    在布局中为 ViewGroup 启用光学边界后,所有 后代视图会继承光学边界布局模式,除非您为分组依据替换该模式 将 android:layoutMode 设置为 "clipBounds"。所有布局元素也都遵循 子视图的光学边界,根据 以及其中的视图不过,布局元素(ViewGroup 的子类) 目前不支持应用于自身背景的九宫格图像的光学边界。

    如果您通过创建 ViewViewGroup 或其任何子类的子类来创建自定义视图,则您的视图将继承这些光学绑定行为。

    注意:Holo 主题支持的所有微件都已更新 具有光学边界,包括 ButtonSpinnerEditText,等等。因此,您可以设置 将 android:layoutMode 属性设为 "opticalBounds"(如果您的应用应用了 Holo 主题) (Theme.HoloTheme.Holo.Light 等)。

    如要使用 Draw 9-patch 工具为您自己的九宫格图像指定光学边界,请在出现以下情况时按住 Ctrl 键: 点击边框像素即可

    Rect 值的动画

    您现在可以使用新的 RectEvaluator 在两个 Rect 值之间添加动画效果。这个新类是 TypeEvaluator 的实现,您可以将其传递给 ValueAnimator.setEvaluator()

    窗口附加和焦点监听器

    以前,如果您想监听视图何时附加/分离到窗口,或者 您需要替换 View 类, 分别实现 onAttachedToWindow()onDetachedFromWindow()onWindowFocusChanged()

    现在,如需接收附加和分离事件,您可以改为实现 ViewTreeObserver.OnWindowAttachListener,并使用以下代码在视图上设置它 addOnWindowAttachListener()。 如需接收焦点事件,您可以实现 ViewTreeObserver.OnWindowFocusChangeListener,并使用以下代码在视图上设置它 addOnWindowFocusChangeListener()

    电视过扫描支持

    为确保应用填满每台电视的整个屏幕,您现在可以启用过扫描 应用布局过扫描模式由 FLAG_LAYOUT_IN_OVERSCAN 标志决定,您可以使用如下平台主题启用该标志: Theme_DeviceDefault_NoActionBar_Overscan 或启用 自定义主题中的 windowOverscan 样式。

    屏幕方向

    <activity> 代码的 screenOrientation 属性现在支持其他值,以遵从用户的自动屏幕旋转偏好:

    "userLandscape"
    行为与 "sensorLandscape" 相同,除非用户停用了自动屏幕旋转功能 则会在正常的横向方向上锁定,而不会翻转。
    "userPortrait"
    行为与 "sensorPortrait" 相同,除非用户随后停用了自动屏幕旋转功能 它就会锁定在正常的纵向方向,而不会翻转。
    "fullUser"
    行为与 "fullSensor" 相同,并且允许向所有四个方向旋转,但以下四个方向除外: 如果用户停用自动屏幕旋转,屏幕将锁定在用户首选方向上。

    此外,您现在还可以声明 "locked" 以将应用的屏幕方向锁定为 屏幕的当前方向。

    旋转动画

    rotationAnimation 字段 WindowManager 可让您从自己设置的三种动画中选择其一 。三个动画是:

    注意:仅当您将 activity 设置为使用“全屏”时,这些动画才可用模式,您可以使用 Theme.Holo.NoActionBar.Fullscreen 等主题启用该模式。

    例如,下面展示了如何启用“淡入淡出”动画:

    Kotlin

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        val params: WindowManager.LayoutParams = window.attributes
        params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE
        window.attributes = params
        ...
    }
    

    Java

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        WindowManager.LayoutParams params = getWindow().getAttributes();
        params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
        getWindow().setAttributes(params);
        ...
    }
    

    用户输入

    新传感器类型

    借助新的 TYPE_GAME_ROTATION_VECTOR 传感器,您可以检测设备的旋转情况,而无需担心磁场干扰。与 TYPE_ROTATION_VECTOR 传感器不同,TYPE_GAME_ROTATION_VECTOR 并非基于磁北。

    新的 TYPE_GYROSCOPE_UNCALIBRATEDTYPE_MAGNETIC_FIELD_UNCALIBRATED 传感器可提供原始传感器数据,而无需 考虑到偏差估算的因素。也就是说,现有的 TYPE_GYROSCOPETYPE_MAGNETIC_FIELD 传感器提供的传感器数据考虑到了由陀螺仪漂移和硬铁产生的估算偏差 。而新的“未校准”则这些传感器的版本 原始传感器数据并单独提供估算的偏差值。借助这些传感器,您可以 通过使用 外部数据

    通知监听器

    Android 4.3 添加了新的服务类 NotificationListenerService,可让您的应用在系统发布新通知时接收有关这些通知的信息。

    如果您的应用目前使用无障碍服务 API 访问系统通知,您应更新应用以改用这些 API。

    联系人提供程序

    查询“contactables”

    新的联系人提供程序查询 Contactables.CONTENT_URI 提供了一种有效的方法,用于获取一个 Cursor,其中包含属于与指定查询匹配的所有联系人的所有电子邮件地址和电话号码。

    查询联系人增量

    联系人提供程序中新增了一些 API,可让您高效地查询联系人数据的近期更改。以前,当联系人数据中的某些内容发生更改时,您的应用会收到通知,但您并不了解具体更改内容,并且需要检索所有联系人,然后进行迭代以发现更改。

    如需跟踪对插入内容和更新的更改,您现在可以在选择中包含 CONTACT_LAST_UPDATED_TIMESTAMP 参数,以仅查询自上次查询提供程序以来更改的联系人。

    为了跟踪哪些联系人已被删除,新表 ContactsContract.DeletedContacts 会提供已删除的联系人日志(但每个已删除的联系人都会在此表中保留一段时间)。与 CONTACT_LAST_UPDATED_TIMESTAMP 类似,您可以使用新的选择参数 CONTACT_DELETED_TIMESTAMP 来检查自上次查询提供程序以来哪些联系人已被删除。该表还包含 DAYS_KEPT_MILLISECONDS 常量,该常量包含日志将保留的天数(以毫秒为单位)。

    此外,当用户遇到以下情况时,联系人提供程序现在会广播 CONTACTS_DATABASE_CREATED 操作 通过系统设置菜单清除联系人存储空间,从而有效地重新创建 联系人提供程序数据库。它旨在向应用发出信号,指示它们需要断开所有联系 并使用新的查询重新加载该数据。

    有关使用这些 API 检查联系人更改的示例代码,请在 ApiDemos 中查找 SDK 示例下载中提供了示例。

    本地化

    改进了对双向文本的支持

    旧版 Android 支持从右到左 (RTL) 的语言和布局, 但有时无法正确处理混合方向文本。因此,Android 4.3 添加了 BidiFormatter API,可帮助您正确设置反向文本格式 而不会对内容的任何部分进行乱码

    例如,当要创建一个带有字符串变量的句子时,比如“您是不是要找 15 Bay Street, Laurel, CA?”的指令,则通常会将已本地化的字符串资源和变量传递给 String.format():

    Kotlin

    val suggestion = String.format(resources.getString(R.string.did_you_mean), address)
    

    Java

    Resources res = getResources();
    String suggestion = String.format(res.getString(R.string.did_you_mean), address);
    

    但是,如果语言区域是希伯来语,则格式化的字符串将如下所示:

    האם התכוונת ל 15 Bay Street, Laurel, CA?

    这是错误的,因为“15”应该放在“Bay Street”的左边。解决方案是使用 BidiFormatter 及其 unicodeWrap() 方法。例如,上面的代码变为:

    Kotlin

    val bidiFormatter = BidiFormatter.getInstance()
    val suggestion = String.format(
            resources.getString(R.string.did_you_mean),
            bidiFormatter.unicodeWrap(address)
    )
    

    Java

    Resources res = getResources();
    BidiFormatter bidiFormatter = BidiFormatter.getInstance();
    String suggestion = String.format(res.getString(R.string.did_you_mean),
            bidiFormatter.unicodeWrap(address));
    

    默认情况下,unicodeWrap() 会使用 第一强方向性估计启发式算法,如果第一个是 指示文本方向的信号并未表示整体内容的合适方向。 如有必要,您可以通过传递 TextDirectionHeuristics 中的某个 TextDirectionHeuristic 常量来指定其他启发法 发送至 unicodeWrap()

    注意:这些新 API 也可用于以前的版本 通过 Android支持 库,其中包含 BidiFormatter 类和相关 API。

    无障碍服务

    处理按键事件

    AccessibilityService 现在可以接收 使用 onKeyEvent() 回调方法实现按键输入事件。这样,您的无障碍服务就可以处理 基于按键的输入设备(如键盘)并将这些事件转换为 以前可能只能通过触摸输入或设备的方向键实现。

    选择文本并复制/粘贴

    AccessibilityNodeInfo 现在提供的 API 一个用于选择、剪切、复制和粘贴的 AccessibilityService 文本。

    要指定要剪切或复制的文字,您的无障碍服务可以使用新的 操作,ACTION_SET_SELECTION,正在传递 为其选择起始位置和结束位置,位置为 ACTION_ARGUMENT_SELECTION_START_INTACTION_ARGUMENT_SELECTION_END_INT。 您也可以使用现有的 操作,ACTION_NEXT_AT_MOVEMENT_GRANULARITY (之前仅用于移动光标位置),并添加参数 ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN

    您可以使用 ACTION_CUT 进行剪切或复制, ACTION_COPY,随后使用 ACTION_PASTE

    注意:这些新 API 也可用于以前的版本 通过 Android支持 包含 AccessibilityNodeInfoCompat 的库 类。

    声明无障碍功能

    从 Android 4.3 开始,无障碍服务必须声明无障碍功能 ,才能使用某些无障碍功能。如果该功能 则此地图项将为空操作。要声明服务的 因此您必须使用与各种 “功能”AccessibilityServiceInfo 中的常量 类。

    例如,如果某项服务未请求 flagRequestFilterKeyEvents 功能, 那么它收不到按键事件

    测试和调试

    自动化界面测试

    新的 UiAutomation 类提供了可让您模拟用户的 API, 用于测试自动化的操作。通过使用平台的 AccessibilityService API,UiAutomation 通过 API,您可以检查屏幕内容并注入任意键盘和触摸事件。

    如需获取 UiAutomation 的实例,请调用 Instrumentation.getUiAutomation()。订单 为使此操作生效,您必须在 instrument 命令中提供 -w 选项 从 adb shell 运行 InstrumentationTestCase 时。

    借助 UiAutomation 实例,您可以执行任意事件来测试 您的应用,方法是调用 executeAndWaitForEvent(),并向其传递要执行的 Runnable(超时) 操作的时间段以及 UiAutomation.AccessibilityEventFilter 接口的实现。您会在 UiAutomation.AccessibilityEventFilter 实现中收到来电 让您可以过滤出感兴趣的事件, 测试失败

    如需在测试期间观察所有事件,请创建 UiAutomation.OnAccessibilityEventListener 的实现并将其传递给 setOnAccessibilityEventListener()。 然后,您的监听器接口会收到对 onAccessibilityEvent() 的调用 每次事件发生时接收 AccessibilityEvent 对象 来描述该事件

    UiAutomation API 还提供各种其他操作 以鼓励开发 uiautomator 等界面测试工具。例如, UiAutomation 还可以:

    • 注入输入事件
    • 更改屏幕的方向
    • 截取屏幕截图

    最重要的是,对于界面测试工具,UiAutomation API 可以 这与 Instrumentation 中的不同。

    适用于应用的 Systrace 事件

    Android 4.3 添加了 Trace 类,其中包含两个静态方法, beginSection()endSection(): 允许您定义要包含在 Systrace 报告中的代码块。通过创建 可跟踪代码段,systrace 日志会向您提供更详细的 并分析应用中发生运行速度缓慢的环节

    如需了解如何使用 Systrace 工具,请参阅使用 Systrace 分析展示广告和性能

    安全

    适用于应用私钥的 Android 密钥库

    Android 现在在 KeyStore 中提供自定义 Java 安全提供程序 名为“Android 密钥库”的工具 可能只有您的应用可以查看和使用。要加载 Android 密钥库,请将 将"AndroidKeyStore"更改为KeyStore.getInstance()

    如需管理您的应用在 Android 密钥库中的私有凭据,请使用以下代码生成新密钥: KeyPairGeneratorSpec会员价为 KeyPairGenerator。第一页 通过调用 getInstance() 获取 KeyPairGenerator 的实例。然后调用 initialize(),向其传递 KeyPairGeneratorSpec,您可以使用 KeyPairGeneratorSpec.Builder。 最后,通过调用 generateKeyPair() 获取 KeyPair

    硬件凭据存储

    Android 现在支持为您的 KeyChain 提供由硬件支持的存储空间 凭据,通过使密钥无法提取来提高安全性。也就是说, 密钥位于由硬件支持的密钥库(安全元件、TPM 或 TrustZone)中,因此可用于 加密操作,但无法导出私钥材料。甚至操作系统内核 无法访问此密钥材料。虽然并非所有 Android 设备都支持 则可通过调用 KeyChain.IsBoundKeyAlgorithm()

    清单声明

    可声明的必备功能

    <uses-feature> 现在支持以下值 元素,这样可以确保您的应用仅安装在提供相应功能的设备上 应用需求

    FEATURE_APP_WIDGETS
    声明您的应用提供应用微件,并且应仅安装在符合以下条件的设备上 提供可供用户嵌入应用微件的主屏幕或类似位置。 示例:
    <uses-feature android:name="android.software.app_widgets" android:required="true" />
    
    FEATURE_HOME_SCREEN
    声明您的应用充当主屏幕替换项,仅应安装在 支持第三方主屏幕应用的设备。 示例:
    <uses-feature android:name="android.software.home_screen" android:required="true" />
    
    FEATURE_INPUT_METHODS
    声明您的应用提供自定义输入法(使用 InputMethodService 构建的键盘),并且应仅安装在符合以下条件的设备上: 支持第三方输入法。 示例:
    <uses-feature android:name="android.software.input_methods" android:required="true" />
    
    FEATURE_BLUETOOTH_LE
    声明您的应用使用蓝牙低功耗 API,并且应仅安装在设备上 能够通过低功耗蓝牙与其他设备进行通信。 示例:
    <uses-feature android:name="android.software.bluetooth_le" android:required="true" />
    

    用户权限

    <uses-permission> 现在支持以下值 来声明 访问特定 API 所需的权限。

    BIND_NOTIFICATION_LISTENER_SERVICE
    必须使用新的 NotificationListenerService API。
    SEND_RESPOND_VIA_MESSAGE
    接收ACTION_RESPOND_VIA_MESSAGE的必要条件 intent。

    如需详细了解 Android 4.3 中的所有 API 变更,请参阅 API 差异报告