赞
踩
为了帮助确保应用稳定性和兼容性,Android 平台开始限制您的应用可在 Android 9(API 级别 28)中使用哪些非 SDK 接口。Android Q 包含更新后的受限非 SDK 接口列表(基于与 Android 开发者之间的协作以及最新的内部测试)。我们的目标是在限制使用非 SDK 接口之前确保有可用的公开替代方案。
如果您不打算以 Android Q 为目标平台,那么其中一些变更可能不会立即对您产生影响。虽然您目前可以使用灰名单中的一些非 SDK 接口(取决于您应用的目标 API 级别),但如果您使用任何非 SDK 方法或字段,则应用无法运行的风险终归较高。
如果您不确定自己的应用是否使用了非 SDK 接口,则可以测试该应用进行确认。如果您的应用依赖于非 SDK 接口,则应该开始计划迁移到 SDK 替代方案。不过,我们知道某些应用具有使用非 SDK 接口的有效用例。如果您无法为应用中的某项功能找到使用非 SDK 接口的替代方案,则应该请求新的公共 API。
要了解详情,请参阅非 SDK 接口在 Android Q 中的受限情况出现变化以及对非 SDK 接口的限制。
Android Q 包含以下 NDK 方面的变更。
Android 6.0(API 级别 23)已禁止在共享对象中使用文本重定位。代码必须按原样加载,且不得修改。此变更可以减少应用的加载时间并提高安全性。
在 Android Q 测试版 1 和 2 中,SELinux 对以 Android 8.0(API 级别 26)及更高版本作为目标版本的应用强制执行此限制。如果此类应用继续使用包含文本重定位的共享对象,则出现故障的风险较高。
从 Android Q 开始,系统二进制文件和库会映射到只执行(不可读取)内存,作为应对代码重用攻击的安全强化技术。有意或意外读入已标记为只执行的内存段会抛出 SIGSEGV,无论此读入行为是来自错误、漏洞还是有意的内存自省都不例外。
您可以通过检查 /data/tombstones/ 中的相关 tombstone 文件来确定崩溃是否由变更改所导致。与只执行相关的崩溃包含以下中止消息:
Cause: execute-only (no-read) memory access error; likely due to data in .text.
要解决此问题,开发者可以通过调用 mprotect() 将只执行内存段标记为“读取+执行”,例如用于执行内存检查。不过,我们强烈建议您事后将其重新设为只执行,因为这样可以更好地保护您的应用和用户。
对 ptrace 的调用不会受到影响,因此 ptrace 调试也不会受到影响。
Android Q 包含以下安全性方面的变更。
以 Android Q 为目标平台的不受信任的应用无法再针对应用主目录中的文件调用 exec()。这种从可写应用的主目录执行文件的行为违反了 W^X。应用应该仅加载嵌入到应用的 APK 文件中的二进制代码。
此外,以 Android Q 为目标平台的应用无法针对已执行 dlopen() 的文件中的可执行代码进行内存中修改。这包括含有文本重定位的所有共享对象 (.so) 文件。
在 Android Q 中,以下与 WLAN 直连相关的广播不再具有粘性。
如果您的应用依赖于在注册时接收这些广播(因为其之前一直具有粘性),请在初始化时使用适当的 get() 方法获取信息。
Android Q 扩大了支持范围,现在可以使用 WLAN 感知数据路径轻松创建 TCP/UDP 套接字。要创建连接到 ServerSocket 的 TCP/UDP 套接字,客户端设备需要知道服务器的 IPv6 地址和端口。这在之前需要通过频外方式进行通信(例如使用 BT 或 WLAN 感知第 2 层消息传递),或者使用其他协议(例如 mDNS)通过频内方式发现。而借助 Android Q,可以将此类消息作为网络设置的一部分进行传递。
服务器可以执行以下任一操作:
以下代码示例显示了如何将端口信息指定为网络请求的一部分:
ServerSocket ss = new ServerSocket();
WifiAwareNetworkSpecifier ns = new WifiAwareNetworkSpecifier
.Builder(discoverySession, peerHandle)
.setPskPassphrase(“some-password”)
.setPort(ss.getLocalPort())
.build();
NetworkRequest myNetworkRequest = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE)
.setNetworkSpecifier(ns)
.build();
然后,客户端会执行 WLAN 感知网络请求来获取服务器提供的 IPv6 和端口:
callback = new ConnectivityManager.NetworkCallback() { @Override public void onAvailable(Network network) { ... } @Override public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) { ... } @Override Public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) { ... TransportInfo ti = networkCapabilities.getTransportInfo(); if (ti instanceof WifiAwareNetworkInfo) { WifiAwareNetworkInfo info = (WifiAwareNetworkInfo) ti; Inet6Address peerAddress = info.getPeerIpv6Addr(); int peerPort = info.getPort(); } } @Override public void onLost(Network network) { ... } }; connMgr.requestNetwork(networkRequest, callback);
在 Android Q(Go 版本)设备上运行的应用无法获得 SYSTEM_ALERT_WINDOW 权限。这是因为绘制叠加层窗口会使用过多的内存,这对低内存 Android 设备的性能十分有害。
如果在搭载 Android 9 或更低版本的 Go 版本设备上运行的应用收到了 SYSTEM_ALERT_WINDOW 权限,则会保留此权限,即使设备升级到 Android Q 也不例外。不过,尚不具有此权限的应用在设备升级后便无法获得此权限了。
如果 Go 设备上的应用发送具有 ACTION_MANAGE_OVERLAY_PERMISSION 操作的 intent,则系统会自动拒绝此请求,并将用户转到设置屏幕,上面会显示不允许授予此权限,原因是它会降低设备的速度。如果 Go 设备上的应用调用 Settings.canDrawOverlays(),则此方法始终返回 false。同样,这些限制不适用于在设备升级到 Android Q 之前便已收到 SYSTEM_ALERT_WINDOW 权限的应用。
在 Android Q 中,当用户首次运行以 Android 6.0(API 级别 23)以下的版本为目标平台的任何应用时,Android 平台会向用户发出警告。如果此应用要求用户授予权限,则系统会先向用户提供调整应用权限的机会,然后才会允许此应用首次运行。
由于 Google Play 的目标 API 方面的要求,用户只有在运行最近未更新的应用时才会看到这些警告。对于通过其他商店分发的应用,我们也将于 2019 年引入类似的目标 API 方面的要求。要详细了解这些要求,请参阅在 2019 年扩展目标 API 级别方面的要求。
以下 SHA-2 CBC 加密套件已从平台中移除:
这些加密套件不如使用 GCM 的类似加密套件安全,并且大多数服务器要么同时支持这些加密套件的 GCM 变体和 CBC 变体,要么二者均不支持。
Android Q 引入了与应用使用情况相关的以下行为变更:
android.preference 库现已弃用。开发者应该改为使用 AndroidX preference 库,这是Android Jetpack 的一部分。如需获取其他资源以帮助进行迁移和开发,请查看经过更新的设置指南以及我们的公开示例应用和参考文档。
很多使用摄像头的应用都会假定如果设备采用纵向配置,则物理设备也会处于纵向,正如摄像头方向中所述。在过去可以做出这样的假定,但在推出新型设备(例如可折叠设备)后,这发生了变化。针对这些设备做出这样的假定可能导致相机取景器的显示产生错误的旋转和/或缩放。
以 API 级别 24 或更高级别为目标平台的应用应该明确设置 android:resizeableActivity,并提供必要的功能来处理多窗口操作。
从 Android Q 开始,只要在发生重大充电事件之后拔下设备电源插头,SystemHealthManager 就会重置其电池用量统计信息。一般来说,重大充电事件指的是设备电池已充满,或者设备电量经历从几乎耗尽到即将充满。
在 Android Q 之前,无论何时拔下设备电源插头,无论电池电量有多微小的变化,电池用量统计信息都会重置。
Android 9 引入了新功能以改善设备电源管理。 这些变更连同 Android 9 之前已存在的功能可帮助确保系统资源被提供给最需要它们的应用。
详情请参阅电源管理。
为了增强用户隐私,Android 9 引入了若干行为变更,如限制后台应用访问设备传感器、限制通过 Wi-Fi 扫描检索到的信息,以及与通话、手机状态和 Wi-Fi 扫描相关的新权限规则和权限组。
无论采用哪一种目标 SDK 版本,这些变更都会影响运行于 Android 9 上的所有应用。
后台对传感器的访问受限
Android 9 限制后台应用访问用户输入和传感器数据的能力。 如果您的应用在运行 Android 9 设备的后台运行,系统将对您的应用采取以下限制:
如果您的应用需要在运行 Android 9 的设备上检测传感器事件,请使用前台服务。
限制访问通话记录
Android 9 引入 CALL_LOG 权限组并将 READ_CALL_LOG、WRITE_CALL_LOG 和 PROCESS_OUTGOING_CALLS 权限移入该组。 在之前的 Android 版本中,这些权限位于 PHONE 权限组。
对于需要访问通话敏感信息(如读取通话记录和识别电话号码)的应用,该 CALL_LOG 权限组为用户提供了更好的控制和可见性。
如果您的应用需要访问通话记录或者需要处理去电,则您必须向 CALL_LOG 权限组明确请求这些权限。 否则会发生 SecurityException。
如果您的应用已经遵循运行时权限最佳做法,则可以处理权限组的变更。
限制访问电话号码
在未首先获得 READ_CALL_LOG 权限的情况下,除了应用的用例需要的其他权限之外,运行于 Android 9 上的应用无法读取电话号码或手机状态。
与来电和去电关联的电话号码可在手机状态广播(比如来电和去电的手机状态广播)中看到,并可通过 PhoneStateListener 类访问。 但是,如果没有 READ_CALL_LOG 权限,则 PHONE_STATE_CHANGED 广播和 PhoneStateListener 提供的电话号码字段为空。
要从手机状态中读取电话号码,请根据您的用例更新应用以请求必要的权限:
限制访问 Wi-Fi 位置和连接信息
在 Android 9 中,应用进行 Wi-Fi 扫描的权限要求比之前的版本更严格。 详情请参阅 Wi-Fi 扫描限制。
类似的限制也适用于 getConnectionInfo() 函数,该函数返回描述当前 Wi-Fi 连接的 WifiInfo 对象。 如果调用应用具有以下权限,则只能使用该对象的函数来检索 SSID 和 BSSID 值:
检索 SSID 或 BSSID 还需要在设备上启用位置服务(在 Settings > Location 下)。
从 Wi-Fi 服务函数中移除的信息
在 Android 9 中,下列事件和广播不接收用户位置或个人可识别数据方面的信息:
Wi-Fi 的 NETWORK_STATE_CHANGED_ACTION系统广播不再包含 SSID(之前为 EXTRA_SSID)、BSSID(之前为 EXTRA_BSSID)或连接信息(之前为 EXTRA_NETWORK_INFO)。 如果应用需要此信息,请改为调用 getConnectionInfo()。
电话信息现在依赖设备位置设置
如果用户在运行 Android 9 的设备上停用设备定位,则以下函数不提供结果:
为帮助确保应用稳定性和兼容性,此平台对某些非 SDK 函数和字段的使用进行了限制;无论您是直接访问这些函数和字段,还是通过反射或 JNI 访问,这些限制均适用。 在 Android 9 中,您的应用可以继续访问这些受限的接口;该平台通过 toast 和日志条目提醒您注意这些接口。 如果您的应用显示这样的 toast,则必须寻求受限接口之外的其他实现策略。 如果您认为没有可行的替代策略,您可以提交错误以请求重新考虑此限制。
对非 SDK 接口的限制包含了更多重要信息。 您应查阅该信息以确保您的应用继续正常工作。
无论应用的目标平台版本如何,Android 9 添加的若干功能均可令应用的安全性得到改善。
传输层安全协议 (TLS) 实现变更
系统的传输层安全协议 (TLS) 实现在 Android 9 中经历了若干次变更:
如果 SSLSocket 的实例在创建时连接失败,系统会引发 IOException 而非 NullPointerException。
SSLEngine 类可正常处理出现的任何 close_notify 提醒。
如需了解有关在 Android 应用中进行安全网络请求的更多信息,请参阅一个 HTTPS 示例。
更严格的 SECCOMP 过滤器
Android 9 对可供应用使用的系统调用做了进一步限制。 此行为是 Android 8.0(API 级别 26)包含的 SECCOMP 过滤器的扩展。
注:此更改仅影响使用授权的系统调用的应用。
Android 9 针对加密算法的实现和处理引入了几项变更。
参数和算法的 Conscrypt 实现
Android 9 在 Conscrypt 中实现了更多的算法参数。 这些参数包括: AES、DESEDE、OAEP 和 EC。 这些参数和许多算法的 Bouncy Castle 版本自 Android 9 起已被弃用。
注:EC 参数的 Conscrypt 实现仅支持已命名的曲线。
如果您的应用以 Android 8.1(API 级别 27)或更低版本为目标,则在请求这些已弃用算法之一的 Bouncy Castle 实现时,您将收到一条警告消息。 然而,如果您以 Android 9 为目标平台,则这些请求会各自引发 NoSuchAlgorithmException。
Android 9 引入了多项与加密有关的其他变更:
如需了解有关使用 Android 的加密功能的更多信息,请参阅加密。
Android 9 完全取消了对 Android 安全加密文件 (ASEC) 的支持。
在 Android 2.2(API 级别 8)中,Android 引入了 ASEC 以支持 SD 卡加载应用功能。 在 Android 6.0(API 级别 23)上,平台引入了一个可采用的存储设备 技术,开发者可用它来代替 ASEC。
Android 9 使用 ICU 库版本 60。 Android 8.0(API 级别 26)和 Android 8.1(API 级别 27)使用 ICU 58。
ICU 用于提供 android.icu package 下的公开 API, 供 Android 平台内部用来提供国际化支持。 例如,它用于实现 java.util、java.text 和 android.text.format 格式的 Android 类。
对 ICU 60 进行的更新包含许多细微但很有用的变更,这包括 Emoji 5.0 数据支持,改进了日期/时间格式,详见 ICU 59 和 ICU 60 版本说明中的介绍。
本次更新中的显著变更:
Android 9 引入了多项针对 Android Test 框架库和类结构的更改。 这些变更可帮助开发者使用支持框架的公共 API,此外,在使用第三方库或自定义逻辑构建和运行测试时,这些变更还可提供更大的灵活性。
从框架移除的内容库
Android 9 将基于 JUnit 的类重新整理成三个内容库: android.test.base、android.test.runner 和 android.test.mock。 此变更允许您针对与您的项目依赖项搭配效果最好的 JUnit 版本运行测试。 此版本的 JUnit 可能不同于 android.jar 提供的版本。
如需了解有关如何将基于 JUnit 的类组织到这些内容库中,以及如何准备您的应用项目以编写和运行测试,请参阅针对 Android 测试设置项目。
测试套件版本号变更
移除了 TestSuiteBuilder 类中的 addRequirements() 函数,TestSuiteBuilder 类本身也已弃用。 addRequirements() 函数要求开发者提供类型为隐藏 API 的参数,结果令 API 失效。
UTF-8 是 Android 中的默认字符集。 UTF-8 字节序列可由 String(byte[] bytes) 之类的 String 构造函数解码。
Android 9 中的 UTF-8 解码器遵循比以前版本中更严格的 Unicode 标准: 这些变更包括:
RFC 2818中介绍了两种对照证书匹配域名的方法—使用 subjectAltName (SAN) 扩展程序中的可用名称,或者在没有 SAN 扩展程序的情况下,回退到 commonName (CN)。
然而,在 RFC 2818 中,回退到 CN 已被弃用。因此,Android 不再回退到使用 CN。 要验证主机名,服务器必须出示具有匹配 SAN 的证书。 不包含与主机名匹配的 SAN 的证书不再被信任。
要求名称解析的网络地址查询可能会涉及网络 I/O,因此会被视为阻塞性操作。 对于主线程的阻塞性操作可能会导致停顿或卡顿。
StrictMode 类是一个有助于开发者检测代码问题的开发工具。
在 Android 9 及更高版本中,StrictMode 可以检测需要名称解析的网络地址查询所导致的网络违规。
您在交付应用时不应启用 StrictMode。 否则,您的应用可能会遭遇异常,例如,在使用 detectNetwork() 或 detectAll() 函数获取用于检测网络违规的政策时,会出现NetworkOnMainThreadException。
解析数字 IP 地址不被视为阻塞性操作。 数字 IP 地址解析的工作方式与 Android 9 以前的版本中所采用的方式相同。
在低于 Android 9 的平台版本上,如果使用 setThreadStatsTag() 函数标记某个套接字,则当使用带 ParcelFileDescriptor 容器的 binder 进程间通信将其发送给其他进程时,套接字会被取消标记。
在 Android 9 及更高版本中,利用 binder 进程间通信将套接字发送至其他进程时,其标记将得到保留。 此变更可能影响网络流量统计,例如,使用 queryDetailsForUidTag() 函数时。
如果您要保留以前版本的行为,即取消已发送至其他进程的套接字的标记,您可以在发送此套接字之前调用 untagSocket()。
在调用 shutdownInput() 函数后,available() 函数会在调用时返回 0。
更详尽的 VPN 网络功能报告
在 Android 8.1(API 级别 28)及更低版本中,NetworkCapabilities 类仅报告 VPN 的有限信息,例如 TRANSPORT_VPN,但会省略 NET_CAPABILITY_NOT_VPN。 信息有限导致难以确定使用 VPN 是否会导致对应用的用户收费。 例如,检查 NET_CAPABILITY_NOT_METERED 并不能确定底层网络是否按流量计费。
从 Android 9 及更高版本开始,当 VPN 调用 setUnderlyingNetworks() 函数时,Android 系统将会合并任何底层网络的传输和能力并返回 VPN 网络的有效网络能力作为结果。
在 Android 9 及更高版本中,已经检查NET_CAPABILITY_NOT_METERED 的应用将收到关于 VPN 网络能力和底层网络的信息。
从 Android 9 开始,不再允许应用直接读取 /proc/net/xt_qtaguid 文件夹中的文件。 这样做是为了确保与某些根本不提供这些文件的设备保持一致。
依赖这些文件的公开 API TrafficStats 和 NetworkStatsManager 继续按照预期方式运行。 然而,不受支持的 cutils 函数(例如 qtaguid_tagSocket())在不同设备上可能不会按照预期方式运行 — 甚至根本不运行。
在 Android 9 中,您不能从非 Activity 环境中启动 Activity,除非您传递 Intent 标志 FLAG_ACTIVITY_NEW_TASK。 如果您尝试在不传递此标志的情况下启动 Activity,则该 Activity 不会启动,系统会在日志中输出一则消息。
注:在 Android 7.0(API 级别 24)之前,标志要求一直是期望的行为并被强制执行。 Android 7.0 中的一个错误会临时阻止实施标志要求。
从 Android 9 开始,对纵向旋转模式做出了重大变更。 在 Android 8.0(API 级别 26)中,用户可以使用 Quicksettings 图块或 Display 设置在自动屏幕旋转和纵向旋转模式之间切换。 纵向模式已重命名为旋转锁定,它会在自动屏幕旋转关闭时启用。 自动屏幕旋转模式没有任何变更。
当设备处于旋转锁定模式时,用户可将其屏幕锁定到顶层可见 Activity 所支持的任何旋转。 Activity 不应假定它将始终以纵向呈现。 如果顶层 Activity 可在自动屏幕旋转模式下以多种旋转呈现,则应在旋转锁定模式下提供相同的选项,根据 Activity 的 screenOrientation 设置,允许存在一些例外情况(见下表)。
请求特定屏幕方向(例如,screenOrientation=landscape)的 Activity 会忽略用户锁定首选项,并且行为与 Android 8.0 中的行为相同。
可在 Android Manifest 中,或以编程方式通过 setRequestedOrientation() 在 Activity 级别设置屏幕方向首选项。
旋转锁定模式通过设置 WindowManager 在处理 Activity 旋转时使用的用户旋转首选项来发挥作用。 用户旋转首选项可能在下列情况下发生变更。 请注意,恢复设备的自然旋转存在偏差,对于外形与手机类似的设备通常设置为纵向:
下表总结了常见屏幕方向的旋转行为:
屏幕方向 | 行为 |
---|---|
未指定、user | 在自动屏幕旋转和旋转锁定下,Activity 可以纵向或横向(以及颠倒纵向或横向)呈现。 预期同时支持纵向和横向布局。 |
userLandscape | 在自动屏幕旋转和旋转锁定下,Activity 可以横向或颠倒横向呈现。 预期只支持横向布局。 |
userPortrait | 在自动屏幕旋转和旋转锁定下,Activity 可以纵向或颠倒纵向呈现。 预期只支持纵向布局。 |
fullUser | 在自动屏幕旋转和旋转锁定下,Activity 可以纵向或横向(以及颠倒纵向或横向)呈现。 预期同时支持纵向和横向布局。旋转锁定用户将可选择锁定到颠倒纵向,通常为 180º。 |
sensor、fullSensor、sensorPortrait、sensorLandscape | 在自动屏幕旋转和旋转锁定下,Activity 可以纵向或横向(以及颠倒纵向或横向)呈现。 预期同时支持纵向和横向布局。 |
未指定、user 在自动屏幕旋转和旋转锁定下,Activity 可以纵向或横向(以及颠倒纵向或横向)呈现。 预期同时支持纵向和横向布局。
userLandscape 在自动屏幕旋转和旋转锁定下,Activity 可以横向或颠倒横向呈现。 预期只支持横向布局。
userPortrait 在自动屏幕旋转和旋转锁定下,Activity 可以纵向或颠倒纵向呈现。 预期只支持纵向布局。
fullUser 在自动屏幕旋转和旋转锁定下,Activity 可以纵向或横向(以及颠倒纵向或横向)呈现。 预期同时支持纵向和横向布局。
在 Android 6.0 中,我们取消了对 Apache HTTP 客户端的支持。
此变更对大多数不以 Android 9 或更高版本为目标的应用没有任何影响。 不过,此变更会影响使用非标准 ClassLoader 结构的某些应用,即使这些应用不以 Android 9 或更高版本为目标平台。
如果应用使用显式委托到系统 ClassLoader 的非标准 ClassLoader,则应用会受到影响。 在 org.apache.http.* 中查找类时,这些应用需要委托给应用 ClassLoader。 如果它们委托给系统 ClassLoader,则应用在 Android 9 或更高版本上将失败并显示 NoClassDefFoundError,因为系统 ClassLoader 不再识别这些类。 为防止将来出现类似问题,一般情况下,应用应通过应用 ClassLoader 加载类,而不是直接访问系统 ClassLoader。
在 Android 9 设备上运行的应用可以通过调用 getCameraIdList() 发现每个可用的摄像头。 应用不应假定设备只有一个后置摄像头或只有一个前置摄像头。
例如,如果您的应用有一个用来切换前置和后置摄像头的按钮,则设备可能有多个前置或后置摄像头可供选择。 您应浏览一下摄像头列表,检查每个摄像头的特征,然后决定向用户显示哪些摄像头。
Android 8.0 为提高电池续航时间而引入的变更之一是,当您的应用进入已缓存状态时,如果没有活动的组件,系统将解除应用具有的所有唤醒锁。
此外,为提高设备性能,系统会限制未在前台运行的应用的某些行为。具体而言:
默认情况下,这些限制仅适用于针对 O 的应用。不过,用户可以从 Settings 屏幕为任意应用启用这些限制,即使应用并不是以 O 为目标平台。
Android 8.0 还对特定函数做出了以下变更:
为节约电池电量、保持良好的用户体验和确保系统健康运行,在运行 Android 8.0 的设备上使用后台应用时,降低了后台应用接收位置更新的频率。此行为变更会影响包括 Google Play 服务在内的所有接收位置更新的应用。
此类变更会影响以下 API:
为确保您的应用按预期方式运行,请完成以下步骤:
Android 8.0 对应用快捷方式做出了以下变更:
Android 7.0(API 级别 24)引入能指定默认类别语言区域的概念,但是某些 API 在本应使用默认 DISPLAY 类别语言区域时,仍然使用不带参数的通用 Locale.getDefault() 函数。现在,在 Android 8.0 中,以下函数使用 Locale.getDefault(Category.DISPLAY) 来代替 Locale.getDefault():
当为 Locale 参数指定的 displayScript 值不可用时,Locale.getDisplayScript(Locale) 同样回退到 Locale.getDefault()。
与语言区域和国际化有关的其他变更如下:
如果应用使用 SYSTEM_ALERT_WINDOW 权限并且尝试使用以下窗口类型之一来在其他应用和系统窗口上方显示提醒窗口:
…那么,这些窗口将始终显示在使用 TYPE_APPLICATION_OVERLAY 窗口类型的窗口下方。如果应用针对的是 Android 8.0,则应用会使用 TYPE_APPLICATION_OVERLAY 窗口类型来显示提醒窗口。
随着 Android 应用出现在 Chrome 操作系统和平板电脑等其他大尺寸设备上,我们看到,用户在 Android 应用中又重新开始使用键盘导航。在 Android 8.0 中,我们又再次使用键盘作为导航输入设备,从而为基于箭头键和 Tab 键的导航构建了一种更可靠并且可预测的模型。
尤其要指出的是,我们对元素焦点行为做出以下变更:
如果您不希望 View 对象在接收焦点时使用此默认突出显示标志,请在包含 View 的布局 XML 文件中将 android:defaultFocusHighlightEnabled 属性设置为 false,或者将 false 传递至应用界面逻辑中的 setDefaultFocusHighlightEnabled()。
另外,Android 8.0 中的所有工具栏元素自动组成键盘导航键区,用户可以更加轻松地导航进入和离开每个作为一个整体的工具栏。
现在,Android 自动填充框架提供对自动填充功能的内置支持,对于安装到运行 Android 8.0 的设备上的应用,与 WebView 对象相关的下列函数已经发生变化:
WebSettings
WebViewDatabase
现在,无障碍服务可识别应用的 TextView 对象内部的所有 ClickableSpan 实例。
如需了解有关如何让您的应用更便于访问的更多信息,请参阅无障碍功能。
Android 8.0 对网络连接和 HTTP(S) 连接行为做出了以下变更:
无正文的 OPTIONS 请求具有 Content-Length: 0 标头。之前,这些请求没有 Content-Length 标头。
HttpURLConnection 在包含斜线的主机或颁发机构名称后面附加一条斜线,使包含空路径的网址规范化。例如,它将http://example.com 转化为 http://example.com/。
通过 ProxySelector.setDefault()设置的自定义代理选择器仅针对所请求的网址(架构、主机和端口)。因此,仅可根据这些值选择代理。传递至自定义代理选择器的网址不包含所请求的网址的路径、查询参数或片段。
URI 不能包含空白标签。 之前,平台支持一种权宜方法,即允许主机名称中包含空白标签,但这是对 URI的非法使用。此权宜方法只是为了确保与旧版 libcore 兼容。开发者如果对 API 使用不当,将会看到一条 ADB 消息:“URIexample…com 的主机名包含空白标签。此格式不正确,将不被未来的 Android 版本所接受。”Android 8.0废除了此权宜方法;系统对格式错误的 URI 会返回 null。
Android 8.0 在实现 HttpsURLConnection 时不会执行不安全的 TLS/SSL 协议版本回退。
对隧道 HTTP(S) 连接处理进行了如下变更:
系统不再将隧道连接请求中的 user-agent 和 proxy-authorization标头发送至代理服务器。在建立隧道时,系统不再将隧道 Http(s)URLConnection 中的proxy-authorization标头发送至代理。相反,由系统生成 proxy-authorization标头,在代理响应初始请求发送 HTTP 407后将其发送至此代理。
同样地,系统不再将 user-agent 标头由隧道连接请求复制到建立隧道的代理请求。相反,库为此请求生成 user-agent 标头。
如果之前执行的 connect() 函数失败,send(java.net.DatagramPacket) 函数将会引发
SocketException。
在回退到 TCP Echo 协议之前,InetAddress.isReachable() 会尝试执行 ICMP。
Android 8.0 对 ScanRecord.getBytes() 函数检索的数据长度做出以下变更:
Android 8.0 对 WLAN 设置进行了多项改进,这样可以更轻松地选择能够提供最佳用户体验的 WLAN 网络。具体变更包括:
Android 8.0 包含以下与安全性有关的变更:
Android 8.0 对平台做出了以下与隐私性有关的变更。
现在,平台改变了标识符的处理方式。
对于安装在运行 Android 8.0 的设备上的应用,ANDROID_ID的值现在将根据应用签署密钥和用户确定作用域。应用签署密钥、用户和设备的每个组合都具有唯一的 ANDROID_ID值。因此,在相同设备上运行但具有不同签署密钥的应用将不会再看到相同的 Android ID(即使对于同一用户来说,也是如此)。
只要签署密钥相同(并且应用未在 OTA 之前安装到某个版本的 O),ANDROID_ID 的值在软件包卸载或重新安装时就不会发生变化。
即使系统更新导致软件包签署密钥发生变化,ANDROID_ID 的值也不会变化。
要借助一个简单的标准系统实现应用获利,请使用广告 ID。广告 ID 是 Google Play 服务针对广告服务提供的唯一 ID,此 ID 可由用户重置。
查询 net.hostname 系统属性返回的结果为空。
如果某个应用安装的 Thread.UncaughtExceptionHandler 未移交给默认的 Thread.UncaughtExceptionHandler,则当出现未捕获的异常时,系统不会终止应用。从 Android 8.0 开始,在此情况下系统将记录异常堆栈跟踪情况;在之前的平台版本中,系统不会记录异常堆栈跟踪情况。
我们建议,自定义 Thread.UncaughtExceptionHandler 实现始终移交给默认处理程序处理;遵循此建议的应用不受 Android 8.0 此项变更的影响。
联系人提供程序使用情况统计方法的变更
在之前版本的 Android 中,联系人提供程序组件允许开发者获取每个联系人的使用情况数据。此使用情况数据揭示了与某个联系人相关联的每个电子邮件地址和每个电话号码的信息,包括与该联系人联系的次数以及上次联系该联系人的时间。请求 READ_CONTACTS 权限的应用可以读取此数据。
如果应用请求 READ_CONTACTS 权限,它们仍可以读取此数据。从 Android 8.0 开始,使用情况数据查询会返回近似值,而不是精确值。不过,Android 系统内部仍然会保留精确值,因此,此变更不会影响 auto-complete API。
此行为变更会影响以下查询参数:
现在,AbstractCollection.removeAll() 和 AbstractCollection.retainAll() 始终引发 NullPointerException;之前,当集合为空时不会引发 NullPointerException。此项变更使行为符合文档要求。
Android 8.0 更改了企业应用(包括设备规范控制器 (DPC))的某些 API 和功能的行为。这些变更包括:
这些行为变更专门应用于针对 O 平台或更高平台版本的应用。针对 Android 8.0 或更高平台版本进行编译,或将 targetSdkVersion 设为 Android 8.0 或更高版本的应用开发者必须修改其应用以正确支持这些行为(如果适用)。
使用 SYSTEM_ALERT_WINDOW 权限的应用无法再使用以下窗口类型来在其他应用和系统窗口上方显示提醒窗口:
相反,应用必须使用名为 TYPE_APPLICATION_OVERLAY 的新窗口类型。
使用 TYPE_APPLICATION_OVERLAY 窗口类型显示应用的提醒窗口时,请记住新窗口类型的以下特性:
Android 8.0 更改了 ContentResolver.notifyChange() 和 registerContentObserver(Uri, boolean, ContentObserver) 在针对 Android 8.0 的应用中的行为方式。
现在,这些 API 需要在所有 URI 中为颁发机构定义一个有效的 ContentProvider。使用相关权限定义一个有效的 ContentProvider 可帮助您的应用防范来自恶意应用的内容变更,并防止将可能的私密数据泄露给恶意应用。
可点击的 View 对象现在默认也可以成为焦点。如果您希望 View 对象可点击但不可成为焦点,请在包含 View 的布局 XML 文件中将 android:focusable 属性设置为 false,或者将 false 传递至应用界面逻辑中的 setFocusable()。
如果您的应用的网络安全性配置选择退出对明文流量的支持,那么您的应用的 WebView 对象无法通过 HTTP 访问网站。每个 WebView 对象必须转而使用 HTTPS。
有关提升应用安全性的其他准则,请参阅面向 Android 开发者的安全性。
除非身份验证器拥有用户帐号或用户授予访问权限,否则,应用将无法再访问用户帐号。仅拥有 GET_ACCOUNTS 权限尚不足以访问用户帐号。要获得帐号访问权限,应用应使用 AccountManager.newChooseAccountIntent() 或特定于身份验证器的函数。获得帐号访问权限后,应用可以调用 AccountManager.getAccounts() 来访问帐号。
Android 8.0 已弃用 LOGIN_ACCOUNTS_CHANGED_ACTION。相反,应用在运行时应使用 addOnAccountsUpdatedListener() 获取帐号更新信息。
有关新增 API 和增加的帐号访问和可检测性函数的信息,请参阅此文档的“新增 API”部分中的帐号访问和可检测性。
以下变更影响 Android 8.0 的隐私性。
在 Android 8.0 之前,如果应用在运行时请求权限并且被授予该权限,系统会错误地将属于同一权限组并且在清单中注册的其他权限也一起授予应用。
对于针对 Android 8.0 的应用,此行为已被纠正。系统只会授予应用明确请求的权限。然而,一旦用户为应用授予某个权限,则所有后续对该权限组中权限的请求都将被自动批准。
例如,假设某个应用在其清单中列出 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE。应用请求 READ_EXTERNAL_STORAGE,并且用户授予了该权限。如果该应用针对的是 API 级别 24 或更低级别,系统还会同时授予 WRITE_EXTERNAL_STORAGE,因为该权限也属于同一 STORAGE 权限组并且也在清单中注册过。如果该应用针对的是 Android 8.0,则系统此时仅会授予 READ_EXTERNAL_STORAGE;不过,如果该应用后来又请求 WRITE_EXTERNAL_STORAGE,则系统会立即授予该权限,而不会提示用户。
框架会执行音频闪避。进行 AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK 时,应用不会失去焦点。新的 API 适用于需要暂停而不是闪避的应用。请注意,此行为无法在 Android 8.0 1 版本中实现。
当用户打电话时,活动的媒体流将在通话期间静音。
所有与音频相关的 API 都应使用 AudioAttributes 而不是音频流类型来说明音频播放用例。仅为音量控制继续使用音频流类型。流类型(例如,已弃用的 AudioTrack constructor)的其他用途仍然有效,但是系统会将其记录为错误。
使用 AudioTrack 时,如果应用请求了足够大的音频缓冲区,则框架将尝试使用深度缓冲区输出(如果可用)。
在针对 Android 8.0 的应用中,如果原生库包含任何可写且可执行的加载代码段,则不会再加载原生库。倘若某些应用的原生库包含不正确的加载代码段,则此变更可能会导致这些应用停止工作。这是一种安全加强措施。
如需了解详细信息,请参阅可写且可执行的代码段。
与早期的开发者预览版相同,Android 8.0 还有助于更轻松地发现所有与链接器有关的问题。链接器的变更绑定到应用的目标 API 级别。如果应用的目标 API 级别发生链接器变更,则该应用无法加载该库。如果您的目标 API 级别低于发生链接器变更的 API 级别,则 logcat 会显示一条警告消息。在预览版期间,与链接器有关的问题不仅会显示在 logcat 中,也会以 toast 的形式显示。对于特定的 API 级别,警告可能会变成错误,此变更有助于提前发现此类问题。
在 Android 8.0 中,Collections.sort() 是在 List.sort() 的基础上实现的。在 Android 7.x(API 级别 24 和 25)中,则恰恰相反。在过去,List.sort() 的默认实现会调用 Collections.sort()。
此项变更使 Collections.sort() 可以利用优化的 List.sort() 实现,但具有以下限制:
List.sort() 的实现不能调用 Collections.sort(),因为这会导致堆栈因无限递归而溢出。相反,如果您需要 List实现的默认行为,应避免重写 sort()。
如果父类以不适当的方法实现 sort() ,通常最好使用在 List.toArray()、Arrays.sort() 和
ListIterator.set() 的基础上构建的实现重写 List.sort()。例如:
@Override public void sort(Comparator<? super E> c) { Object[] elements = toArray(); Arrays.sort(elements, c); ListIterator<E> iterator = (ListIterator<Object>) listIterator(); for (Object element : elements) { iterator.next(); iterator.set((E) element); } } public void sort(Comparator<? super E> c) { Object[] elements = toArray(); Arrays.sort(elements, c); ListIterator<E> iterator = (ListIterator<Object>) listIterator(); for (Object element : elements) { iterator.next(); iterator.set((E) element); } }
在大多数情况下,您也可以使用根据 API 级别委托给其他默认实现的实现重写 List.sort()。例如:
@Override public void sort(Comparator<? super E> comparator) { if (Build.VERSION.SDK_INT <= 25) { Collections.sort(this); } else { super.sort(comparator); } } public void sort(Comparator<? super E> comparator) { if (Build.VERSION.SDK_INT <= 25) { Collections.sort(this); } else { super.sort(comparator); } }
如果您选择后者只是因为您希望开发一种适用于所有 API 级别的 sort() 函数,可以考虑赋予其一个唯一的名称,例如 sortCompat(),而不是重写 sort()。
现在,Collections.sort() 只是对调用 sort() 的 List 实现进行的一项结构性修改。例如,在 Android
8.0 之前的平台版本中,如果通过调用 List.sort() 进行排序,则当迭代处理 ArrayList 以及在迭代过程中调用 sort()时,会引发 ConcurrentModificationException。而 Collections.sort() 则不会引发异常。
此项变更使平台行为更加一致:现在,两种方法都会引发 ConcurrentModificationException。
Android 8.0 检查确保类加载器在加载新类时不会违反运行时假设条件。不论类引用自 Java(来自 forName())、Dalvik 字节码还是 JNI,都会执行这些检查。平台不会拦截 Java 对 loadClass() 函数的直接调用,也不会检查此类调用的结果。此行为不应影响运行良好的类加载器的正常运行。
平台将检查类加载器返回的类描述符是否与预期的描述符一致。如果返回的描述符与预期不符,平台会引发 NoClassDefFoundError 错误,并在异常日志中存储一条注明不一致之处的详细错误消息。
平台还检查请求的类描述符是否有效。此检查捕获间接加载诸如 GetFieldID() 等类的 JNI 调用,向这些类传递无效的描述符。例如,找不到包含 java/lang/String 签名的字段,是因为此签名无效;它应为 Ljava/lang/String;。
这与 JNI 对 FindClass() 的调用不同,其中 java/lang/String 是一个有效的完全限定名称。
Android 8.0 不支持多个类加载器同时尝试使用相同的 DexFile 对象来定义类。尝试进行此操作,会导致 Android 运行时引发 InternalError 错误,同时显示消息“Attempt to register dex file with multiple class loaders”。
DexFile API 现已弃用,强烈建议您改为使用此平台的类加载器之一,包括 PathClassLoader 或 BaseDexClassLoader。
注: 您可以创建多个引用文件系统中同一个 APK 或 JAR 文件容器的类加载器。这样做通常不会占用大量内存:如果存储而不压缩容器中的 DEX 文件,平台可以对此类文件执行 mmap 操作,而不直接提取它们。但是,如果平台必须从容器中提取 DEX 文件,以这种方式引用 DEX 文件可能占用大量内存。
在 Android 中,所有类加载器都被视为支持并行运行。当多个线程争用同一个类加载器加载相同的类时,第一个完成此操作的线程胜出,而操作结果将用于其他线程。无论类加载器是返回同一个类、返回不同的类还是引发异常,都将发生此行为。该平台静默忽略此类异常。
Android 7.0 包括旨在延长设备电池寿命和减少 RAM 使用的系统行为变更。这些变更可能会影响您的应用访问系统资源,以及您的应用通过特定隐式 intent 与其他应用交互的方式。
低电耗模式
Android 6.0(API 级别 23)引入了低电耗模式,当用户设备未插接电源、处于静止状态且屏幕关闭时,该模式会推迟 CPU和网络活动,从而延长电池寿命。而 Android 7.0则通过在设备未插接电源且屏幕关闭状态下、但不一定要处于静止状态(例如用户外出时把手持式设备装在口袋里)时应用部分 CPU和网络限制,进一步增强了低电耗模式。
图1,低电耗模式如何应用第一级系统活动限制以延长电池寿命的图示。
当设备处于充电状态且屏幕已关闭一定时间后,设备会进入低电耗模式并应用第一部分限制:关闭应用网络访问、推迟作业和同步。如果进入低电耗模式后设备处于静止状态达到一定时间,系统则会对 PowerManager.WakeLock、AlarmManager 闹铃、GPS 和 WLAN 扫描应用余下的低电耗模式限制。无论是应用部分还是全部低电耗模式限制,系统都会唤醒设备以提供简短的维护时间窗口,在此窗口期间,应用程序可以访问网络并执行任何被推迟的作业/同步。
图2,低电耗模式如何在设备处于静止状态达到一定时间后应用第二级系统活动限制的图示。
请注意,激活屏幕或插接设备电源时,系统将退出低电耗模式并移除这些处理限制。此项新增的行为不会影响有关使您的应用适应 Android 6.0(API 级别 23)中所推出的旧版本低电耗模式的建议和最佳做法,如对低电耗模式和应用待机模式进行针对性优化中所讨论。您仍应遵循这些建议(例如使用 Google 云消息传递 (GCM) 发送和接收消息)并开始安排更新计划以适应新增的低电耗模式行为。
Android 7.0 移除了三项隐式广播,以帮助优化内存使用和电量消耗。此项变更很有必要,因为隐式广播会在后台频繁启动已注册侦听这些广播的应用。删除这些广播可以显著提升设备性能和用户体验。
移动设备会经历频繁的连接变更,例如在 WLAN 和移动数据之间切换时。目前,可以通过在应用清单中注册一个接收器来侦听隐式 CONNECTIVITY_ACTION 广播,让应用能够监控这些变更。由于很多应用会注册接收此广播,因此单次网络切换即会导致所有应用被唤醒并同时处理此广播。
同理,在之前版本的 Android 中,应用可以注册接收来自其他应用(例如相机)的隐式 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)。此设置可防止私有文件的元数据泄漏,如它们的大小或存在性。此权限更改有多重副作用:
对于面向 Android 7.0 的应用,Android 框架执行的 StrictMode API 政策禁止在您的应用外部公开 file:// URI。如果一项包含文件 URI 的 intent 离开您的应用,则应用出现故障,并出现 FileUriExposedException 异常。
要在应用间共享文件,您应发送一项 content:// URI,并授予 URI 临时访问权限。进行此授权的最简单方式是使用 FileProvider 类。
此版本引入了一种新的权限模式,如今,用户可直接在运行时管理应用权限。这种模式让用户能够更好地了解和控制权限,同时为应用开发者精简了安装和自动更新过程。用户可为所安装的各个应用分别授予或撤销权限。
对于以 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 权限。
注:当运行 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。
现在,当用户在您的应用中选择文本时,您可以在一个浮动工具栏中显示“剪切”、“复制”和“粘贴”等文本选择操作。其在用户交互实现上与为单个视图启用上下文操作模式中所述的上下文操作栏类似。
要实现可用于文本选择的浮动工具栏,请在您的现有应用中做出以下更改:
请注意,如果您使用 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 引入了以下行为变更。
在此版本中,相机服务中共享资源的访问模式已从之前的“先到先得”访问模式更改为高优先级进程优先的访问模式。对服务行为的变更包括:
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 的行为变更:
在 Android 5.0 中,ART 运行时取代 Dalvik 成为平台默认设置。Android 4.4 中已引入处于实验阶段的 ART 运行时。
有关 ART 的新功能概述,请参阅 ART 简介。部分主要的新功能包括:
大多数 Android 应用无需任何更改就可以在 ART 下工作。不过,部分适合 Dalvik 的技术并不适用于 ART。如需了解有关最重要问题的信息,请参阅在 Android Runtime (ART) 上验证应用行为。如存在以下情况,应特别注意:
在白色(或非常浅)的背景上使用深色文本绘制通知,以便与新的 Material Design 小部件匹配。请确保您的所有通知都与新的配色方案协调一致。如果您的通知看上去不协调,请进行修正:
如果您当前使用 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。
现在,当设备处于活动状态时(即,设备未锁定且其屏幕已打开),通知可以显示在小型浮动窗口中(也称为“浮动通知”)。这些通知看上去类似于精简版的通知,只是浮动通知还显示操作按钮。用户可以在不离开当前应用的情况下处理或清除浮动通知。
可能触发浮动通知的条件示例包括:
如果您的应用在以上任何情形下实现通知,请确保系统正确显示浮动通知。
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 更改了应用的默认行为。
根据权限概述中所述,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。
服务器不支持 TLSv1.1、TLSv1.2 或新的 TLS 扩展
例如,与服务器握手的 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 5.0 移除了对锁定屏幕小部件的支持;它继续为主屏幕上的小组件提供支持。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。