隐私权限:
1.强制执行分区存储机制
以 Android 11 为目标平台的应用始终会受分区存储行为的影响
影响应用:以 Android 11 为目标平台的应用,以及以 Android 10 为目标平台且未将 requestLegacyExternalStorage
设为 true
以停用分区存储的应用
1)访问媒体文件:请查看官方文档
2)操作其他文档,请参考这个;
3)分享文件,使用provider,请参考这个;
注意:
1)如果启用了分区存储,则媒体库表 MediaStore.Files
仅显示应用创建的照片、视频和音频文件;未启用则显示所有类型的媒体文件;
2)您可以在调用 update()
的过程中通过更改 MediaColumns.RELATIVE_PATH
或 MediaColumns.DISPLAY_NAME
在磁盘上移动文件。
3)更新媒体库其他应用创建的媒体文件时会抛出异常,处理可用参考这个链接;
4)声明权限的时候可以声明api版本限制;如:
2.单次授权与获取电话号码权限
3.Android 11 中的软件包可见性
影响查询手机中已安装应用,startSevice 显示调用等
4.Android 11 中的前台服务类型
需要显示声明该服务可能访问的数据类型:
...
5。应用进程退出原因
Android 11 引入了 ActivityManager.getHistoricalProcessExitReasons()
方法,用于报告近期任何进程终止的原因。应用可以使用此方法收集崩溃诊断信息,例如进程终止是由于 ANR、内存问题还是其他原因所致。此外,您还可以使用新的 setProcessStateSummary()
方法存储自定义状态信息,以便日后进行分析。
android 10:
1.分区存储
很多厂商没有强制要求android 10 需要分区存储,android 11上强制要求。见android 11 介绍。也可以参考博客
2.限制后台请求用户位置(以android 10 为目标版本收影响)
为了让用户更好地控制应用对位置信息的访问权限,Android 10 引入了 ACCESS_BACKGROUND_LOCATION
权限。
与 ACCESS_FINE_LOCATION
和 ACCESS_COARSE_LOCATION
权限不同,ACCESS_BACKGROUND_LOCATION
权限仅会影响应用在后台运行时对位置信息的访问权限。除非符合以下条件之一,否则应用将被视为在后台访问位置信息:
该应用运行的某个前台设备已声明前台服务类型为 location
。
要声明您的应用中的某个服务的前台服务类型,请将应用的 targetSdkVersion
或 compileSdkVersion
设置为 29
或更高版本。详细了解前台服务如何继续执行用户发起的需要访问位置信息的操作。
以 Android 9 或更低版本为目标平台时自动授予访问权限
3. 限制后台启动Activity
需要有前台界面或者前台服务等,或者拥有SYSTEM_ALERT_WINDOW权限;需要注意该权限的申请,可以参考这个;
google推荐采用“显示通知”的方式来实现后台启动activity
4.限制获取不可重置的硬件标识符,如设备序列号和IMEI等
普通应用无法申请READ_PRIVILEGED_PHONE_STATE
权限;
许多使用场景都不需要不可重置的设备标识符。例如,如果您的应用将不可重置的设备标识符用于广告跟踪或用户分析目的,请为这些特定使用场景使用 Android 广告 ID。要了解详情,请参阅唯一标识符的最佳做法。
5. 限制了对剪贴板数据的访问权限
除非您的应用是默认输入法 (IME) 或是目前处于焦点的应用,否则它无法访问 Android 10 或更高版本平台上的剪贴板数据。
6.限制对屏幕内容的访问
为了保护用户的屏幕内容,Android 10 更改了 READ_FRAME_BUFFER
、CAPTURE_VIDEO_OUTPUT
和 CAPTURE_SECURE_VIDEO_OUTPUT
权限的作用域,从而禁止以静默方式访问设备的屏幕内容。从 Android 10 开始,这些权限只能通过签名访问。
需要访问设备屏幕内容的应用应使用 MediaProjection
API,此 API 会显示提示,要求用户同意访问。
7.面向用户的权限检查(针对旧版应用)
如果您的应用以 Android 5.1(API 级别 22)或更低版本为目标平台,则用户首次在搭载 Android 10 或更高版本的平台上使用您的应用时,系统会向其显示权限屏幕,如图 1 所示。此屏幕让用户有机会撤消系统先前在安装时向应用授予的访问权限。
android 9
一、对所有运行在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
。
注:因为这些权限已变更组并在运行时授予,用户可以拒绝您的应用访问通话记录信息。 在这种情况下,您的应用应该能够妥善处理无法访问信息的状况。
如果您的应用已经遵循运行时权限最佳做法,则可以处理权限组的变更。
在 Android 9 中,应用进行 Wi-Fi 扫描的权限要求比之前的版本更严格。 详情请参阅 Wi-Fi 扫描限制。
类似的限制也适用于 getConnectionInfo()
函数,该函数返回描述当前 Wi-Fi 连接的 WifiInfo
对象。 如果调用应用具有以下权限,则只能使用该对象的函数来检索 SSID 和 BSSID 值:
检索 SSID 或 BSSID 还需要在设备上启用位置服务(在 Settings > Location 下)。
在 Android 9 中,下列事件和广播不接收用户位置或个人可识别数据方面的信息:
WifiManager
中的 getScanResults()
和 getConnectionInfo()
函数。WifiP2pManager
中的 discoverServices()
和 addServiceRequest()
函数。NETWORK_STATE_CHANGED_ACTION
广播。Wi-Fi 的 NETWORK_STATE_CHANGED_ACTION
系统广播不再包含 SSID(之前为 EXTRA_SSID)、BSSID(之前为 EXTRA_BSSID)或连接信息(之前为 EXTRA_NETWORK_INFO)。 如果应用需要此信息,请改为调用 getConnectionInfo()
。
为帮助确保应用稳定性和兼容性,此平台对某些非 SDK 函数和字段的使用进行了限制;无论您是直接访问这些函数和字段,还是通过反射或 JNI 访问,这些限制均适用。 在 Android 9 中,您的应用可以继续访问这些受限的接口;该平台通过 toast 和日志条目提醒您注意这些接口。 如果您的应用显示这样的 toast,则必须寻求受限接口之外的其他实现策略。
在 Android 9 中,您不能从非 Activity 环境中启动 Activity,除非您传递 Intent 标志 FLAG_ACTIVITY_NEW_TASK
。 如果您尝试在不传递此标志的情况下启动 Activity,则该 Activity 不会启动,系统会在日志中输出一则消息。
注:在 Android 7.0(API 级别 24)之前,标志要求一直是期望的行为并被强制执行。 Android 7.0 中的一个错误会临时阻止实施标志要求。
对于Android7.0以下和9.0及以上,非Activity环境启动一个Activity时,老老实实加上FLAG_ACTIVITY_NEW_TASK标记吧;对于Android7.0~8.1系统,调用startActivity(Intent intent)可以不用加标记,调用startActivity(Intent intent, Bundle options)时,options有值则需注意加标记或为options添加上指定的LaunchTaskId。
在 Android 9 设备上运行的应用可以通过调用 getCameraIdList()
发现每个可用的摄像头。 应用不应假定设备只有一个后置摄像头或只有一个前置摄像头。
如果应用以 Android 9 或更高版本为目标平台并使用前台服务,则必须请求 FOREGROUND_SERVICE
权限。这是普通权限,因此,系统会自动为请求权限的应用授予此权限。
在 Android 9 中,Build.SERIAL
始终设为 "UNKNOWN"
,以保护用户隐私。
如果您的应用需要访问设备的硬件序列号,您应改为请求 READ_PHONE_STATE
权限,然后调用 getSerial()
。
以 Android 9 为目标平台的应用应采用私有 DNS API。具体而言,应用应确保,当系统解析器正在通过传输层安全协议 (TLS) 执行 DNS 时,任何内置的 DNS 客户端均使用加密的 DNS 查找与系统相同的主机名,或停用它而改用系统解析器。
如果您的应用以 Android 9 或更高版本为目标平台,则 isCleartextTrafficPermitted()
方法默认返回 false
。如果您的应用需要针对特定网域启用明文,则您必须在应用的网络安全配置中,针对这些网域明确将 cleartextTrafficPermitted
设置为 true
。
在 Android 6.0 中,我们移除了对 Apache HTTP 客户端的支持。从 Android 9 开始,该内容库已从 bootclasspath 中移除,且默认情况下应用无法使用它。
要继续使用 Apache HTTP 客户端,以 Android 9 及更高版本为目标平台的应用可以向其 AndroidManifest.xml
添加以下内容:
0 面积的视图(即宽度或高度为 0)无法再被聚焦。
此外,Activity 不会再在轻触模式下隐式分配初始焦点,而是需要由您根据需要显式请求初始焦点。
以 Android 9 或更高版本为目标平台的应用必须支持草稿版 CSS 颜色模块级别 4 行为,以便处理 4 位和 8 位十六进制数字 CSS 颜色。
Chrome 自版本 52 以来便一直支持 CSS 颜色模块级别 4,但 WebView 目前停用了此功能,因为现有 Android 应用被发现包含 Android ordering (ARGB) 中的 32 位十六进制颜色,而这会导致呈现错误。
例如,对于以 API 级别 27 或更低版本为目标的应用,颜色 #80ff8080
目前在 WebView 中呈现为不透明的浅红色(#ff8080
)。先导组件(Android 将其解读为 Alpha 组件)目前被忽略。如果某个应用以 API 级别 28 或更高级别为目标,则 #80ff8080
会被解读为 50% 透明的浅绿色 (#80ff80
)。
低于 Android 9 的 Android 版本可以通过文件内容推断出 MIME 类型。从 Android 9(API 级别 28)开始,在 WebView 中加载 file:
URI 时,应用必须使用正确的文件扩展名。
使用文件内容推断 MIME 类型可能会导致出现安全错误,现代浏览器通常不允许这样做。
如果文件具有可识别的文件扩展名(例如,.html
、.txt
、.js
或 .css
),则 MIME 类型将由扩展名决定。如果文件没有扩展名或者扩展名无法识别,则 MME 类型将为纯文本。
例如,file:///sdcard/test.html
等 URI 将以 HTML 形式呈现,但 file:///sdcard/test
等 URI 将以纯文本形式呈现,即使相应文件中包含 HTML 数据也是如此。
Android 9 可以正确处理文档的根元素为滚动元素的情况。在之前的版本中,滚动位置在正文元素上设置,根元素的滚动值为零。Android 9 支持符合标准的行为,在这种行为中,滚动元素是根元素。
此外,直接访问 document.body.scrollTop
、document.body.scrollLeft
、document.documentElement.scrollTop
或 document.documentElement.scrollLeft
的行为会因目标 SDK 的不同而异。要访问视口滚动值,请使用 document.scrollingElement
(如果有)。
在 Android 9 之前,已暂停的应用发出的通知会被取消。从 Android 9 开始,已暂停的应用发出的通知会被隐藏,直到应用恢复运行。
1)通知
从 Android 8.0(API 级别 26)开始,必须为所有通知分配渠道,否则通知将不会显示。
setTimeoutAfter()
创建通知时您可以设置超时。您可以使用此函数指定一个持续时间,超过该持续时间后,通知应取消。如果需要,您可以在指定的超时持续时间之前取消通知。Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES
Intent 从通知创建指向应用通知设置的链接时,您可以调用 setSettingsText()
来设置要显示的文本。此系统可以提供以下 Extra 数据和 Intent,用于过滤应用必须向用户显示的设置:EXTRA_CHANNEL_ID
、NOTIFICATION_TAG
和 NOTIFICATION_ID
。NotificationListenerService
类的新 onNotificationRemoved()
函数。Notification.Builder.setColor()
设置所需的背景颜色。这样做将允许您使用 Notification.Builder.setColorized()
启用通知的背景颜色设置。Android 8.0 允许以画中画 (PIP) 模式启动操作组件。PIP 是一种特殊的多窗口模式,最常用于视频播放。
快捷方式分为静态、动态和固定快捷方式。
以 Android 7.1(API 级别 25)或更低版本为目标平台的应用默认的最大屏幕纵横比为 1.86。针对 Android 8.0 或更高版本的应用没有默认的最大纵横比。如果您的应用需要设置最大纵横比,请使用定义您的操作组件的清单文件中的 maxAspectRatio 属性。
从 Android 8.0 开始,此平台为多显示器提供增强的支持。如果 Activity 支持多窗口模式,并且在具有多显示器的设备上运行,则用户可以将 Activity 从一个显示器移动到另一个显示器。当应用启动 Activity 时,此应用可指定 Activity 应在哪个显示器上运行。
Android 8.0 让您可以更轻松地指定 View
元素的对边使用相同外边距和内边距的情形。具体来说,您现在可以在布局 XML 文件中使用以下属性:
layout_marginVertical
,同时定义 layout_marginTop
和 layout_marginBottom
。layout_marginHorizontal
,同时定义 layout_marginLeft
和 layout_marginRight
。paddingVertical
,同时定义 paddingTop
和 paddingBottom
。paddingHorizontal
,同时定义 paddingLeft
和 paddingRight
。某些应用(例如游戏、远程桌面和虚拟化客户端)将大大受益于鼠标指针控制。指针捕获是 Android 8.0 中的一项新功能,可以通过将所有鼠标事件传递到您的应用中焦点视图的方式提供此类控制。
从 Android 8.0 开始,您的应用中的 View
可以请求指针捕获并定义一个侦听器来处理捕获的指针事件。鼠标指针在此模式下将隐藏。如果不再需要鼠标信息,该视图可以释放指针捕获。系统也可以在视图丢失焦点时(例如,当用户打开另一个应用时)释放指针捕获。
在适当的情况下,Android 8.0 允许每个应用声明其所属的类别。这些类别用于将应用呈现给用户的用途或功能类似的应用归类在一起,例如按流量消耗、电池消耗和存储消耗将应用归类。您可以在
清单标记中设置 android:appCategory
属性,定义应用的类别。
从 Android 8.0 开始,AnimatorSet
API 现在支持寻道和倒播功能。寻道功能允许您将动画的位置设置为指定的时间点处。如果您的应用包含可撤消的操作的动画,倒播功能会很有用。现在,您不必定义两组独立的动画,而只需反向播放同一组动画。
Android 8.0 添加了三个新的 StrictMode 检测程序,帮助识别应用可能出现的错误:
detectUnbufferedIo()
将检测您的应用何时读取或写入未缓冲的数据,这可能极大影响性能。detectContentUriWithoutPermission()
将检测您的应用在其外部启动 Activity 时何时意外忘记向其他应用授予权限。detectUntaggedSockets()
将检测您的应用何时使用网络流量,而不使用 setThreadStatsTag(int)
将流量标记用于调试目的。现在,ContentProvider
和 ContentResolver
类均包含 refresh()
函数,这样,客户端可以更轻松地知道所请求的信息是否为最新信息。
您可以扩展 ContentProvider
以添加自定义的内容刷新逻辑。请务必重写 refresh()
函数,以返回 true
,告知提供程序的客户端您已尝试自行刷新数据。
您的客户端应用可通过调用另一个函数(又称 refresh()
),显式请求已刷新的内容。在调用此函数时,传入待刷新数据的 URI。
注:由于您可能通过网络不断请求数据,您应仅在有明显迹象表明内容确已过时时才从客户端调用 refresh()
。执行此类内容刷新最常见的原因是响应滑动刷新手势,该手势显式请求当前界面显示最新内容
Android 8.0 引入了对 JobScheduler
的多项改进。由于您通常可以使用计划作业替代现在受限的后台服务或隐式广播接收器,这些改进可以让您的应用更轻松地符合新的后台执行限制。
Android 8.0 了解用户的个性化分享首选项,在通过哪些应用分享各个类型的内容方面,也有着更好的把握。例如,如果用户为一张收据拍照,Android 8.0 可以建议费用跟踪应用;如果用户自拍,一款社交媒体应用可以更好地处理图像。Android 8.0 可以根据用户的个性化首选项自动学习所有这些模式。
智能分享适用于 image
之外的内容类型,例如 audio
、video
、text
和 URL
等。
要启用智能分享,请将具有最多三个字符串注释的 ArrayList
添加到分享内容的 intent。这些注释应说明内容中的主要部分或主题。下面的代码示例显示了如何向 intent 添加注释:
ArrayList annotations = new ArrayList<>();
annotations.add("topic1");
annotations.add("topic2");
annotations.add("topic3");
intent.putStringArrayListExtra(
Intent.EXTRA_CONTENT_ANNOTATIONS,
annotations
);
如需了解有关智能分享注释的详细信息,请参阅 EXTRA_CONTENT_ANNOTATIONS
。
在兼容设备上,Android 8.0 让应用可以帮助用户以更有意义的方式与文本交互。当用户长按某个实体中可识别格式的单词(例如某个地址或餐馆名称)时,系统会选中整个实体。用户会看到一个浮动工具栏,该工具栏包含可以处理所选文本实体的应用。例如,如果系统识别出某个地址,它可以将用户导向地图应用。
系统识别的实体包括地址、网址、电话号码和电子邮件地址。如需了解详细信息,请参阅 TextClassifier
。
Android 8.0 引入了多个与电话有关的新权限:
ANSWER_PHONE_CALLS
允许您的应用通过编程方式接听呼入电话。要在您的应用中处理呼入电话,您可以使用 acceptRingingCall()
函数。READ_PHONE_NUMBERS
权限允许您的应用读取设备中存储的电话号码。这些权限均被划分为危险类别,属于 PHONE
权限组。
Android 8.0 对应用访问用户帐号的方式引入多项改进。对于由身份验证器管理的帐号,身份验证器在决定对应用隐藏帐号还是显示帐号时可以使用自己的策略。Android 系统跟踪可以访问特定帐号的应用。
Android 8.0 为提高电池续航时间而引入的变更之一是,当您的应用进入已缓存状态时,如果没有活动的组件,系统将解除应用具有的所有唤醒锁。
此外,为提高设备性能,系统会限制未在前台运行的应用的某些行为。具体而言:
默认情况下,这些限制仅适用于针对 O 的应用。不过,用户可以从 Settings 屏幕为任意应用启用这些限制,即使应用并不是以 O 为目标平台。
Android 8.0 还对特定函数做出了以下变更:
startService()
函数,则该函数将引发一个 IllegalStateException
。Context.startForegroundService()
函数将启动一个前台服务。现在,即使应用在后台运行,系统也允许其调用 Context.startForegroundService()
。不过,应用必须在创建服务后的五秒内调用该服务的 startForeground()
函数。如需了解详细信息,请参阅后台执行限制。
为节约电池电量、保持良好的用户体验和确保系统健康运行,在运行 Android 8.0 的设备上使用后台应用时,降低了后台应用接收位置更新的频率。此行为变更会影响包括 Google Play 服务在内的所有接收位置更新的应用。
此类变更会影响以下 API:
为确保您的应用按预期方式运行,请完成以下步骤:
如需了解此类变更的详细信息,请参阅后台位置限制。
Android 8.0 对应用快捷方式做出了以下变更:
com.android.launcher.action.INSTALL_SHORTCUT
广播不再会对您的应用有任何影响,因为它现在是私有的隐式广播。相反,您应使用 ShortcutManager
类中的 requestPinShortcut()
函数创建应用快捷方式。ACTION_CREATE_SHORTCUT
Intent 可以创建可使用 ShortcutManager
类进行管理的应用快捷方式。此 Intent 还可以创建不与 ShortcutManager
交互的旧版启动器快捷方式。在以前,此 Intent 只能创建旧版启动器快捷方式。requestPinShortcut()
创建的快捷方式和在处理 ACTION_CREATE_SHORTCUT
Intent 的操作组件中创建的快捷方式均已转换为功能齐全的应用快捷方式。因此,应用现在可以使用 ShortcutManager
中的函数来更新这些快捷方式。如需了解有关应用快捷方式变更的更多信息,请参阅固定快捷方式和微件预览功能指南。
AbstractCollection.removeAll()
和 AbstractCollection.retainAll()
始终引发 NullPointerException
;之前,当集合为空时不会引发 NullPointerException
。此项变更使行为符合文档要求。使用 SYSTEM_ALERT_WINDOW
权限的应用无法再使用以下窗口类型来在其他应用和系统窗口上方显示提醒窗口:
TYPE_PHONE
TYPE_PRIORITY_PHONE
TYPE_SYSTEM_ALERT
TYPE_SYSTEM_OVERLAY
TYPE_SYSTEM_ERROR
相反,应用必须使用名为 TYPE_APPLICATION_OVERLAY
的新窗口类型。
使用 TYPE_APPLICATION_OVERLAY
窗口类型显示应用的提醒窗口时,请记住新窗口类型的以下特性:
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 开发者的安全性。
以下变更影响 Android 8.0 的隐私性。
net.dns1
、net.dns2
、net.dns3
和 net.dns4
不再可用,此项变更可加强平台的隐私性。ACCESS_NETWORK_STATE
权限的应用可以注册 NetworkRequest
或 NetworkCallback
对象。这些类在 Android 5.0(API 级别 21)及更高版本中提供。Build.getSerial()
函数,该函数要求具有 READ_PHONE_STATE
权限。LauncherApps
API 不再允许工作资料应用获取有关主个人资料的信息。当某个用户在托管配置文件中时,LauncherApps
API 的行为就像同一配置文件组的其他配置文件中未安装任何应用一样。和之前一样,尝试访问无关联的个人资料会引发 SecurityExceptions。在 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 版本中实现。AudioAttributes
而不是音频流类型来说明音频播放用例。仅为音量控制继续使用音频流类型。流类型(例如,已弃用的 AudioTrack constructor
)的其他用途仍然有效,但是系统会将其记录为错误。AudioTrack
时,如果应用请求了足够大的音频缓冲区,则框架将尝试使用深度缓冲区输出(如果可用)。在 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 iterator = (ListIterator
在大多数情况下,您也可以使用根据 API 级别委托给其他默认实现的实现重写 List.sort()
。例如:
@Override
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 中,所有类加载器都被视为支持并行运行。当多个线程争用同一个类加载器加载相同的类时,第一个完成此操作的线程胜出,而操作结果将用于其他线程。无论类加载器是返回同一个类、返回不同的类还是引发异常,都将发生此行为。该平台静默忽略此类异常。
MediaMetadataRetriever
类拥有一个新方法 getScaledFrameAtTime()
,它能够在给定时间值附近找到一个帧,并返回一个与源帧具有相同宽高比的位图,但会对该位图进行缩放,使其能够嵌入具有特定宽高度的矩形。这对于从视频生成缩略图非常有用。
我们建议使用此方法而不是 getFrameAtTime()
,因为后者会返回与源视频具有相同分辨率的位图,导致内存被浪费。例如,4K 视频的一帧是 16MB 的位图,远远大于您所需的缩略图大小。
Android 8.1(API 级别 27)引入了新的 SharedMemory
API。通过该类,您可以创建、映射和管理匿名 SharedMemory
实例。您在 SharedMemory
对象上针对读取和/或写入设置内存保护,由于 SharedMemory
对象是可打包的,因此您可以通过 AIDL 轻松将其传递给其他进程。
SharedMemory
API 可以与 NDK 中的 ASharedMemory
工具进行互操作。ASharedMemory
提供对文件描述符的访问权限,然后即可映射文件描述符,以进行读取和写入。这是在多个应用之间或者一个应用的多个进程之间共享大量数据的理想方式。
在 Android 7.0 中,我们为该平台引入了一个新的而且非常需要的多任务处理功能 — 多窗口支持。
现在,用户可以一次在屏幕上打开两个应用。(主要是分屏)
从 Android 7.0 及更高版本中的 Chrome 版本 51 开始,您的设备中的 Chrome APK 用于提供和渲染 Android 系统 WebView。这种方法改善了设备本身的内存使用率,同时减少保持 WebView 更新所需的带宽(因为只要保持启用 Chrome,单机版 WebView APK 将不再进行更新)。
您可以启用开发者选项和选择 WebView 实现,选择您的 WebView 提供商。您可以使用设备上安装的任何兼容的 Chrome 版本(Dev、Beta 或 Stable)或单机版 Webview APK,作为 WebView 实现。
从 Android 7.0 中的 Chrome 版本 51 开始,WebView 将开发者选项“多进程 WebView”被启用时,在一个单独的沙盒进程中运行网页内容。
我们正在寻求关于 N 中的兼容性和运行时性能的反馈,并随后将在未来 Android 版本中启用多进程 WebView。在这个版本中,可预期启动时间回归、总内存使用和软件渲染性能。
在 Android 7.0 中,通过使用说明性“网络安全性配置”(而不是使用传统的易出错的编程 API(例如,X509TrustManager)),应用可以安全地自定义其安全(HTTPS、TLS)连接的行为,无需任何代码修改。
Android 7.0 引入一项新的应用签名方案 APK Signature Scheme v2,它能提供更快的应用安装时间和更多针对未授权 APK 文件更改的保护。在默认情况下,Android Studio 2.2 和 Android Plugin for Gradle 2.2 会使用 APK Signature Scheme v2 和传统签名方案来签署您的应用。
在 Android 7.0 中,应用可以使用新的 API 请求访问特定的外部存储目录,包括可移动媒体上的目录,如 SD 卡。新 API 大大简化了应用访问标准外部存储目录的方式,如 Pictures
目录。应用(如照片应用)可以使用这些 API(而不是使用 READ_EXTERNAL_STORAGE
),其授予所有存储目录的访问权限或存储访问框架,从而让用户可以导航到目录。
二、变更
Android 6.0(API 级别 23)引入了低电耗模式,当用户设备未插接电源、处于静止状态且屏幕关闭时,该模式会推迟 CPU 和网络活动,从而延长电池寿命。而 Android 7.0 则通过在设备未插接电源且屏幕关闭状态下、但不一定要处于静止状态(例如用户外出时把手持式设备装在口袋里)时应用部分 CPU 和网络限制,进一步增强了低电耗模式。
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 6.0 版移除了对 Apache HTTP 客户端的支持。如果您的应用使用该客户端,并以 Android 2.3(API 级别 9)或更高版本为目标平台,请改用 HttpURLConnection
类。此 API 效率更高,因为它可以通过透明压缩和响应缓存减少网络使用,并可最大限度降低耗电量。要继续使用 Apache HTTP API,您必须先在 build.gradle
文件中声明以下编译时依赖项:
android {
useLibrary 'org.apache.http.legacy'
}
此版本移除了 Notification.setLatestEventInfo()
方法。请改用 Notification.Builder
类来构建通知。要重复更新通知,请重复使用 Notification.Builder
实例。调用 build()
方法可获取更新后的 Notification
实例。
adb shell dumpsys notification
命令不再打印输出您的通知文本。请改用 adb shell dumpsys notification --noredact
命令打印输出 notification 对象中的文本。
Android 5.1 添加了对同时使用多个蜂窝运营商 SIM 卡的支持。有了此功能,用户可以在具有两个或多个 SIM 卡插槽的设备上激活和使用额外的 SIM。
您可以通过 SubscriptionManager
类获取有关当前激活的 SIM 的信息,包括设备是否被认为在当前网络上漫游。对于希望为对数据访问费用敏感的设备用户减少或关闭应用数据访问的开发者而言,这些信息非常有用。可以通过请求 READ_PHONE_STATE
权限和对 SubscriptionManager
对象设置 SubscriptionManager.OnSubscriptionsChangedListener
,提醒您的应用注意设备当前网络连接的状态变化。
Android 5.1 中已弃用 org.apache.http
类和 android.net.http.AndroidHttpClient
类。这些类将不再保留,您应尽快将使用这些 API 的任何应用代码迁移至 URLConnection
类。
一、新增
Android 5.0 添加了对 Android 的新 Material Design 样式的支持。您可以创建具有 Material Design 功能的应用,实现动态视觉效果,利用其中的 UI 元素转换赋予用户自然的感觉。此支持包括:
RecyclerView
小部件在之前的版本中,最近使用的应用屏幕只能为最近与用户交互过的每个应用显示一项任务。现在,您的应用可以根据需要为其他并发文档 Activity 打开更多任务。此功能简化了多任务处理,通过在所有应用中提供一致的切换体验,让用户能够在最近使用的应用屏幕中的各个 Activity 和文档之间快速切换。此类并行任务示例可能包括:网络浏览器应用中打开的标签页、效率类应用中的文档、游戏中的并行对局或信息应用中的聊天。您的应用可以通过 ActivityManager.AppTask
类管理它的任务。
为插入逻辑换行符以便系统将您的 Activity 视为新任务,请在使用 startActivity()
启动 Activity 时使用 FLAG_ACTIVITY_NEW_DOCUMENT
。您还可以通过在清单中将 documentLaunchMode
属性设置为 "intoExisting"
或 "always"
来获得此行为。
为避免使最近使用的应用屏幕变得混乱,您可以在应用中设置该屏幕中可显示的任务数上限。要实现此目的,请设置 android:maxRecents
。目前可指定的上限为每位用户 50 个任务(RAM 较低设备为 25 个)。
可将最近使用的应用屏幕中的任务设置为在重启后保留。要控制持久化行为,请使用 android:persistableMode 属性。您还可以通过调用 setTaskDescription()
方法,更改 Activity 在最近使用的应用屏幕中的视觉属性,如 Activity 的颜色、标签和图标。
android.media.projection
API,让您可以为应用添加屏幕采集和屏幕共享功能。例如,如果您想在视频会议应用中启用屏幕共享,便可使用此功能。新增的 createVirtualDisplay()
方法允许您的应用将主屏幕(默认显示)的内容采集到一个 Surface
对象中,然后您的应用便可将其发送至整个网络。该 API 只允许采集非安全屏幕内容,不允许采集系统音频。要开始采集屏幕,您的应用必须先使用通过 createScreenCaptureIntent()
方法获得的 Intent
启动屏幕采集对话框,请求用户授予权限。
MediaProjectionDemo
类。Android 5.0 新增了一个 JobScheduler
API,允许您定义一些系统在稍后或指定条件下(如设备充电时)以异步方式运行的作业,从而优化电池寿命。下列情形下,作业计划排定功能很有用:
一个作业单位由一个 JobInfo
对象封装。该对象指定计划排定标准。
使用 JobInfo.Builder
类可配置应如何运行已排计划的任务。您可以安排任务在特定条件下运行,例如:
例如,您可以添加一段如下代码,在无限流量网络上运行您的任务:
JobInfo uploadTask = new JobInfo.Builder(mJobId,
mServiceComponent /* JobService component */)
.setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED)
.build();
JobScheduler jobScheduler =
(JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(uploadTask);
如果设备有稳定的电源(也就是说,设备已插入电源超过 2 分钟,并且电池处于健康水平),系统将运行任何已做好运行准备的计划作业,无论作业期限是否已过。
要查看如何使用 JobScheduler
API 的示例,请参阅此版本中的 JobSchedulerSample
实现示例。
在 Android 5.0 中,ART 运行时取代 Dalvik 成为平台默认设置。Android 4.4 中已引入处于实验阶段的 ART 运行时。
有关 ART 的新功能概述,请参阅 ART 简介。部分主要的新功能包括:
大多数 Android 应用无需任何更改就可以在 ART 下工作。不过,部分适合 Dalvik 的技术并不适用于 ART。如需了解有关最重要问题的信息,请参阅在 Android Runtime (ART) 上验证应用行为。如存在以下情况,应特别注意:
Android 5.0 中引入新的“并发文档和 Activity 任务”功能后(请参阅下文最近使用的应用屏幕中的并发文档和 Activity),为提升用户隐私的安全性,现已弃用 ActivityManager.getRecentTasks()
方法。对于向后兼容性,此方法仍会返回它的一小部分数据,包括调用应用自己的任务和可能的一些其他非敏感任务(如首页)。如果您的应用使用此方法检索它自己的任务,则改用 getAppTasks()
检索该信息。
Context.bindService()
方法现在需要显式 Intent
,如果提供隐式 intent,将引发异常。为确保应用的安全性,请使用显式 intent 启动或绑定 Service
,且不要为服务声明 intent 过滤器。
Android 5.0 移除了对锁定屏幕小部件的支持;它继续为主屏幕上的小组件提供支持。