Android 5.0 行为变更

API 级别:21

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

如果您之前已发布 Android 应用,请注意您的应用可能会受到 Android 5.0 中这些变更的影响。

如需概览新平台特性,请参阅 Android Lollipop 亮点

视频

Dev Byte:Android 5.0 新特性

Dev Byte:通知

Android Runtime (ART)

在 Android 5.0 中,ART 运行时取代 Dalvik 成为平台的默认运行时。ART 运行时在 Android 4.4 中作为实验性功能引入。

如需概览 ART 的新特性,请参阅ART 简介。一些主要的新特性包括:

  • 预先 (AOT) 编译
  • 改进的垃圾回收 (GC)
  • 改进的调试支持

大多数 Android 应用在 ART 下无需任何更改即可正常工作。但是,某些在 Dalvik 上有效的技术在 ART 上无效。如需了解最重要的问题,请参阅在 Android Runtime (ART) 上验证应用行为。如果出现以下情况,请特别注意:

  • 您的应用使用 Java 本地接口 (JNI) 运行 C/C++ 代码。
  • 您使用的开发工具生成非标准代码(例如某些混淆器)。
  • 您使用的技术与压缩垃圾回收不兼容。

通知

确保您的通知考虑了这些 Android 5.0 变更。要了解有关针对 Android 5.0 及更高版本设计通知的更多信息,请参阅通知设计指南

Material Design 风格

通知使用深色文本绘制在白色(或非常浅色)背景上,以匹配新的 Material Design 微件。确保您的所有通知在新配色方案下看起来正常。如果您的通知看起来不正常,请修复它们。

  • 使用 setColor() 设置图标图片后面的圆圈中的强调色。
  • 更新或移除包含颜色的资源。系统会忽略操作图标和主通知图标中的所有非 alpha 通道。您应假定这些图标仅包含 alpha 通道。系统会以白色绘制通知图标,以深灰色绘制操作图标。

声音和振动

如果您当前使用 RingtoneMediaPlayerVibrator 类向您的通知添加声音和振动,请移除此代码,以便系统能够在优先模式下正确呈现通知。请改用 Notification.Builder 方法添加声音和振动。

将设备设置为 RINGER_MODE_SILENT 会使设备进入新的优先模式。如果您将其设置为 RINGER_MODE_NORMALRINGER_MODE_VIBRATE,设备将退出优先模式。

以前,Android 使用 STREAM_MUSIC 作为主音频流来控制平板电脑设备的音量。在 Android 5.0 中,手机和平板电脑设备的主音量流现已统一,由 STREAM_RINGSTREAM_NOTIFICATION 控制。

锁屏可见性

默认情况下,通知现在会出现在 Android 5.0 的用户锁屏界面上。用户可以选择保护敏感信息不被泄露,在这种情况下,系统会自动编辑通知显示的文本。要自定义此编辑后的通知,请使用 setPublicVersion()

如果通知不包含个人信息,或者您想允许在通知上进行媒体播放控制,请调用 setVisibility() 方法并将通知的可见性级别设置为 VISIBILITY_PUBLIC

媒体播放

如果您正在实现显示媒体播放状态或传输控制的通知,请考虑使用新的 Notification.MediaStyle 模板,而不是自定义的 RemoteViews.RemoteView 对象。无论您选择哪种方法,都要确保将通知的可见性设置为 VISIBILITY_PUBLIC,以便您的控件可以从锁屏访问。请注意,从 Android 5.0 开始,系统不再在锁屏界面上显示 RemoteControlClient 对象。有关更多信息,请参阅如果您的应用使用了 RemoteControlClient

浮动通知

当设备处于活动状态(即设备已解锁且屏幕开启)时,通知现在可能出现在一个小的浮动窗口(也称为浮动通知)中。这些通知看起来与您的通知的紧凑形式相似,不同之处在于浮动通知还会显示操作按钮。用户可以在不离开当前应用的情况下对浮动通知采取操作或将其忽略。

可能触发浮动通知的条件包括:

  • 用户活动处于全屏模式(应用使用 fullScreenIntent
  • 通知具有高优先级并使用铃声或振动

如果您的应用在上述任何场景下实现了通知,请确保浮动通知能够正确呈现。

媒体控件和 RemoteControlClient

RemoteControlClient 类现已弃用。请尽快切换到新的 MediaSession API。

Android 5.0 的锁屏界面不会显示您的 MediaSessionRemoteControlClient 的传输控制。相反,您的应用可以通过通知从锁屏提供媒体播放控制。这使您的应用能够更好地控制媒体按钮的呈现,同时为用户在锁定和未锁定设备上提供一致的体验。

Android 5.0 为此目的引入了新的 Notification.MediaStyle 模板。Notification.MediaStyle 会将您使用 Notification.Builder.addAction() 添加的通知操作转换为嵌入在应用媒体播放通知中的紧凑按钮。将您的会话令牌传递给 setSession() 方法,以告知系统此通知控制一个正在进行的媒体会话。

务必将通知的可见性设置为 VISIBILITY_PUBLIC,以标记该通知可在任何锁屏界面(安全或不安全)上安全显示。有关更多信息,请参阅锁屏通知

如果您的应用在 Android TVWear 平台上运行,并且要显示媒体播放控件,请实现 MediaSession 类。如果您的应用需要在 Android 设备上接收媒体按钮事件,您也应实现 MediaSession

getRecentTasks()

随着 Android 5.0 中引入新的最近任务屏幕中的并行文档和活动任务功能(请参阅下方的最近任务屏幕中的并行文档和活动),ActivityManager.getRecentTasks() 方法现已弃用,以提高用户隐私。为了向后兼容,此方法仍然返回其数据的一小部分,包括调用应用自身的任务以及可能的一些其他非敏感任务(例如 Home)。如果您的应用正在使用此方法检索自己的任务,请改用 getAppTasks() 来检索该信息。

Android NDK 中的 64 位支持

Android 5.0 引入了对 64 位系统的支持。64 位增强功能增加了地址空间并提高了性能,同时仍然完全支持现有的 32 位应用。64 位支持还提高了 OpenSSL 在加密方面的性能。此外,此版本还引入了新的原生媒体 NDK API 以及原生 OpenGL ES (GLES) 3.1 支持。

要使用 Android 5.0 中提供的 64 位支持,请从Android NDK 页面下载并安装 NDK Revision 10c。有关 NDK 的重要变更和 bug 修复的更多信息,请参阅 Revision 10c 的发布说明

绑定到服务

Context.bindService() 方法现在需要一个明确的 Intent,如果提供隐式 intent 则会抛出异常。为确保您的应用安全,在启动或绑定 Service 时使用明确的 intent,并且不要为服务声明 intent 过滤器。

WebView

Android 5.0 更改了您的应用的默认行为。

  • 如果您的应用目标 API 级别为 21 或更高
  • 如果您的应用目标 API 级别低于 21: 系统允许混合内容和第三方 Cookie,并且始终一次性渲染整个文档。

自定义权限的唯一性要求

权限概览文档所述,Android 应用可以定义自定义权限,作为以专有方式管理对组件访问的一种手段,而无需使用平台预定义的系统权限。应用在其清单文件中声明的 <permission> 元素中定义自定义权限。

在少数情况下,定义自定义权限是合法且安全的方法。然而,有时创建自定义权限是不必要的,甚至可能给应用带来潜在风险,具体取决于为权限分配的保护级别。

Android 5.0 包含一项行为变更,以确保只有一个应用可以定义给定的自定义权限,除非该应用与定义该权限的其他应用使用相同的密钥签名。

使用重复自定义权限的应用

任何应用都可以定义它想要的任何自定义权限,因此可能会出现多个应用定义相同的自定义权限的情况。例如,如果两个应用提供类似的功能,它们可能会为其自定义权限派生相同的逻辑名称。应用还可能包含通用公共库或代码示例,这些库或示例本身包含相同的自定义权限定义。

在 Android 4.4 及更早版本中,用户可以在给定设备上安装多个此类应用,尽管系统会分配由第一个安装的应用指定的保护级别。

从 Android 5.0 开始,系统对使用不同密钥签名的应用强制执行新的自定义权限唯一性限制。现在,设备上只有一个应用可以定义给定的自定义权限(由其名称确定),除非定义该权限的其他应用使用相同的密钥签名。如果用户尝试安装具有重复自定义权限且未与定义该权限的驻留应用使用相同密钥签名的应用,系统将阻止安装。

对您的应用的考量

在 Android 5.0 及更高版本中,应用可以像以前一样继续定义自己的自定义权限,并通 <uses-permission> 机制请求其他应用的自定义权限。但是,随着 Android 5.0 中引入的新要求,您应该仔细评估可能对您的应用造成的影响。

以下是一些需要考虑的点:

  • 您的应用是否在其清单中声明了任何 <permission> 元素?如果是,它们是否真正是您的应用或服务正常运行所必需的?或者您可以改用系统默认权限吗?
  • 如果您的应用中包含 <permission> 元素,您知道它们来自哪里吗?
  • 您是否确实打算让其他应用通过 <uses-permission> 请求您的自定义权限?
  • 您的应用是否使用了包含 <permission> 元素的样板或示例代码?这些权限元素是否真正必要?
  • 您的自定义权限使用的名称是否简单或基于其他应用可能共享的通用术语?

新安装和更新

如上所述,对于在运行 Android 4.4 或更早版本的设备上新安装和更新您的应用,行为不受影响,没有变化。对于在运行 Android 5.0 或更高版本的设备上新安装和更新应用,如果您的应用定义了已由现有驻留应用定义的自定义权限,则系统将阻止您的应用安装

已安装的应用在 Android 5.0 系统更新后的情况

如果您的应用使用自定义权限并且已广泛分发和安装,则当用户将其设备更新到 Android 5.0 时,您的应用可能会受到影响。安装系统更新后,系统会重新验证已安装的应用,包括检查其自定义权限。如果您的应用定义了已由另一个已验证的应用定义的自定义权限,并且您的应用未与该其他应用使用相同的密钥签名,则系统将不会重新安装您的应用

建议

在运行 Android 5.0 或更高版本的设备上,我们建议您立即检查您的应用,进行必要的调整,并尽快向您的用户发布更新版本。

  • 如果您的应用使用自定义权限,请考虑它们的来源以及您是否确实需要它们。从您的应用中删除所有 <permission> 元素,除非您确定它们是应用正常运行所必需的。
  • 如果可能,考虑用系统默认权限替换您的自定义权限。
  • 如果您的应用需要自定义权限,请重命名您的自定义权限,使其在您的应用中具有唯一性,例如将其附加到您的应用的完整包名之后。
  • 如果您有一套使用不同密钥签名的应用,并且这些应用通过自定义权限访问共享组件,请确保该自定义权限仅在共享组件中定义一次。使用共享组件的应用不应自行定义自定义权限,而应通过 <uses-permission> 机制请求访问权限。
  • 如果您有一套使用相同密钥签名的应用,则每个应用可以根据需要定义相同的自定义权限 — 系统允许以通常的方式安装这些应用。

TLS/SSL 默认配置变更

Android 5.0 引入了对应用用于 HTTPS 和其他 TLS/SSL 流量的默认 TLS/SSL 配置的更改

  • 现已启用 TLSv1.2 和 TLSv1.1 协议,
  • 现已启用 AES-GCM (AEAD) 密码套件,
  • 现已禁用 MD5、3DES、导出和静态密钥 ECDH 密码套件,
  • 优先使用前向保密密码套件(ECDHE 和 DHE)。

这些更改可能会导致在少数以下列出的情况下出现 HTTPS 或 TLS/SSL 连接中断。

请注意,Google Play 服务的安全 ProviderInstaller 已在 Android 平台版本(可追溯到 Android 2.3)中提供这些更改。

服务器不支持任何已启用的密码套件

例如,服务器可能仅支持 3DES 或 MD5 密码套件。首选的修复方法是改进服务器配置以启用更强和更现代的密码套件和协议。理想情况下,应启用 TLSv1.2 和 AES-GCM,并启用并优先使用前向保密密码套件(ECDHE、DHE)。

另一种方法是修改应用,使其使用自定义 SSLSocketFactory 与服务器通信。该工厂应设计为创建 SSLSocket 实例,除了默认密码套件外,这些实例还应启用服务器所需的一些密码套件。

应用对用于连接服务器的密码套件做出了错误的假设

例如,某些应用包含自定义的 X509TrustManager,由于它期望 authType 参数为 RSA 但遇到 ECDHE_RSA 或 DHE_RSA 而导致中断。

服务器对 TLSv1.1、TLSv1.2 或新的 TLS 扩展不耐受

例如,与服务器的 TLS/SSL 握手被错误地拒绝或停滞。首选的修复方法是将服务器升级以符合 TLS/SSL 协议。这将使服务器能够成功协商这些更新的协议,或者协商 TLSv1 或更旧的协议,并忽略它无法理解的 TLS 扩展。在某些情况下,在服务器上禁用 TLSv1.1 和 TLSv1.2 可以作为一种临时措施,直到服务器软件升级。

另一种方法是修改应用,使其使用自定义 SSLSocketFactory 与服务器通信。该工厂应设计为创建仅启用服务器正确支持的那些协议的 SSLSocket 实例。

对托管个人资料的支持

设备管理员可以向设备添加托管个人资料。此个人资料由管理员拥有,管理员可以控制托管个人资料,同时用户的个人个人资料及其存储空间仍由用户控制。此变更可能以下列方式影响您现有应用的行为。

处理 intent

设备管理员可以限制从托管个人资料访问系统应用。在这种情况下,如果应用从托管个人资料触发了一个通常由该应用处理的 intent,并且在托管个人资料上没有适合该 intent 的处理程序,则该 intent 会导致异常。例如,设备管理员可以限制托管个人资料上的应用访问系统的相机应用。如果您的应用在托管个人资料上运行并为 MediaStore.ACTION_IMAGE_CAPTURE 调用 startActivityForResult(),并且托管个人资料上没有可以处理该 intent 的应用,则会导致 ActivityNotFoundException

您可以通过在触发任何 intent 之前检查至少有一个处理程序来防止这种情况。要检查有效的处理程序,请调用 Intent.resolveActivity()。您可以在简单拍照:使用相机应用拍照中看到一个执行此操作的示例。

跨个人资料共享文件

每个个人资料都有自己的文件存储。由于文件 URI 指向文件存储中的特定位置,这意味着在一个个人资料上有效的文件 URI 在另一个个人资料上无效。对于应用来说,这通常不是问题,因为它通常只访问它创建的文件。但是,如果应用将文件附加到 intent,附加文件 URI 是不安全的,因为在某些情况下,intent 可能在另一个个人资料上处理。例如,设备管理员可以指定图像捕获事件应由个人资料上的相机应用处理。如果 intent 由托管个人资料上的应用触发,相机需要能够将图像写入托管个人资料的应用可以读取的位置。

为了安全起见,当您需要将文件附加到可能从一个个人资料跨越到另一个个人资料的 intent 时,您应该为文件创建并使用一个内容 URI。有关使用内容 URI 共享文件的更多信息,请参阅共享文件。例如,设备管理员可能允许 ACTION_IMAGE_CAPTURE 由个人资料中的相机处理。触发 intent 的 EXTRA_OUTPUT 应包含一个内容 URI,指定照片应存储的位置。相机应用可以将图像写入该 URI 指定的位置,并且即使应用位于另一个个人资料上,触发 intent 的应用也能够读取该文件。

锁屏微件支持已移除

Android 5.0 移除了对锁屏微件的支持;它继续支持主屏幕上的微件。