首页 > 代码库 > Android 7.0行为变化—开发者应该关注的(官网同步翻译)
Android 7.0行为变化—开发者应该关注的(官网同步翻译)
Android 7.0行为变化—开发者应该关注的(官网同步翻译)
版权声明:转载必须注明本文转自严振杰的博客: http://blog.yanzhenjie.com
如果想了解更多Android7.0的内容,可以顺便再看看Android7.0写给开发者的一封信(官网同步翻译)。
如果你的引文够好,推荐你阅读官网文章:
Android 7.0 Behavior Changes
Android N 除了提供诸多新特性和功能外,还对系统和 API 行为做出了各种变更。本文重点介绍你应该了解并在开发应用时加以考虑的一些重要变更。
如果您之前发布过Android App,请注意你的App可能受到这些平台变更的影响。
电池和内存
Android N包括旨在延长设备电池寿命和减少RAM使用的系统行为变更。这些变更可能会影响您的应用访问系统资源,以及您的系统通过特定隐式Intent与其他应用互动的方式。
低电耗模式
Android 6.0(API leve 23)引入了低电耗模式,当用户设备未插接电源、处于静止状态且屏幕关闭时,该模式会推迟CPU和网络访问,从而延长电池寿命。而Android 7.0则通过在设备未插接电源且屏幕关闭状态下、但不一定要处于静止状态(例如用户外出时把手持设备装在兜兜里)时应用部分CPU和网络限制,进一步增强了低电耗模式。
低电耗模式如何应用第一级系统活动限制以延长电池寿命的图示:
当设备处于充电状态且屏幕已关闭一定时间后,设备会进入低电耗模式并应用第一部分限制:关闭应用网络访问、推迟Work和Sync。如果进入低电耗模式后设备处于静止状态达到一定时间,系统则会对PowerManager.WakeLock
、AlarmManager
、闹铃
、GPS
和Wi-Fi扫描
应用低电耗模式限制。无论是应用部分限制还是全部低电耗模式限制,系统都会唤醒设备提供一个短时间的维护窗口,在此窗口展示期间,应用程序可以访问网络并执行所有被推迟的Work/Sync。
低电耗模式如何在设备处于静止状态达到一定时间后应用第二级系统活动限制的图示:
请注意,激活屏幕或插接设备电源时,系统将退出低电耗模式并取消之前的限制。此项新增的行为不会影响有关使你的App适应Android 6.0(API Leve23)中所发布旧版本低电耗模式的建议和最佳实践,如低电耗模式和应用待机模式优化中提到的内容。你还是应该遵循这些建议(例如使用 Google Cloud Messaging (GCM) 发送和接收消息),并且兼容新的低电耗模式。
Project Svelte:后台优化
Android 7.0删除了三个隐式广播,优化内存使用和优化电量消耗。这个变化是非常必要的,因为隐式广播会在后台频繁启动已注册侦听这些广播的应用。删除这些广播可以显著提升设备性能和用户体验。
移动设备会经历频繁的连接变更,例如在Wi-Fi和移动数据之间切换时。目前,可以通过在Manifest.xml
中注册一个BroadcastRecevier
来监听隐式CONNECTIVITY_ACTION广播,让应用能够监控这些变更。由于很多App会注册接收这个广播,因此单次网络切换即会导致所有应用被唤醒并同时处理此广播。
同样的道理,应用可以注册接收来自其他应用(例如相机)的隐式ACTION_NEW_PICTURE和ACTION_NEW_VIDEO广播。当用户使用相机应用拍摄照片时,这些应用即会被唤醒以处理广播。
为缓解缓解上面的问题,Android 7.0采用了下面优化措施:
- 针对Android 7.0开发的应用不会收CONNECTIVITY_ACTION广播,即使它们已经在
Manifest.xml
中注册了接受这个广播的BroadcastRecevier
因为不会收到。在前台运行的应用如果使用BroadcastReceiver
接收通知,则仍可以在主线程中侦听CONNECTIVITY_CHANGE
。 - 应用无法发送或接收
ACTION_NEW_PICTURE
或ACTION_NEW_VIDEO
广播。这个改变会影响到所有的App,不仅仅是针对Android 7.0开发的App。
如果你的App使用了任何隐式Intent,您仍需要尽快移除它们的依赖关系,以正确适配Android 7.0的设备。 Android framework提供多个解决方案来缓解对这些隐式广播的需求。例如JobScheduler API提供了一个稳健可靠的机制来安排满足指定条件(例如连入无限流量网络)时所执行的网络操作。您甚至可以使用JobScheduler来适应 Content providers
变化。
如需了解有关 Android 7.0中后台优化以及如何改写应用的详细信息,请参阅后台优化。
权限更改
Android 7.0 做了一些权限更改,这些更改可能会影响到你的App。
系统权限更改
为了提高私有文件的安全性,面向 Android 7.0或更高版本的App私有目录被限制访问(0700)。此设置可防止私有文件的元数据泄漏,如它们的大小或是否存在(状态)。此权限策略的更改有多重副作用:
私有文件的文件权限不应再由所有者放宽,为使用MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE而进行的此类尝试将触发SecurityException,会导致App崩溃的。
注:迄今为止,这种限制还不能完全执行。App仍可能使用原生API或File API来修改它们的私有目录权限。但是Google强烈反对放宽私有目录的权限。
传递软件包网域外的 file://URI可能给接收器留下无法访问的路径。因此传递file://URI会触发
FileUriExposedException
。分享私有文件内容的推荐方法是使用FileProvider。- DownloadManager不再按文件名分享私人存储的文件。老的App在访问COLUMN_LOCAL_FILENAME时可能出现无法访问的路径。针对Android 7.0或更高版本开发的应用在尝试访问COLUMN_LOCAL_FILENAME时会触发 SecurityException。通过使用DownloadManager.Request.setDestinationInExternalFilesDir()或DownloadManager.Request.setDestinationInExternalPublicDir()将下载位置设置为公共位置的老App仍可以访问COLUMN_LOCAL_FILENAME中的路径,但是Google还是强烈反对使用这种方法。访问由DownloadManager公开的文件的首选方式是使用ContentResolver.openFileDescriptor()。
应用间共享文件
对于针对Android 7.0的应用,Android framework执行的StrictMode API禁止向你的App外公开file://URI
。如果一个包含文件URI的Intent发送到你的应用之外,App会发生FileUriExposedException
异常。
若要在应用间共享文件,您应发送一项content://URI,并授予URI临时访问权限。进行此授权的最简单方式是使用FileProvider类。如需有关权限和共享文件的更多信息,请参阅共享文件。
无障碍改进
为提高平台对于视力不佳或视力受损用户的可用性,Android 7.0做出了一些更改。这些更改正常情况下不需要改你的代码,不过你要仔细检查并用你的App测试这些功能,以评估它们对用户体验的潜在影响。
屏幕缩放
Android 7.0支持用户设置显示尺寸,以放大或缩小屏幕上的所有元素,从而提升设备对视力不佳用户的可访问性。用户无法将屏幕缩放至低于最小屏幕宽度sw320dp
,该宽度是Nexus 4
的宽度,也是常规中等大小手机的宽度。
Android 7.0 系统映像正常大小运行效果:
Android 7.0 系统映像增大显示尺寸后的效果:
当设备密度发生更改时,系统会以如下方式通知正在运行的应用:
- 如果是面向API leve 23或更低版本系统的应用,系统会自动终止其所有后台进程。也就是说如果用户切换后离开你的App,打开“Settings”更改
Display size
设置,则系统会像处理内存不足的情况一样终止该应用。如果应用具有任何前台进程,则系统会如处理运行时变更中所述将配置变更通知给这些进程,就像对待设备屏幕方向变更一样,具体大家可以再看看这个超链接。 - 如果是针对Android 7.0的App,则其所有进程(前台和后台)都会收到有关配置变更的通知,如处理运行时变更中所讲的那样。
大多数App并不需要进行任何更改即可支持此功能,不过前提是这些应用遵循Android最佳实践。具体要检查的事项:
- 在屏幕宽度为 sw320dp 的设备上测试你的App,并确保其正常运行。
- 当设备Config发生变更时,更新任何与密度相关的缓存信息,例如缓存位图或从网络加载的资源。当应用从暂停状态恢复运行时,检查Config的变化。
注:如果你要缓存与配置相关的数据,则最好也包括相关元数据,例如该数据对应的屏幕尺寸或像素密度。保存这些元数据便于你在Config变更后决定是否需要刷新缓存数据。
- 避免用像素单位指定尺寸,因为像素不会随屏幕密度缩放。应改为使用dp等单位。
设置向导中的视觉设置
Android 7.0 在“Welcome”页面中加入了“Vision Settings”,用户可以在新设备上操作`无障碍功能设置`: `Magnification gesture`、`Font size`、`Display size`和`TalkBack`。这个变化增加了与不同屏幕设置相关的错误的可见性。要测试此功能的影响,你应该在启用这些设置的状态下测试应用,可以在`Settings > Accessibility`中找到这些设置。NDK 应用链接至平台库
Android 7.0做了一些命名空间更改,以阻止加载非公开API。如果你使用NDK,则只能使用Android平台提供的公开 API。在下一个官方发布的Android 版本上使用非公开API会导致应用崩溃。 为提醒你使用了非公开API,在Android 7.0的设备上运行的App会在有App调用非公开API时在日志消息输出中生成一个错误。此错误还会作为消息显示在设备屏幕上,以帮助增强你对此情况的认识。你应该检查应用代码以删除使用非公开API,并使用预览版设备或模拟器全面测试App。 如果您的App依赖平台库,则请参见NDK文档,了解使用公开API等效替换普通私有API的修复方案。你还可以链接至平台库,而无需实现此应用,如果App使用的库是平台的一部分(例如libpng),但不属于NDK,则更可如此。这种情况下,请确保您的APK包含您打算链接到的所有.so 文件。App不应该依赖或使用不属于NDK的原生库,因为这些库可能会发生更改,或者从一个Android版本迁移至另一版本的时候发生更改。例如,从OpenSSL切换至BoringSSL即属于此类更改。此外,不同的设备可能提供不同级别的兼容性,因为不属于NDK中的平台库没有兼容性要求。如果你必须在较旧设备上访问非NDK库,则请依据 Android API 级别进行加载。 为帮助您诊断此类问题,下面列举了一些在您试图使用 Android N 开发应用时可能遇到的 Java 和 NDK 错误: Java 错误示例:注意:有些第三方库可能会链接至非公开API。如果您的应用使用这些库,那么当您的应用在下一个官方发布的 Android 版本上运行时可能会出现崩溃现象,so,你也要认真检查使用的第三方库是否使用了非公开api,例如百度地图。
java.lang.UnsatisfiedLinkError: dlopen failed: library "/system/lib/libcutils.so"
is not accessible for the namespace "classloader-namespace"
NDK 错误示例:
dlopen failed: cannot locate symbol "__system_property_get" referenced by ...
以下是遇到这类错误的应用的一些典型修复:
* 可以使用标准JNI函数来替代使用`libandroid_runtime.so`中的`getJavaVM`和`getJNIEnv`:
AndroidRuntime::getJavaVM -> GetJavaVM from <jni.h>
AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or
JavaVM::AttachCurrentThread from <jni.h>.
- 可以使用公开
alternative __system_property_get
来替代使用libcutils.so
中的property_get
符号。如需这样做,请使用__system_property_get
及以下include
函数:
#include <sys/system_properties.h>
- 应使用应用本地版本来替代使用
libcrypto.so
中的SSL_ctrl
符号。例如,你应在.so
文件中静态链接libcyrpto.a
,或者在应用中包含你自己的来自BoringSSL
或OpenSSL
的动态libcrypto.so
。
Android for Work
Android 7.0包含一些针对面向Android for Work
的应用的变更,包括对证书安装、密码重置、二级用户管理、设备标识符访问权限的变更。如果你是要针对Android for Work
环境开发应用,则应仔细检查这些变更并相应地修改你的App代码。
你必须先安装授权证书安装程序,然后DPC才能对其进行设置。对于面向
7.0 SDK
的个人资料和设备所有者应用,您应在设备策略控制器(DPC)调用DevicePolicyManager.setCertInstallerPackage()
之前安装授权证书安装程序。如果尚未安装此安装程序,则系统会引发IllegalArgumentException
。针对设备管理员的重置密码限制现在也适用于个人资料所有者。设备管理员无法再使用
DevicePolicyManager.resetPassword()
来清除或更改已经设置的密码。设备管理员仍可以设置密码,但只能在设备没有密码、PIN或图案时这样做。即使设置了限制,设备所有者和个人资料所有者仍可以管理帐户。而且,即使具有
DISALLOW_MODIFY_ACCOUNTS
用户限制,设备所有者和个人资料所有者仍可调用Account Management API
。设备所有者可以更轻松地管理二级用户。当设备在设备所有者模式下运行时,系统将自动设置
DISALLOW_ADD_USER
限制。这样可以防止用户创建非托管二级用户。此外,CreateUser()
和createAndInitializeUser()
方法已弃用,取而代之的DevicePolicyManager.createAndManageUser()
方法。设备所有者可以访问设备标识符。设备所有者可以使用
DevicePolicyManagewr.getWifiMacAddress()
访问设备的Wi-Fi MAC
地址。如果设备上从未启用Wi-Fi,则此方法将返回一个null
值。工作模式设置控制工作应用访问。当工作模式关闭时,系统启动器通过使工作应用显示为灰色来指示它们不可用。启用工作模式会再次恢复正常行为。
如需了解有关Android 7.0中针对Android for Work
所做变更的详细信息,请参阅Android for Work 更新。
注解保留
Android 7.0在注解可见性被忽略时修复错误。这种问题将启用本不应被允许的运行时访问注解。 这些注解包括:
* VISIBILITY_BUILD
:仅应编译时可见。
* VISIBILITY_SYSTEM
:运行时应可见,但仅限基本系统。
如果你的App依赖这种行为,请在注解中添加一项运行时必须可用的保留政策。你可通过使用@Retention(RetentionPolicy.RUNTIME) 这样做。
其他重要说明
如果一个针对较低API级别开发的App在Android 7.0上运行,那么在用户更改显示尺寸时,系统将终止此App进程。App必须能够正常处理此情景。否则,当用户从最近使用记录中恢复运行App时,App将会出现崩溃现象。您应测试应用以确保不会发生此行为。要进行此测试,您可以通过DDMS手动终止应用,可以造成相同的崩溃现象。在屏幕密度发生更改时,系统不会自动终止针对Android 7.0及更高版本开发的App;不过这些App仍可能对配置变更做出不良响应。
Android 7.0上的应用应能够正常处理配置变更,并且在后续启动时不会出现崩溃现象。你可以通过更改字体大小 (Setting > Display > Font size) 并随后从最近使用记录中恢复运行应用,来验证App行为。
由于之前的Android版本中的一项错误,系统没有对主线程上的一个TCP Socket的写入操作严格检查。Android 7.0修复了这个系统错误。之前有这种行为的App将会引发
android.os.NetworkOnMainThreadException
。一般情况下,不建议在主线程上执行网络操作,因为这些操作通常都有可能导致ANR和卡顿,这个应该是中所周知的,大家一般不会犯。Debug.startMethodTracing()
方法族现在默认在你的共享的存储空间上的软件包特定目录中存储输出,而非 SD卡顶级。这意味着应用不再需要请求WRITE_EXTERNAL_STORAGE
权限就可以使用这些API。许多平台API现在开始检查在Binder事务间发送的大负载,系统现在会将
TransactionTooLargeExceptions
再次作为RuntimeExceptions
引发,而不再只是默默记录或不抛出这个错误。一个常见例子是在Activity.onSaveInstanceState()上存储过多数据,导致ActivityThread.StopInfo
在你的App面向 Android 7.0时引发RuntimeException
。如果应用向View post Runnable任务,并且View未附加到窗口,系统会用View为Runnable任务排队;在 View附加到窗口之前,Runnable任务不会执行。 此行为会修复以下错误:
- 如果一个App是从并非预期Window UI线程的其他线程发布到View,则
Runnable
可能会因此运行错误。 - 如果
Runnable
任务是从并非looper thread的其他线程发布,则应用可能会曝光Runnable任务。
- 如果一个App是从并非预期Window UI线程的其他线程发布到View,则
如果Android 7.0上有DELETE_PACKAGES权限的应用尝试删除一个软件包,但另一项应用已经安装了这个软件包,则系统可能要求用户确认。在这种情况下,应用在调用PackageInstaller.uninstall() 时的返回状态应为STATUS_PENDING_USER_ACTION。
如果想了解更多Android7.0的内容,可以顺便再看看Android7.0写给开发者的一封信(官网同步翻译)。
版权声明:转载必须注明本文转自严振杰的博客: http://blog.yanzhenjie.com
Android 7.0行为变化—开发者应该关注的(官网同步翻译)