通过goole官网摘要
在 Android 5.0 中,ART 运行时取代 Dalvik 成为平台默认设置。Android 4.4 中已引入处于实验阶段的 ART 运行时。
有关 ART 的新功能概述,请参阅 ART 简介。部分主要的新功能包括:
大多数 Android 应用无需任何更改就可以在 ART 下工作。不过,部分适合 Dalvik 的技术并不适用于 ART。如需了解有关最重要问题的信息,请参阅在 Android Runtime (ART) 上验证应用行为。如存在以下情况,应特别注意:
请确保您的通知考虑了上述 Android 5.0 变更。要详细了解如何为 Android 5.0 及更高版本设计通知,请参阅通知设计指南。
在白色(或非常浅)的背景上使用深色文本绘制通知,以便与新的 Material Design 小部件匹配。请确保您的所有通知都与新的配色方案协调一致。如果您的通知看上去不协调,请进行修正:
setColor()
在您的图标图像后面的圆形中设置重点色彩。 如果您当前使用 Ringtone
、MediaPlayer
或 Vibrator
类向通知中添加声音和振动,则移除此代码,以便系统可以在“优先”模式中正确显示通知。取而代之的是,使用 Notification.Builder
方法添加声音和振动。
将设备设为 RINGER_MODE_SILENT
可使设备进入新的优先模式。如果您将设备设为 RINGER_MODE_NORMAL
或 RINGER_MODE_VIBRATE
,则设备将退出优先模式。
以前,Android 使用 STREAM_MUSIC
作为主流式传输来控制平板电脑设备上的音量。在 Android 5.0 中,手机和平板电脑设备的主音量流式传输现已合并,由 STREAM_RING
或 STREAM_NOTIFICATION
进行控制。
默认情况下,在 Android 5.0 中,通知现在显示在用户的锁定屏幕上。用户可以选择保护敏感信息不被公开,在此情况下,系统会自动删减通知显示的文本。要自定义此删减的通知,请使用 setPublicVersion()
。
如果通知不包含个人信息,或者您想允许媒体播放控件显示在通知上,则调用 setVisibility()
方法并将通知的可见性级别设为 VISIBILITY_PUBLIC
。
如果您要实现显示媒体播放状态或传输控件的通知,请考虑使用新的 Notification.MediaStyle
模板,而不是自定义 RemoteViews.RemoteView
对象。无论您选择使用哪个方法,请务必将通知的可见性设为 VISIBILITY_PUBLIC
,以便可通过锁定屏幕访问您的控件。请注意,从 Android 5.0 开始,系统不再将 RemoteControlClient
对象显示在锁定屏幕上。如需了解详细信息,请参阅如果您的应用使用 RemoteControlClient。
现在,当设备处于活动状态时(即,设备未锁定且其屏幕已打开),通知可以显示在小型浮动窗口中(也称为“浮动通知”)。这些通知看上去类似于精简版的通知,只是浮动通知还显示操作按钮。用户可以在不离开当前应用的情况下处理或清除浮动通知。
可能触发浮动通知的条件示例包括:
fullScreenIntent
)如果您的应用在以上任何情形下实现通知,请确保系统正确显示浮动通知。
RemoteControlClient
类现已弃用。请尽快切换到新的 MediaSession
API。
Android 5.0 中的锁定屏幕不会为 MediaSession
或 RemoteControlClient
显示传输控件。不过,您的应用可以通过一个通知从锁定屏幕提供媒体播放控件。这让您的应用可以对媒体按钮的显示进行更多控制,同时为使用锁定设备和未锁定设备的用户提供一致的体验。
为实现此目的,Android 5.0 引入了一个新的 Notification.MediaStyle
模板。Notification.MediaStyle
将您使用 Notification.Builder.addAction()
添加的通知操作转换为精简按钮,嵌入到应用的媒体播放通知中。将您的会话令牌传递到 setSession()
方法以告知系统该通知控制进行中的媒体会话。
请务必将通知的可见性设为 VISIBILITY_PUBLIC
,以将通知标记为安全,从而显示在任何锁定屏幕上(以安全方式或其他方式)。如需了解详细信息,请参阅锁定屏幕通知。
要让应用在 Android TV 或 Wear 平台上运行时显示媒体播放控件,则实现 MediaSession
类。如果您的应用需要在 Android 设备上接收媒体按钮事件,您还应实现 MediaSession
。
Android 5.0 中引入新的“并发文档和 Activity 任务”功能后(请参阅下文最近使用的应用屏幕中的并发文档和 Activity),为提升用户隐私的安全性,现已弃用 ActivityManager.getRecentTasks()
方法。对于向后兼容性,此方法仍会返回它的一小部分数据,包括调用应用自己的任务和可能的一些其他非敏感任务(如首页)。如果您的应用使用此方法检索它自己的任务,则改用 getAppTasks()
检索该信息。
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 进行的重要变更和问题修复的更多信息,请参阅 Revision 10c 版本说明。
Context.bindService()
方法现在需要显式 Intent
,如果提供隐式 intent,将引发异常。为确保应用的安全性,请使用显式 intent 启动或绑定 Service
,且不要为服务声明 intent 过滤器。
Android 5.0 更改了应用的默认行为。
setMixedContentMode()
和 setAcceptThirdPartyCookies()
方法。enableSlowWholeDocumentDraw()
停用此优化。 根据权限概述中所述,Android 应用可以定义以专有方式管理组件访问权限的自定义权限,无需使用平台预定义的系统权限。应用在其清单文件中声明的
元素中定义自定义权限。
少数情况下定义自定义权限是合规且安全的方法。不过,创建自定义权限有时并无必要,甚至可能会给应用带来潜在风险,具体取决于分配给权限的保护级别。
Android 5.0 其中一项行为变更确保只有一个应用可以定义给定自定义权限,除非使用与定义权限的其他应用相同的密钥进行签名。
任何应用都可以定义它需要的任何自定义权限,因此,可能会出现多个应用定义相同的自定义权限的情况。例如,如果两个应用提供相似的功能,它们可能会为其自定义权限派生出相同的逻辑名称。应用可能还纳入了本身包含相同自定义权限定义的通用公共库或代码示例。
在 Android 4.4 和更早的版本中,用户可以在给定设备上安装多个此类应用,不过系统会分配由第一个安装的应用指定的保护级别。
从 Android 5.0 开始,对于使用不同密钥签名的应用,系统会强制执行新的自定义权限唯一性限制。现在,设备上只有一个应用可以定义给定的自定义权限(按其名称确定),除非定义此权限的其他应用使用相同密钥签名。如果用户尝试安装的应用具有重复自定义权限且签名密钥不同于定义此权限的驻留应用,则系统将阻止安装。
在 Android 5.0 和更新的版本中,应用可以和以前一样继续定义自己的自定义权限,并通过
机制请求其他应用的自定义权限。不过,对于 Android 5.0 中引入的新要求,您应仔细评估可能给您的应用带来的影响。
下面是一些需要考虑的因素:
元素?如果是,那么这些权限是否确实是您的应用或服务正常运行不可或缺的?或者,能否使用系统默认权限代替它们?
元素,您是否知道它们来自哪里?
请求您的自定义权限?
元素的应用中使用样板文件或示例代码?那些权限元素确实是不可或缺的吗?如上所述,在运行 Android 4.4 或更早版本的设备上新安装和更新您的应用不会受影响,且行为没有任何变化。在运行 Android 5.0 或更新版本的设备上进行新安装和更新时,如果应用定义一个已由现有驻留应用定义的自定义权限,则系统会阻止安装您的应用。
如果您的应用使用自定义更新且已广泛分发和安装,那么,当用户收到将设备升级到 Android 5.0 的更新时,您的应用可能会受影响。在安装系统更新后,系统重新验证已安装的应用,包括检查它们的自定义权限。如果您的应用定义一个已由另一个通过验证的应用定义的自定义权限,且您的应用没有使用与该应用相同的密钥签名,则系统不会重新安装您的应用。
在运行 Android 5.0 或更新版本的设备上,我们建议您立即检查您的应用,进行任何所需的调整,并尽快向您的用户发布更新版本。
元素,除非您确定它们是应用正常运行所必需的元素。
机制请求访问权限。Android 5.0 针对 HTTPS 和其他 TLS/SSL 通信引入了对应用使用的默认 TLS/SSL 配置的变更:
在下面列出的少数情况下,这些变更可能会导致 HTTPS 或 TLS/SSL 连接断开。
请注意,来自 Google Play 服务的安全性 ProviderInstaller 自 Android 2.3 开始就已在 Android 平台版本上提供这些变更。
例如,服务器可能仅支持 3DES 或 MD5 加密套件。首选的修复方法是改进服务器的配置,以启用更强更现代的加密套件和协议。理想情况下,应启用 TLSv1.2 和 AES-GCM 以及 Forward Secrecy 加密套件(ECDHE、DHE),且最好使用后者。
也可以修改应用以使用自定义 SSLSocketFactory 与服务器通信。出厂时应精心设计以创建 SSLSocket 实例,除默认加密套件外,此实例还应启用服务器所需的部分加密套件。
例如,某些应用包含中断的自定义 X509TrustManager,因为它预计 authType 参数将成为 RSA,但出现了 ECDHE_RSA 或 DHE_RSA。
例如,与服务器握手的 TLS/SSL 被错误地拒绝或出现停顿。首选的修复方法是升级服务器以符合 TLS/SSL 协议。这使服务器可以成功地协商这些更新的协议或协商 TLSv1 或更早的协议,并忽略它不理解的传输层安全协议扩展程序。在某些情况下,在服务器上禁用 TLSv1.1 和 TLSv1.2 可以作为权宜之计,直到升级服务器软件。
也可以修改应用以使用自定义 SSLSocketFactory 与服务器通信。出厂时应精心设计以创建 SSLSocket 实例,该实例仅包含已启用且服务器可以正确为其提供支持的协议。
设备管理员可以向设备添加托管配置文件。此配置文件由管理员所有,让管理员控制托管配置文件的同时,允许由用户控制其自己的个人配置文件及其存储空间。此变更会通过下列方式影响您的现有应用的行为。
设备管理员可以从托管配置文件限制对系统应用的访问权限。在此情况下,如果应用从托管文件触发一个通常由该应用处理的 intent,且托管文件上没有适合此 intent 的处理程序,则此 intent 会引发异常。例如,设备管理员可以限制托管配置文件上的应用访问系统的相机应用。如果您的应用在托管配置文件上运行,并为 MediaStore.ACTION_IMAGE_CAPTURE
调用 startActivityForResult()
,且托管配置文件上没有可以处理此 intent 的应用,则会导致 ActivityNotFoundException
。
为防止出现此情况,您可以在触发任何 intent 之前检查是否至少有一个适合此 intent 的处理程序。要检查是否存在有效的处理程序,请调用 Intent.resolveActivity()
。您可以在轻松拍照:使用相机应用拍摄照片中查看执行上述操作的示例。
每个配置文件都有自己的文件存储空间。文件 URI 指的是文件存储空间中的特定位置,这意味着在一个配置文件上有效的文件 URI 在另一个文件上是无效的。对于只访问自己创建的文件的应用而言,这通常不是什么问题。不过,如果应用向某个 intent 附加文件,则附加文件 URI 并不安全,因为在某些情况下,可能会在其他配置文件上处理该 intent。例如,设备管理员可能会指定图像采集事件应由个人配置文件上的相机应用处理。如果此 intent 由托管配置文件上的应用触发,则相机需要能够将图像写入托管配置文件的应用可以读取的位置。
为安全起见,如果您需要将文件附加到某个可能会从一个配置文件移动到另一个配置文件的 intent,您应为该文件创建并使用内容 URI。有关共享文件及内容 URI 的更多信息,请参阅共享文件。例如,设备管理员可能会制定将由个人配置文件中的相机处理的 ACTION_IMAGE_CAPTURE
白名单。触发的 intent 的 EXTRA_OUTPUT
应包含指定照片应存储在何处的内容 URI。相机应用可以将图像写入该 URI 指定的位置,触发 intent 的应用将能够读取该文件,即使应用位于其他配置文件上。
此版本引入了一种新的权限模式,如今,用户可直接在运行时管理应用权限。这种模式让用户能够更好地了解和控制权限,同时为应用开发者精简了安装和自动更新过程。用户可为所安装的各个应用分别授予或撤销权限。
对于以 Android 6.0(API 级别 23)或更高版本为目标平台的应用,请务必在运行时检查和请求权限。要确定您的应用是否已被授予权限,请调用新增的 checkSelfPermission()
方法。要请求权限,请调用新增的 requestPermissions()
方法。即使您的应用并不以 Android 6.0(API 级别 23)为目标平台,您也应该在新权限模式下测试您的应用。
如需了解有关在您的应用中支持新权限模式的详情,请参阅使用系统权限。如需了解有关如何评估新模式对应用的影响的提示,请参阅权限最佳做法。
此版本引入了针对空闲设备和应用的最新节能优化技术。这些功能会影响所有应用,因此请务必在这些新模式下测试您的应用。
要详细了解这些节能变更,请参阅对低电耗模式和应用待机模式进行针对性优化。
Android 6.0 版移除了对 Apache HTTP 客户端的支持。如果您的应用使用该客户端,并以 Android 2.3(API 级别 9)或更高版本为目标平台,请改用 HttpURLConnection
类。此 API 效率更高,因为它可以通过透明压缩和响应缓存减少网络使用,并可最大限度降低耗电量。要继续使用 Apache HTTP API,您必须先在 build.gradle
文件中声明以下编译时依赖项:
android { useLibrary 'org.apache.http.legacy' }
Android 正在从使用 OpenSSL 库转向使用 BoringSSL 库。如果您要在应用中使用 Android NDK,请勿链接到并非 NDK API 组成部分的加密库,如 libcrypto.so
和 libssl.so
。这些库并非公共 API,可能会在不同版本和设备上毫无征兆地发生变化或出现故障。此外,您还可能让自己暴露在安全漏洞的风险之下。请改为修改原生代码,以通过 JNI 调用 Java 加密 API,或静态链接到您选择的加密库。
为给用户提供更严格的数据保护,从此版本开始,对于使用 WLAN API 和 Bluetooth API 的应用,Android 移除了对设备本地硬件标识符的编程访问权。WifiInfo.getMacAddress()
方法和 BluetoothAdapter.getAddress()
方法现在会返回常量值 02:00:00:00:00:00
。
现在,要通过蓝牙和 WLAN 扫描访问附近外部设备的硬件标识符,您的应用必须拥有 ACCESS_FINE_LOCATION
或 ACCESS_COARSE_LOCATION
权限。
WifiManager.getScanResults()
BluetoothDevice.ACTION_FOUND
BluetoothLeScanner.startScan()
注:当运行 Android 6.0(API 级别 23)的设备发起后台 WLAN 或蓝牙扫描时,在外部设备看来,该操作的发起来源是一个随机化 MAC 地址。
此版本移除了 Notification.setLatestEventInfo()
方法。请改用 Notification.Builder
类来构建通知。要重复更新通知,请重复使用 Notification.Builder
实例。调用 build()
方法可获取更新后的 Notification
实例。
adb shell dumpsys notification
命令不再打印输出您的通知文本。请改用 adb shell dumpsys notification --noredact
命令打印输出 notification 对象中的文本。
不再支持通过 AudioManager
类直接设置音量或将特定音频流静音。setStreamSolo()
方法已弃用,您应该改为调用 requestAudioFocus()
方法。类似地,setStreamMute()
方法也已弃用,请改为调用 adjustStreamVolume()
方法并传入方向值 ADJUST_MUTE
或 ADJUST_UNMUTE
。
现在,当用户在您的应用中选择文本时,您可以在一个浮动工具栏中显示“剪切”、“复制”和“粘贴”等文本选择操作。其在用户交互实现上与为单个视图启用上下文操作模式中所述的上下文操作栏类似。
要实现可用于文本选择的浮动工具栏,请在您的现有应用中做出以下更改:
View
对象或 Activity
对象中,将 ActionMode
调用从 startActionMode(Callback)
更改为 startActionMode(Callback, ActionMode.TYPE_FLOATING)
。ActionMode.Callback
的现有实现扩展 ActionMode.Callback2
。onGetContentRect()
方法,用于提供 Rect
内容对象(如文本选择矩形)在视图中的坐标。invalidateContentRect()
方法。 请注意,如果您使用 Android 支持库 22.2 修订版,浮动工具栏不向后兼容,默认情况下 appcompat 会获得对 ActionMode
对象的控制权。这会禁止显示浮动工具栏。要在 ActionMode
中启用 AppCompatActivity
支持,请调用 getDelegate()
,然后对返回的 setHandleNativeActionModesEnabled()
对象调用 AppCompatDelegate
,并将输入参数设置为 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 密钥库提供程序不再支持 DSA。但仍支持 ECDSA。
停用或重置安全锁定屏幕时(例如,由用户或设备管理员执行此类操作时),系统将不再删除需要闲时加密的密钥,但在上述事件期间会删除需要闲时加密的密钥。
此版本对 WLAN API 和 Networking API 引入了以下行为变更。
WifiConfiguration
对象的状态。系统不允许您修改或删除由用户或其他应用创建的 WifiConfiguration
对象。disableAllOthers=true
设置的 enableNetwork()
强制设备连接特定 WLAN 网络,设备将会断开与移动数据网络等其他网络的连接。在此版本中,设备不再断开与上述其他网络的连接。如果您的应用的 targetSdkVersion
为 “20”
或更低,则会固定连接所选 WLAN 网络。如果您的应用的 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_LOCAL
的 dlopen(3)
调用将受到影响(除非您的应用显式使用 RTLD_GLOBAL
)。使用 RTLD_LOCAL
时,在随后通过调用 dlopen(3)
加载的库中并不能使用这些符号(这与由 DT_NEEDED
条目引用的情况截然不同)。
在之前版本的 Android 上,如果您的应用请求系统加载包含文本重定位信息的共享库,系统会显示警告,但仍允许加载共享库。从此版本开始,如果您的应用的目标 SDK 版本为 23 或更高,则系统会拒绝加载该库。为帮助您检测库是否加载失败,您的应用应该记录 dlopen(3)
失败日志,并在日志中加入 dlerror(3)
调用返回的问题描述文本。要详细了解如何处理文本重定位,请参阅此指南。
该平台现在执行的 APK 验证更为严格。如果在清单中声明的文件在 APK 中并不存在,该 APK 将被视为已损坏。移除任何内容后必须重新签署 APK。
默认情况下,现在通过 USB 端口进行的设备连接设置为仅充电模式。要通过 USB 连接访问设备及其内容,用户必须明确地为此类交互授予权限。如果您的应用支持用户通过 USB 端口与设备进行交互,请将必须显式启用交互考虑在内。
此版本包含下列针对 Android for Work 的行为变更:
setCrossProfileCallerIdDisabled()
设置为 true
可在 Google 拨号器通话记录中隐藏托管配置文件联系人。仅当您将 setBluetoothContactSharingDisabled()
设置为 false
时,才可以通过蓝牙将工作联系人随个人联系人一起显示给设备。默认情况下,它设置为 true
。addNetwork()
方法添加的配置)。WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN
不为零,则用户无法再修改或删除任何由活动设备所有者创建的 WLAN 配置。用户仍可创建和修改其自己的 WLAN 配置。活动设备所有者拥有编辑或删除任何 WLAN 配置(包括并非由其创建的配置)的权限。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。EXTRA_PROVISIONING_RESET_PROTECTION_PARAMETERS
已删除,因此 NFC 占位配置无法通过编程解锁受恢复出厂设置保护的设备EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE
extra 在对托管设备进行 NFC 配置期间向设备所有者应用传递数据。DevicePolicyManager
权限 API 不会影响 M 之前版本的应用。ACTION_PROVISION_MANAGED_PROFILE
或 ACTION_PROVISION_MANAGED_DEVICE
intent 发起的设置流程的同步部分时,系统现在会返回 RESULT_CANCELED
结果代码。android.app.usage.NetworkUsageStats
类已重命名为 NetworkStats
。setGlobalSettings()
进行设置:
BLUETOOTH_ON
DEVELOPMENT_SETTINGS_ENABLED
MODE_RINGER
NETWORK_PREFERENCE
WIFI_ON
setGlobalSettings()
进行设置:
WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN
Android 7.0 除了提供诸多新特性和功能外,还对系统和 API 行为做出了各种变更。本文重点介绍您应该了解并在开发应用时加以考虑的一些主要变更。
如果您之前发布过 Android 应用,请注意您的应用可能受到这些平台变化的影响。
Android 7.0 包括旨在延长设备电池寿命和减少 RAM 使用的系统行为变更。这些变更可能会影响您的应用访问系统资源,以及您的应用通过特定隐式 intent 与其他应用交互的方式。
Android 6.0(API 级别 23)引入了低电耗模式,当用户设备未插接电源、处于静止状态且屏幕关闭时,该模式会推迟 CPU 和网络活动,从而延长电池寿命。而 Android 7.0 则通过在设备未插接电源且屏幕关闭状态下、但不一定要处于静止状态(例如用户外出时把手持式设备装在口袋里)时应用部分 CPU 和网络限制,进一步增强了低电耗模式。
当设备处于充电状态且屏幕已关闭一定时间后,设备会进入低电耗模式并应用第一部分限制:关闭应用网络访问、推迟作业和同步。如果进入低电耗模式后设备处于静止状态达到一定时间,系统则会对 PowerManager.WakeLock
、AlarmManager
闹铃、GPS 和 WLAN 扫描应用余下的低电耗模式限制。无论是应用部分还是全部低电耗模式限制,系统都会唤醒设备以提供简短的维护时间窗口,在此窗口期间,应用程序可以访问网络并执行任何被推迟的作业/同步。
请注意,激活屏幕或插接设备电源时,系统将退出低电耗模式并移除这些处理限制。此项新增的行为不会影响有关使您的应用适应 Android 6.0(API 级别 23)中所推出的旧版本低电耗模式的建议和最佳做法,如对低电耗模式和应用待机模式进行针对性优化中所讨论。您仍应遵循这些建议(例如使用 Google 云消息传递 (GCM) 发送和接收消息)并开始安排更新计划以适应新增的低电耗模式行为。
Android 7.0 移除了三项隐式广播,以帮助优化内存使用和电量消耗。此项变更很有必要,因为隐式广播会在后台频繁启动已注册侦听这些广播的应用。删除这些广播可以显著提升设备性能和用户体验。
移动设备会经历频繁的连接变更,例如在 WLAN 和移动数据之间切换时。目前,可以通过在应用清单中注册一个接收器来侦听隐式 CONNECTIVITY_ACTION
广播,让应用能够监控这些变更。由于很多应用会注册接收此广播,因此单次网络切换即会导致所有应用被唤醒并同时处理此广播。
同理,在之前版本的 Android 中,应用可以注册接收来自其他应用(例如相机)的隐式 ACTION_NEW_PICTURE
和 ACTION_NEW_VIDEO
广播。当用户使用相机应用拍摄照片时,这些应用即会被唤醒以处理广播。
为缓解这些问题,Android 7.0 应用了以下优化措施:
CONNECTIVITY_ACTION
广播,即使它们已有清单条目来请求接受这些事件的通知。在前台运行的应用如果使用 BroadcastReceiver
请求接收通知,则仍可以在主线程中侦听 CONNECTIVITY_CHANGE
。ACTION_NEW_PICTURE
或 ACTION_NEW_VIDEO
广播。此项优化会影响所有应用,而不仅仅是面向 Android 7.0 的应用。 如果您的应用使用任何 intent,您仍需要尽快移除它们的依赖关系,以正确适配 Android 7.0 设备。Android 框架提供多个解决方案来缓解对这些隐式广播的需求。例如,JobScheduler
API 提供了一个稳健可靠的机制来安排满足指定条件(例如连入无限流量网络)时所执行的网络操作。您甚至可以使用 JobScheduler
来适应内容提供程序变化。
如需了解有关 Android N 中后台优化以及如何改写应用的详细信息,请参阅后台优化。
Android 7.0 做了一些权限更改,这些更改可能会影响您的应用。
为了提高私有文件的安全性,面向 Android 7.0 或更高版本的应用私有目录被限制访问 (0700
)。此设置可防止私有文件的元数据泄漏,如它们的大小或存在性。此权限更改有多重副作用:
MODE_WORLD_READABLE
和/或 MODE_WORLD_WRITEABLE
而进行的此类尝试将触发 SecurityException
。 注:迄今为止,这种限制尚不能完全执行。应用仍可能使用原生 API 或 File
API 来修改它们的私有目录权限。但是,我们强烈反对放宽私有目录的权限。
file://
URI 可能给接收器留下无法访问的路径。因此,尝试传递 file://
URI 会触发 FileUriExposedException
。分享私有文件内容的推荐方法是使用 FileProvider
。DownloadManager
不再按文件名分享私人存储的文件。旧版应用在访问 COLUMN_LOCAL_FILENAME
时可能出现无法访问的路径。面向 Android 7.0 或更高版本的应用在尝试访问 COLUMN_LOCAL_FILENAME
时会触发 SecurityException
。通过使用 DownloadManager.Request.setDestinationInExternalFilesDir()
或 DownloadManager.Request.setDestinationInExternalPublicDir()
将下载位置设置为公共位置的旧版应用仍可以访问 COLUMN_LOCAL_FILENAME
中的路径,但是我们强烈反对使用这种方法。对于由 DownloadManager
公开的文件,首选的访问方式是使用ContentResolver.openFileDescriptor()
。 对于面向 Android 7.0 的应用,Android 框架执行的 StrictMode
API 政策禁止在您的应用外部公开 file://
URI。如果一项包含文件 URI 的 intent 离开您的应用,则应用出现故障,并出现 FileUriExposedException
异常。
要在应用间共享文件,您应发送一项 content://
URI,并授予 URI 临时访问权限。进行此授权的最简单方式是使用 FileProvider
类。如需了解有关权限和共享文件的详细信息,请参阅共享文件。
为提高平台对于视力不佳或视力受损用户的易用性,Android 7.0 做出了一些更改。这些更改一般并不要求更改您的应用代码,不过您应仔细检查并使用您的应用测试这些功能,以评估它们对用户体验的潜在影响。
Android 7.0 支持用户设置显示尺寸,以放大或缩小屏幕上的所有元素,从而提升设备对视力不佳用户的可访问性。用户无法将屏幕缩放至低于最小屏幕宽度 sw320dp,该宽度是 Nexus 4 的宽度,也是常规中等大小手机的宽度。
当设备密度发生更改时,系统会以如下方式通知正在运行的应用:
大多数应用并不需要进行任何更改即可支持此功能,不过前提是这些应用遵循 Android 最佳做法。具体要检查的事项:
sw320dp
的设备上测试您的应用,并确保其充分运行。注:如果您要缓存与配置相关的数据,则最好也包括相关元数据,例如该数据对应的屏幕尺寸或像素密度。保存这些元数据便于您在配置变更后决定是否需要刷新缓存数据。
dp
) 单位指定尺寸。Android 7.0 在“Welcome”屏幕中加入了“Vision Settings”,用户可以在新设备上设置以下无障碍功能设置:Magnification gesture、Font size、Display size 和话语提示。此项变更让您可以更容易发现与不同屏幕设置有关的错误。要评估此功能的影响,您应在启用这些设置的状态下测试应用。您可以在 Settings > Accessibility 中找到这些设置。
从 Android 7.0 开始,系统将阻止应用动态链接非公开 NDK 库,这种库可能会导致您的应用崩溃。此行为变更旨在为跨平台更新和不同设备提供统一的应用体验。即使您的代码可能不会链接私有库,但您的应用中的第三方静态库可能会这么做。因此,所有开发者都应进行相应检查,确保他们的应用不会在运行 Android 7.0 的设备上崩溃。如果您的应用使用原生代码,则只能使用公开 NDK API。
您的应用可通过以下三种方式尝试访问私有平台 API:
libcrypto.so
的 Android 平台版本上运行。不过,此应用在不包含此库的新版 Android(例如,Android 6.0 和更高的版本)上会崩溃。为修复此问题,请确保您的 APK 捆绑您的所有非 NDK 库。应用不应使用 NDK 中未包含的原生库,因为这些库可能会发生更改或在不同 Android 版本之间的可用性不同。例如,从 OpenSSL 切换至 BoringSSL 即属于此类更改。此外,由于不属于 NDK 中的平台库没有兼容性要求,因此不同的设备可能提供不同级别的兼容性。
为降低此限制可能对当前发布的应用的影响,面向 API 级别 23 或更低级别的应用在 Android N 上可暂时访问颇为常用的一组库,例如 libandroid_runtime.so
、libcutils.so
、libcrypto.so
和 libssl.so
。如果您的应用加载其中某个库,logcat 会生成一个警告,并在目标设备上显示一个 Toast 来通知您。如果您看到这些警告,您应更新您的应用以添加该应用自己的库副本,或仅使用公开 NDK API。将来发布的 Android 平台可能会完全限制对私有库的使用,并导致您的应用崩溃。
所有应用在调用既非公开又不可暂时访问的 API 时都会生成一个运行时错误。结果就是 System.loadLibrary
和 dlopen(3)
同时返回 NULL
,并可能导致您的应用崩溃。您应检查应用代码以移除对私有平台 API 的使用,并使用预览版设备或模拟器全面测试应用。如果您不确定您的应用是否使用私有库,您可以检查 logcat 以识别运行时错误。
下表描述的是根据应用使用的私有原生库及其目标 API 级别 (android:targetSdkVersion
),应用预期显示的行为。
库 | 目标 API 级别 | 通过动态链接器进行运行时访问 | N Developer Preview 行为 | 最终 Android N 版本行为 | 未来的 Android 平台行为 |
---|---|---|---|---|---|
公开 NDK | 任意 | 可访问 | 合乎预期 | 合乎预期 | 合乎预期 |
私有(暂时可访问的私有库) | 23 或更低 | 暂时可访问 | 合乎预期,但您会在目标设备上收到一个 logcat 警告和一条消息。 | 合乎预期,但您会收到一个 logcat 警告。 | 运行时错误 |
私有(暂时可访问的私有库) | 24 或更高 | 受限 | 运行时错误 | 运行时错误 | 运行时错误 |
私有(其他) | 任意 | 受限 | 运行时错误 | 运行时错误 | 运行时错误 |
为帮助您识别加载私有库的问题,logcat 可能会生成一个警告或运行时错误。例如,如果您的应用面向 API 级别 23 或更低级别,并在运行 Android 7.0 的设备上尝试访问私有库,您可能会看到一个类似于下面所示的警告:
03-21 17:07:51.502 31234 31234 W linker : library "libandroid_runtime.so" ("/system/lib/libandroid_runtime.so") needed or dlopened by "/data/app/com.popular-app.android-2/lib/arm/libapplib.so" is not accessible for the namespace "classloader-namespace" - the access is temporarily granted as a workaround for http://b/26394120
这些 logcat 警告通知您哪个库正在尝试访问私有平台 API,但不会导致您的应用崩溃。但是,如果应用面向 API 级别 24 或更高级别,logcat 会生成以下运行时错误,您的应用可能会崩溃:
java.lang.UnsatisfiedLinkError: dlopen failed: library "libcutils.so" ("/system/lib/libcutils.so") needed or dlopened by "/system/lib/libnativeloader.so" is not accessible for the namespace "classloader-namespace" at java.lang.Runtime.loadLibrary0(Runtime.java:977) at java.lang.System.loadLibrary(System.java:1602)
如果您的应用使用动态链接到私有平台 API 的第三方库,您可能也会看到上述 logcat 输出。利用 Android 7.0DK 中的 readelf 工具,您可以通过运行以下命令生成给定 .so
文件的所有动态链接的共享库列表:
aarch64-linux-android-readelf -dW libMyLibrary.so
通过下面的一些步骤,您可以修复上述类型的错误并确保您的应用不会在将来的更新版平台上崩溃:
libandroid_runtime.so
的 getJavaVM
和 getJNIEnv
: AndroidRuntime::getJavaVM -> GetJavaVM fromAndroidRuntime::getJNIEnv -> JavaVM::GetEnv or JavaVM::AttachCurrentThread from .
__system_property_get
而非来自 libcutils.so
的私有 property_get
符号。为此,请使用 __system_property_get
及以下 include 函数: #include
注:系统属性的可用性和内容未通过 CTS 进行测试。应执行进一步修复以避免同时使用这些属性。
libcrypto.so
的 SSL_ctrl
符号的本地版本。例如,您应在您的 .so
文件中静态链接 libcyrpto.a
,或从 BoringSSL/OpenSSL 添加一个动态链接的 libcrypto.so
版本,并将其打包到您的 APK 中。Android 7.0 包含一些针对面向 Android for Work 的应用的变更,包括对证书安装、密码重置、二级用户管理、设备标识符访问权限的变更。如果您是要针对 Android for Work 环境开发应用,则应仔细检查这些变更并相应地修改您的应用。
DevicePolicyManager.setCertInstallerPackage()
之前安装授权证书安装程序。如果尚未安装此安装程序,则系统会引发 IllegalArgumentException
。DevicePolicyManager.resetPassword()
来清除或更改已经设置的密码。设备管理员仍可以设置密码,但只能在设备没有密码、PIN 码或图案时这样做。DISALLOW_MODIFY_ACCOUNTS
用户限制,设备所有者和配置文件所有者仍可调用 Account Management API。DISALLOW_ADD_USER
限制。这样可以防止用户创建非托管二级用户。此外,CreateUser()
和 createAndInitializeUser()
方法已弃用,取而代之的是 DevicePolicyManager.createAndManageUser()
方法。DevicePolicyManagewr.getWifiMacAddress()
访问设备的 WLAN MAC 地址。如果设备上从未启用 WLAN,则此方法将返回一个 null
值。KeyChain.getCertificateChain()
的结果。如果需要,使用 .crt 或 .cer 文件扩展名的 DER 编码格式通过 Settings UI 单独将 CA 证书安装到受信任的凭据存储空间。DevicePolicyManager.getStorageEncryptionStatus()
返回新的加密状态 ENCRYPTION_STATUS_ACTIVE_PER_USER
,以表明加密处于活动状态,且加密密钥与用户关联。仅当 DPC 面向 API 级别 24 和更高级别时才会返回新的状态。对于面向更早的 API 级别的应用,即使加密密钥是用户或配置文件特有的,系统也会返回 ENCRYPTION_STATUS_ACTIVE
。DevicePolicyManager.getParentProfileInstance()
文档中。)例如,DevicePolicyManager.lockNow()
只锁定托管配置文件,而不是锁定整个设备。对于上述每个方法,您可以通过对 DevicePolicyManager
的父实例调用该方法来获取以前的行为;您可以通过调用 DevicePolicyManager.getParentProfileInstance()
获取此父项。例如,如果您调用父实例的 lockNow()
方法,则整个设备将被锁定。如需了解有关 Android 7.0 中针对 Android for Work 所做变更的详细信息,请参阅 Android for Work 更新。
Android 7.0 修复了一个注解可见性被忽略的错误。这种问题会导致应用可在运行时访问原本不允许访问的注解。这些注解包括:
VISIBILITY_BUILD
:仅应编译时可见。VISIBILITY_SYSTEM
:运行时应可见,但仅限底层系统。 如果您的应用依赖这种行为,请为运行时必须可用的注解添加保留政策。您可通过使用 @Retention(RetentionPolicy.RUNTIME)
来执行此操作。
您应测试应用以确保不会发生此行为。要进行此测试,您可以通过 DDMS 手动终止应用,以造成相同的崩溃现象。
在密度发生更改时,系统不会自动终止面向 N 及更高版本的应用;不过,这些应用仍可能对配置变更做出不良响应。
android.os.NetworkOnMainThreadException
。一般情况下,我们不建议在主线程上执行网络操作,因为这些操作通常会出现可能导致 ANR 和卡顿的高尾延迟。Debug.startMethodTracing()
方法系列现在默认在您的共享存储空间上的软件包特定目录中存储输出,而非 SD 卡根目录。这意味着应用不再需要请求 WRITE_EXTERNAL_STORAGE
权限来使用这些 API 。Binder
事务间发送的大负载,系统现在会将 TransactionTooLargeExceptions
作为 RuntimeExceptions
再次引发,而不再只是默默记录或抑制它们。一个常见例子是在 Activity.onSaveInstanceState()
上存储过多数据,导致 ActivityThread.StopInfo
在您的应用面向 Android 7.0 时引发 RuntimeException
。View
发布 Runnable
任务,并且 View
未附加到窗口,系统会用 View
为 Runnable
任务排队;在 View
附加到窗口之前,不会执行 Runnable
任务。此行为会修复以下错误:
View
,则 Runnable
可能会因此运行错误的线程。Runnable
任务是从并非环路线程的其他线程发布,则应用可能会曝光 Runnable
任务。DELETE_PACKAGES
权限的应用尝试删除一个软件包,但另一项应用已经安装了这个软件包,则系统需要用户进行确认。在这种情况下,应用在调用 PackageInstaller.uninstall()
时预计的返回状态应为 STATUS_PENDING_USER_ACTION
。