Android 6.0 变化

除了新功能和特性外,Android 6.0(API 级别 23)还包含各种系统变更和 API 行为变更。本文档重点介绍了您应了解并在应用中加以考虑的一些关键变更。

如果您之前发布过 Android 应用,请注意这些平台变更会影响您的应用。

运行时权限

此版本引入了新的权限模型,用户现在可以在运行时直接管理应用权限。此模型提高了用户对权限的可见性和控制力,同时简化了应用开发者的安装和自动更新流程。用户可以单独授予或撤销已安装应用的权限。

对于目标 API 级别为 Android 6.0(API 级别 23)或更高版本的应用,请务必在运行时检查并请求权限。要确定您的应用是否已获得某个权限,请调用新的 checkSelfPermission() 方法。要请求权限,请调用新的 requestPermissions() 方法。即使您的应用未将 Android 6.0(API 级别 23)作为目标,也应在新的权限模型下测试您的应用。

有关在应用中支持新权限模型的详细信息,请参阅处理系统权限。有关如何评估对应用影响的提示,请参阅权限使用注意事项

低电耗模式和应用待机模式

此版本引入了针对空闲设备和应用的新省电优化措施。这些功能会影响所有应用,因此请务必在这些新模式下测试您的应用。

  • 低电耗模式:如果用户拔下设备电源并将其长时间静置(屏幕关闭),设备会进入低电耗模式,在此模式下,设备会尝试使系统保持睡眠状态。在此模式下,设备会周期性地短暂恢复正常操作,以便进行应用同步和系统执行任何待处理的操作。
  • 应用待机模式:应用待机模式允许系统在用户未主动使用应用时确定该应用是否处于空闲状态。系统会在用户长时间未触碰该应用时做出此判断。如果设备未连接电源,系统会禁用其认为空闲的应用的网络访问并暂停同步和作业。

要详细了解这些省电变更,请参阅针对低电耗模式和应用待机模式进行优化

移除 Apache HTTP 客户端

Android 6.0 版本移除了对 Apache HTTP 客户端的支持。如果您的应用正在使用此客户端,且目标 API 级别为 Android 2.3(API 级别 9)或更高版本,请改用 HttpURLConnection 类。此 API 更高效,因为它通过透明压缩和响应缓存减少网络使用,并最大限度地降低功耗。要继续使用 Apache HTTP API,您必须首先在 build.gradle 文件中声明以下编译时依赖项

android {
    useLibrary 'org.apache.http.legacy'
}

BoringSSL

Android 正在从 OpenSSL 转向 BoringSSL 库。如果您在应用中使用 Android NDK,请不要链接到不属于 NDK API 的加密库,例如 libcrypto.solibssl.so。这些库不是公共 API,可能会在不同版本和设备上更改或损坏,恕不另行通知。此外,您可能会暴露在安全漏洞之下。相反,请修改您的原生代码,通过 JNI 调用 Java 加密 API,或静态链接到您选择的加密库。

硬件标识符访问

为了向用户提供更好的数据保护,从本版本开始,Android 移除了使用 Wi-Fi 和蓝牙 API 的应用对设备本地硬件标识符的程序化访问权限。现在,WifiInfo.getMacAddress()BluetoothAdapter.getAddress() 方法返回常量值 02:00:00:00:00:00

要通过蓝牙和 Wi-Fi 扫描访问附近外部设备的硬件标识符,您的应用现在必须拥有 ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION 权限

注意:当运行 Android 6.0(API 级别 23)的设备启动后台 Wi-Fi 或蓝牙扫描时,该操作对外部设备而言显示为源自随机 MAC 地址。

通知

此版本移除了 Notification.setLatestEventInfo() 方法。请改用 Notification.Builder 类构建通知。要重复更新通知,请重复使用 Notification.Builder 实例。调用 build() 方法以获取更新的 Notification 实例。

命令 adb shell dumpsys notification 不再输出您的通知文本。请改用 adb shell dumpsys notification --noredact 命令输出通知对象中的文本。

AudioManager 变更

不再支持通过 AudioManager 类直接设置音量或将特定音频流静音。方法 setStreamSolo() 已弃用,应改用 requestAudioFocus() 方法。类似地,方法 setStreamMute() 已弃用;请改用 adjustStreamVolume() 方法,并传入方向值 ADJUST_MUTEADJUST_UNMUTE

文本选择

Screen showing new text selection features within a floating toolbar

用户在您的应用中选择文本时,您现在可以在浮动工具栏中显示文本选择操作,例如剪切复制粘贴。用户交互的实现类似于上下文操作栏的实现,如为单个视图启用上下文操作模式中所述。

要为文本选择实现浮动工具栏,请在现有应用中进行以下更改

  1. 在您的 ViewActivity 对象中,将 ActionMode 调用从 startActionMode(Callback) 更改为 startActionMode(Callback, ActionMode.TYPE_FLOATING)
  2. 获取现有的 ActionMode.Callback 实现,并将其改为扩展 ActionMode.Callback2
  3. 覆盖 onGetContentRect() 方法,以提供视图中内容 Rect 对象的坐标(例如文本选择矩形)。
  4. 如果矩形定位不再有效,且这是唯一需要无效化的元素,请调用 invalidateContentRect() 方法。

如果您使用的是 Android 支持库 revision 22.2,请注意浮动工具栏不向后兼容,并且 appcompat 默认会控制 ActionMode 对象。这会阻止显示浮动工具栏。要在 AppCompatActivity 中启用 ActionMode 支持,请调用 getDelegate(),然后对返回的 AppCompatDelegate 对象调用 setHandleNativeActionModesEnabled(),并将输入参数设置为 false。此调用将 ActionMode 对象的控制权交还给框架。在运行 Android 6.0(API 级别 23)的设备上,这允许框架支持 ActionBar 或浮动工具栏模式,而在运行 Android 5.1(API 级别 22)或更低版本的设备上,仅支持 ActionBar 模式。

浏览器书签变更

此版本移除了对全局书签的支持。现在,方法 android.provider.Browser.getAllBookmarks()android.provider.Browser.saveBookmark() 已被移除。同样,权限 READ_HISTORY_BOOKMARKSWRITE_HISTORY_BOOKMARKS 也已被移除。如果您的应用目标 API 级别为 Android 6.0(API 级别 23)或更高版本,请勿从全局提供程序访问书签或使用书签权限。您的应用应改为在内部存储书签数据。

Android Keystore 变更

从本版本开始,Android Keystore 提供程序不再支持 DSA。仍支持 ECDSA。

不需要静态加密的密钥在安全锁屏被禁用或重置(例如,由用户或设备管理员)时将不再被删除。需要静态加密的密钥将在这些事件期间被删除。

Wi-Fi 和网络变更

此版本对 Wi-Fi 和网络 API 引入了以下行为变更。

  • 现在,您的应用仅在创建了 WifiConfiguration 对象后才能更改其状态。您不允许修改或删除用户或其他应用创建的 WifiConfiguration 对象。
  • 以前,如果应用使用 enableNetwork() 并设置 disableAllOthers=true 强制设备连接到特定的 Wi-Fi 网络,设备会断开与蜂窝数据等其他网络的连接。在此版本中,设备不再断开与此类其他网络的连接。如果您的应用 targetSdkVersion“20” 或更低,它会锁定在选定的 Wi-Fi 网络上。如果您的应用 targetSdkVersion“21” 或更高,请使用多网络 API(例如 openConnection()bindSocket() 以及新的 bindProcessToNetwork() 方法)来确保其网络流量发送到选定的网络。

相机服务变更

在此版本中,相机服务中共享资源访问模型已从之前的“先到先得”访问模型更改为优先处理高优先级进程的访问模型。服务行为的变更包括

  • 对相机子系统资源的访问,包括打开和配置相机设备,是根据客户端应用程序进程的“优先级”授予的。具有用户可见或前台活动的应用程序进程通常具有更高的优先级,这使得相机资源的获取和使用更加可靠。
  • 当优先级较高的应用尝试使用相机时,优先级较低的应用的活动相机客户端可能会被“驱逐”。在已弃用的 Camera API 中,这会导致为被驱逐的客户端调用 onError()。在 Camera2 API 中,这会导致为被驱逐的客户端调用 onDisconnected()
  • 在具有适当相机硬件的设备上,不同的应用程序进程能够同时独立地打开和使用不同的相机设备。但是,相机服务现在会检测并阻止同时访问导致任何打开的相机设备性能或功能显著下降的多进程用例。即使没有其他应用直接尝试访问同一相机设备,此更改也可能导致优先级较低的客户端被“驱逐”。
  • 更改当前用户会导致前一个用户帐户拥有的应用中的活动相机客户端被驱逐。对相机的访问仅限于当前设备用户拥有的用户资料。实际上,这意味着,例如,“访客”帐户在用户切换到其他帐户时将无法留下使用相机子系统的正在运行的进程。

运行时

ART 运行时现在正确实现了 newInstance() 方法的访问规则。此更改修复了 Dalvik 在以前版本中错误检查访问规则的问题。如果您的应用使用 newInstance() 方法并希望覆盖访问检查,请调用 setAccessible() 方法,并将输入参数设置为 true。如果您的应用使用 v7 appcompat 库v7 recyclerview 库,您必须更新应用以使用这些库的最新版本。否则,请确保 XML 中引用的所有自定义类都已更新,以便其类构造函数可访问。

此版本更新了动态链接器的行为。动态链接器现在理解库的 soname 及其路径之间的区别(公共错误 6670),并且现在实现了按 soname 搜索。以前可以工作但具有错误的 DT_NEEDED 条目(通常是构建机器文件系统上的绝对路径)的应用加载时可能会失败。

标志 dlopen(3) RTLD_LOCAL 现在已正确实现。请注意,RTLD_LOCAL 是默认值,因此未明确使用 RTLD_LOCALdlopen(3) 调用将受到影响(除非您的应用明确使用了 RTLD_GLOBAL)。使用 RTLD_LOCAL 时,符号将不会提供给后续调用 dlopen(3) 加载的库(与被 DT_NEEDED 条目引用不同)。

在早期版本的 Android 上,如果您的应用请求系统加载具有文本重定位的共享库,系统会显示警告,但仍允许加载该库。从本版本开始,如果您的应用的目标 SDK 版本是 23 或更高,系统将拒绝此库。为了帮助您检测库是否未能加载,您的应用应记录 dlopen(3) 失败,并包含 dlerror(3) 调用返回的问题描述文本。要详细了解如何处理文本重定位,请参阅此指南

APK 验证

平台现在对 APK 执行更严格的验证。如果清单中声明了文件但 APK 本身中不存在该文件,则认为 APK 已损坏。如果移除了任何内容,则必须重新签名 APK。

USB 连接

通过 USB 端口的设备连接现在默认为仅充电模式。要通过 USB 连接访问设备及其内容,用户必须明确授予此类交互的权限。如果您的应用支持用户通过 USB 端口与设备进行交互,请考虑必须明确启用该交互。

Android for Work 变更

此版本包含 Android for Work 的以下行为变更

  • 个人上下文中的工作联系人。当用户查看过去通话时,Google 拨号器通话记录现在会显示工作联系人。将 setCrossProfileCallerIdDisabled() 设置为 true 会在 Google 拨号器通话记录中隐藏工作资料联系人。仅当您将 setBluetoothContactSharingDisabled() 设置为 false 时,工作联系人才能与个人联系人一起通过蓝牙显示到设备上。默认情况下,它设置为 true
  • Wi-Fi 配置移除:由资料所有者添加的 Wi-Fi 配置(例如,通过调用 addNetwork() 方法)现在会在该工作资料被删除时被移除。
  • Wi-Fi 配置锁定:如果 WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN 非零,则由活动设备所有者创建的任何 Wi-Fi 配置不能再由用户修改或删除。用户仍可以创建和修改自己的 Wi-Fi 配置。活动设备所有者有权编辑或删除任何 Wi-Fi 配置,包括并非由他们创建的配置。
  • 通过添加 Google 帐户下载设备政策控制器:当需要在托管上下文之外通过设备政策控制器 (DPC) 应用管理的 Google 帐户添加到设备时,添加帐户流程现在会提示用户安装相应的 WPC。此行为也适用于通过设置 > 帐户以及在初始设备设置向导中添加的帐户。
  • 特定 DevicePolicyManager API 行为变更
  • 其他 API 变更:
    • 数据使用情况:类 android.app.usage.NetworkUsageStats 已更名为 NetworkStats
  • 全局设置变更: