7.0 -API 24 行为变更

Android 7.0 除了提供诸多新特性和功能外,还对系统和 API 行为做出了各种变更。本文重点介绍您应该了解并在开发应用时加以考虑的一些主要变更。

如果您之前发布过 Android 应用,请注意您的应用可能受到这些平台变化的影响。

电池和内存

Android 7.0 包括旨在延长设备电池寿命和减少 RAM 使用的系统行为变更。这些变更可能会影响您的应用访问系统资源,以及您的应用通过特定隐式 intent 与其他应用交互的方式。

低电耗模式

Android 6.0(API 级别 23)引入了低电耗模式,当用户设备未插接电源、处于静止状态且屏幕关闭时,该模式会推迟 CPU 和网络活动,从而延长电池寿命。而 Android 7.0 则通过在设备未插接电源且屏幕关闭状态下、但不一定要处于静止状态(例如用户外出时把手持式设备装在口袋里)时应用部分 CPU 和网络限制,进一步增强了低电耗模式。

android电池损耗 安卓电池衰减_Android

 图1,低电耗模式如何应用第一级系统活动限制以延长电池寿命的图示。

当设备处于充电状态且屏幕已关闭一定时间后,设备会进入低电耗模式并应用第一部分限制:关闭应用网络访问、推迟作业和同步。如果进入低电耗模式后设备处于静止状态达到一定时间,系统则会对 PowerManager.WakeLockAlarmManager 闹铃、GPS 和 WLAN 扫描应用余下的低电耗模式限制。无论是应用部分还是全部低电耗模式限制,系统都会唤醒设备以提供简短的维护时间窗口,在此窗口期间,应用程序可以访问网络并执行任何被推迟的作业/同步。

android电池损耗 安卓电池衰减_android电池损耗_02

图2,低电耗模式如何在设备处于静止状态达到一定时间后应用第二级系统活动限制的图示。

请注意,激活屏幕或插接设备电源时,系统将退出低电耗模式并移除这些处理限制。此项新增的行为不会影响有关使您的应用适应 Android 6.0(API 级别 23)中所推出的旧版本低电耗模式的建议和最佳做法,如对低电耗模式和应用待机模式进行针对性优化中所讨论。您仍应遵循这些建议(例如使用 Google 云消息传递 (GCM) 发送和接收消息)并开始安排更新计划以适应新增的低电耗模式行为。

Project Svelte 后台优化

Android 7.0 移除了三项隐式广播,以帮助优化内存使用和电量消耗。此项变更很有必要,因为隐式广播会在后台频繁启动已注册侦听这些广播的应用。删除这些广播可以显著提升设备性能和用户体验。

移动设备会经历频繁的连接变更,例如在 WLAN 和移动数据之间切换时。目前,可以通过在应用清单中注册一个接收器来侦听隐式 CONNECTIVITY_ACTION同理,在之前版本的 Android 中,应用可以注册接收来自其他应用(例如相机)的隐式 ACTION_NEW_PICTURE 和 ACTION_NEW_VIDEO

为缓解这些问题,Android 7.0 应用了以下优化措施:

  • 面向 Android 7.0 开发的应用不会收到 

CONNECTIVITY_ACTION

  •  广播,即使它们已有清单条目来请求接受这些事件的通知。在前台运行的应用如果使用 

BroadcastReceiver

  •  请求接收通知,则仍可以在主线程中侦听 

CONNECTIVITY_CHANGE

  • 应用无法发送或接收 

ACTION_NEW_PICTURE

  •  或 

ACTION_NEW_VIDEO如果您的应用使用任何 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

  • 传递软件包网域外的 

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 类。如需了解有关权限和共享文件的详细信息,请参阅共享文件


6.0 -API 23 行为变更

运行时权限

此版本引入了一种新的权限模式,如今,用户可直接在运行时管理应用权限。这种模式让用户能够更好地了解和控制权限,同时为应用开发者精简了安装和自动更新过程。用户可为所安装的各个应用分别授予或撤销权限。

对于以 Android 6.0(API 级别 23)或更高版本为目标平台的应用,请务必在运行时检查和请求权限。要确定您的应用是否已被授予权限,请调用新增的 checkSelfPermission() 方法。要请求权限,请调用新增的 requestPermissions()

如需了解有关在您的应用中支持新权限模式的详情,请参阅使用系统权限。如需了解有关如何评估新模式对应用的影响的提示,请参阅权限最佳做法

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

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

  • 低电耗模式:如果用户拔下设备的电源插头,并在屏幕关闭后的一段时间内使其保持不活动状态,设备会进入低电耗模式,在该模式下设备会尝试让系统保持休眠状态。在该模式下,设备会定期短时间恢复正常工作,以便进行应用同步,还可让系统执行任何挂起的操作。
  • 应用待机模式:应用待机模式允许系统判定应用在用户未主动使用它时处于空闲状态。当用户有一段时间未触摸应用时,系统便会作出此判定。如果拔下了设备电源插头,系统会为其视为空闲的应用停用网络访问以及暂停同步和作业。

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

WLAN 和网络连接变更

此版本对 WLAN API 和 Networking API 引入了以下行为变更。

  • 现在,您的应用只能更改由您创建的 

WifiConfiguration

  •  对象的状态。系统不允许您修改或删除由用户或其他应用创建的 

WifiConfiguration

  • 在之前的版本中,如果应用利用带有 

disableAllOthers=true

  •  设置的 

enableNetwork()

  •  强制设备连接特定 WLAN 网络,设备将会断开与移动数据网络等其他网络的连接。在此版本中,设备不再断开与上述其他网络的连接。如果您的应用的 

targetSdkVersion

  •  为 

“20”

  •  或更低,则会固定连接所选 WLAN 网络。如果您的应用的 

targetSdkVersion

  •  为 

“21”

  •  或更高,请使用多网络 API(如 

openConnection()

bindSocket()

  •  和新增的 

bindProcessToNetwork()