Android 6.0(API 级别 23)除了提供诸多新特性和功能外,还对系统和 API 行为做出了各种变更。本文重点介绍您应该了解并在开发应用时加以考虑的一些重要变更。
如果您之前发布过 Android 应用,请注意,平台中的这些更改会影响您的应用。
运行时权限
此版本引入了一种新的权限模型,使用户现在可以直接在运行时管理应用权限。此模式可让用户更好地了解和控制权限,同时为应用开发者简化安装和自动更新流程。用户可以为已安装的应用单独授予或撤消权限。
对于以 Android 6.0(API 级别 23)或更高版本为目标平台的应用,请务必在运行时检查和请求权限。如需确定您的应用是否已被授予权限,请调用新的 checkSelfPermission()
方法。如需请求权限,请调用新的 requestPermissions()
方法。即使您的应用并非以 Android 6.0(API 级别 23)为目标平台,您也应该在新权限模式下测试您的应用。
如需详细了解如何在应用中支持新权限模型,请参阅 使用系统权限。如需了解如何评估新政策对应用的影响,请参阅权限使用说明。
低电耗模式和应用待机模式
此版本引入了针对空闲设备和应用的全新节能优化技术。这些功能会影响所有应用,因此请务必在这些新模式下测试您的应用。
- 低电耗模式:如果用户拔下设备的电源插头,并在屏幕关闭一段时间后使其保持不活动状态,设备会进入低电耗模式,在该模式下,系统会尝试使系统保持休眠状态。在此模式下,设备会定期短时间恢复正常运行,以便进行应用同步,同时系统可以执行任何待处理的操作。
- 应用待机模式:应用待机模式允许系统判定应用在用户未主动使用它时处于空闲状态。当用户有一段时间未触摸应用时,系统便会作出此判定。如果将设备拔出,系统会为其视为空闲的应用停用网络访问,并暂停同步和作业。
如需详细了解这些节能变更,请参阅对低电耗模式和应用待机模式进行优化。
取消支持 Apache HTTP 客户端
Android 6.0 版本取消了对 Apache HTTP 客户端的支持。如果您的应用使用此客户端并以 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.so
和 libssl.so
。这些库不是公共 API,在不同版本和设备上,这些库可能会随时发生更改或出现故障,恕不另行通知。此外,您还可能面临安全漏洞的风险。请改为修改原生代码,以通过 JNI 调用 Java 加密 API,或静态链接到您选择的加密库。
硬件标识符访问权
为了向用户提供更好的数据保护,从此版本开始,对于使用 Wi-Fi 和 Bluetooth API 的应用,Android 不再支持以编程方式访问设备本地硬件标识符。WifiInfo.getMacAddress()
和 BluetoothAdapter.getAddress()
方法现在会返回一个常量值 02:00:00:00:00:00
。
现在,若要通过蓝牙和 Wi-Fi 扫描访问附近外部设备的硬件标识符,您的应用必须具有 ACCESS_FINE_LOCATION
或 ACCESS_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
类直接设置音量或将特定音频流静音。setStreamSolo()
方法已弃用,您应改为调用 requestAudioFocus()
方法。同样,setStreamMute()
方法已废弃;请改为调用 adjustStreamVolume()
方法并传入方向值 ADJUST_MUTE
或 ADJUST_UNMUTE
。
文本选择
![显示浮动工具栏中新的文本选择功能的屏幕](https://developer.android.google.cn/static/images/android-6.0/text-selection.gif?authuser=3&hl=sk)
现在,当用户在您的应用中选择文本时,您可以在浮动工具栏中显示文本选择操作,如剪切、复制和粘贴。用户互动实现与上下文操作栏的实现类似,如 为单个视图启用上下文操作模式中所述。
如需实现用于文本选择的悬浮工具栏,请在现有应用中做出以下更改:
- 在
View
或Activity
对象中,将ActionMode
调用从startActionMode(Callback)
更改为startActionMode(Callback, ActionMode.TYPE_FLOATING)
。 - 改为使用
ActionMode.Callback
的现有实现扩展ActionMode.Callback2
。 - 替换
onGetContentRect()
方法,以提供内容Rect
对象(如文本选择矩形)在视图中的坐标。 - 如果矩形的定位不再有效,并且这是唯一需要失效的元素,请调用
invalidateContentRect()
方法。
如果您使用的是
Android 支持库修订版 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_BOOKMARKS
和 WRITE_HISTORY_BOOKMARKS
权限也会被移除。如果您的应用以 Android 6.0(API 级别 23)或更高版本为目标平台,请勿访问全局提供程序中的书签或使用书签权限。您的应用应在内部存储书签数据。
Android 密钥库变更
在此版本中,Android 密钥库提供程序不再支持 DSA。但仍支持 ECDSA。
停用或重置安全锁定屏幕时(例如,由用户或设备管理员执行此类操作时),系统将不会再删除不需要静态加密的密钥。在这些事件期间,需要静态加密的密钥将被删除。
WLAN 和网络连接变更
此版本对 WLAN API 和 Networking API 引入了以下行为变更。
- 现在,您的应用只能更改由您创建
WifiConfiguration
对象的状态。您无法修改或删除由用户或其他应用创建的WifiConfiguration
对象。 -
以前,如果应用通过将
enableNetwork()
与disableAllOthers=true
设置搭配使用来强制设备连接到特定 Wi-Fi 网络,则设备会断开与其他网络(例如移动数据网络)的连接。在此版本中,设备不再断开与此类其他网络的连接。如果您的应用的targetSdkVersion
为“20”
或更低,则会固定到所选 Wi-Fi 网络。如果应用的targetSdkVersion
为“21”
或更高版本,请使用多网络 API(例如openConnection()
、bindSocket()
和新的bindProcessToNetwork()
方法)来确保通过所选网络发送其网络流量。
相机服务变更
在此版本中,相机服务中共享资源的访问模式已从之前的“先到先得”访问模式更改为高优先级进程优先的访问模式。对服务行为的变更包括:
- 根据客户端应用进程的“优先级”,授予对相机子系统资源的访问权,包括打开和配置相机设备。具有用户可见 activity 或前台 activity 的应用进程通常会被授予更高的优先级,从而使相机资源的获取和使用更加可靠。
- 当高优先级的应用尝试使用摄像头时,系统可能会“逐出”正在使用中摄像头客户端的低优先级应用。在已废弃的
Camera
API 中,这会导致系统为被逐出的客户端调用onError()
。在Camera2
API 中,这会导致系统为被逐出的客户端调用onDisconnected()
。 - 在配备相应相机硬件的设备上,不同的应用进程可同时独立打开和使用单独的相机设备。不过,在多进程用例中,同时访问会导致任何打开的摄像头设备的性能或功能显著下降,现在会由摄像头服务检测并禁止该用例。即使没有其他应用直接尝试访问同一摄像头设备,此更改也可能会导致优先级较低的客户端被“驱逐”。
- 更改当前用户会导致之前用户帐号所拥有的应用中处于活跃状态的摄像头客户端被驱逐。对摄像头的访问权限仅限于当前设备用户拥有的用户个人资料。例如,在实际使用中,这意味着当用户切换到其他帐号时,“访客”帐号将无法让使用相机子系统的进程保持运行状态。
运行时
ART 运行时现在可以正确实现 newInstance()
方法的访问规则。此更改修复了在以前的版本中 Dalvik 错误地检查访问规则的问题。如果您的应用使用 newInstance()
方法,并且您想要替换访问权限检查,请调用 setAccessible()
方法,并将输入参数设置为 true
。如果您的应用使用 v7 appcompat 库或 v7 recyclerview 库,您必须更新应用以使用这些库的最新版本。否则,请确保更新从 XML 引用的任何自定义类,以便可以访问其类构造函数。
此版本更新了动态链接器的行为。动态链接器现在可以理解库的 soname
与其路径之间的差异(
公开 bug 6670),并且现已实现按 soname
搜索。之前包含错误 DT_NEEDED
条目(通常是构建机器文件系统上的绝对路径)却能正常运行的应用,在加载时可能会失败。
dlopen(3) RTLD_LOCAL
标志现已正确实现。请注意,RTLD_LOCAL
是默认值,因此未明确使用 RTLD_LOCAL
的 dlopen(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 行为的变更:- 调用
setCameraDisabled()
方法只会影响发起调用的用户的相机;从受管理资料调用它不会影响主要用户运行的相机应用。 - 此外,
setKeyguardDisabledFeatures()
方法现在可供资料所有者以及设备所有者使用。 - 个人资料所有者可以设置以下键盘锁限制:
KEYGUARD_DISABLE_TRUST_AGENTS
和KEYGUARD_DISABLE_FINGERPRINT
,它们会影响个人资料的父级用户的锁屏设置。KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS
:只会影响受管理个人资料中的应用生成的通知。
DevicePolicyManager.createAndInitializeUser()
和DevicePolicyManager.createUser()
方法已废弃。- 当指定用户的应用在前台运行时,
setScreenCaptureDisabled()
方法现在也会屏蔽辅助结构。 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM
现在默认为 SHA-256。为了实现向后兼容性,SHA-1 仍受支持,但将来会被移除。EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM
现在仅接受 SHA-256。- Android 6.0(API 级别 23)中曾经存在的 Device initializer API 现已删除
- 移除了
EXTRA_PROVISIONING_RESET_PROTECTION_PARAMETERS
,因此 NFC 触碰配置无法以程序化方式解锁受恢复出厂设置保护的设备。 - 您现在可以使用
EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE
extra 在受管设备的 NFC 配置期间向设备所有者应用传递数据。 - Android for Work API 针对 M 运行时权限(包括工作资料、辅助层等)进行了优化。新增的
DevicePolicyManager
权限 API 不会影响 Android M 之前的版本应用。 - 当用户退出通过
ACTION_PROVISION_MANAGED_PROFILE
或ACTION_PROVISION_MANAGED_DEVICE
intent 发起的设置流程的同步部分时,系统现在会返回RESULT_CANCELED
结果代码。
- 调用
- 对其他 API 的更改:
- 数据使用:
android.app.usage.NetworkUsageStats
类已重命名为NetworkStats
。
- 数据使用:
- 对全局设置的更改:
- 这些设置无法再通过
setGlobalSettings()
进行设置:BLUETOOTH_ON
DEVELOPMENT_SETTINGS_ENABLED
MODE_RINGER
NETWORK_PREFERENCE
WIFI_ON
- 这些全局设置现在可以通过
setGlobalSettings()
进行设置:
- 这些设置无法再通过