https://mp.weixin.qq.com/s/Ezfm-Xaz3fzsaSm0TU5LMw
Android O 行为变更https://developer.android.google.cn/preview/behavior-changes.html
1. Android O 新特性
前段时间解决了几个 QQ 音乐多窗口屏幕显示的 bug,虽然这个问题最终不是 Android O 版本的问题,多窗口是 Android 7.1 之后引入的(关于多窗口适配需要注意的地方,但是趁此机会了解一下 Android O 版本的新特性也不错,而且 Google IO 大会刚刚过去,趁这个热度介绍一下。 在大会上介绍到的 Android O 新版本更新和优化主要集中在两个方面:Fluid Experiences和 Vitals,Fluid Experience 主要包含了四个显著特性:Notification Dots, Picture In Picture, Autofill Framework 和 Smart Text Selection;而 Vitals 主要在电池续航、安全、启动时间以及稳定性这几个方面做优化。
1.1 通知变更
Android O 版本重新设计了通知,让通知的管理更加方便,首先引入了通知渠道用来让用户统一管理通知,当 targetApi 设置为 O 版本时,必须要实现一个或多个通知渠道,如果设置为 O 版本之前的版本,在 O 版本设备上的行为则和 7.x 版本保持一致。通知渠道提供了一种将应用内的通知变成一个个易于管理组的方法,通知渠道创建并提交到 notification manager 后,便无法通过编程方式修改通知渠道的行为,这些设置之后则由用户掌控。用户现在可以使用一致的系统 UI 管理大多数与通知有关的设置。所有发布至同一通知渠道的通知都具有相同的行为。当用户长摁通知或者通过设置去到通知的设置页面的时候,可以看到这些界面:
通过这个设置页面可以看到,用户可以将应用所有的通知渠道关闭,或者关闭某一个单独的通知渠道,每一个通知渠道也有相应的行为,用户可以去自行修改,比如修改通知渠道的优先级,如果支持的话,用户还可以去声明通知是否同时显示为应用的角标。Android O 还引入了通知角标,当一个应用的通知没有 dismiss 的时候,会在应用的图标上面显示一个角标,长摁这个应用的图标,也会显示通知的详情信息:
O 版本弃用了对单个通知设置优先级的功能,现在是对通知渠道设置优先级,该通知渠道的所有通知都适用于该优先级,优先级从 IMPORTANCE_NONE(0)(https://developer.android.com/reference/android/app/NotificationManager.html#IMPORTANCE_NONE) 至 IMPORTANCE_HIGH(4)(https://developer.android.com/reference/android/app/NotificationManager.html#IMPORTANCE_HIGH),对用户的提醒等级从小到大。关于创建通知渠道组,向渠道组发送通知或者修改通知渠道组设置的代码可以查看 Google 文档:通知渠道(https://developer.android.com/preview/features/notification-channels.html#CreatingGroups)。 同时还引入了一个通知睡眠的功能,用户可以休眠一个通知,让它在指定的时候再出现,被休眠的时候仍然可以修改这个通知的设置,但是不会让这个通知立马出现。另外还可以设置一个通知的超时时间,用来让某个通知在一段时间之后被自动 cancel。其他的比如可以获取通知的清除方式,修改通知的背景颜色,修改通知的样式可以看官方文档:Android O-通知(https://developer.android.com/preview/api-overview.html#notifications)。 使用场景:针对应用的不同优先级别的通知设置不同的通知渠道,强提醒可以发出声音加震动,弱提醒可能仅仅只需要呼吸灯和角标这样等,这样可以最大程度减少对用户的干扰。
1.2 画中画模式
在 Android O 之前,画中画模式已经可用于 Android TV,而 Android O 则让这一个功能可以支持到其他的 Android 设备,当某个 Activity 处于 PIP 模式时,它会回调生命周期的 onPause 方法,所以此时在 PIP 模式下比如视频播放等操作就不能够在 onPause 里面暂停,而应该在 onStop 里面,这一点和多窗口模式一样,来看看它的效果:
我们可以看到在当从 youtube 视频切换出去之后会回到桌面,这时候会有一个视频播放的窗口悬浮在所有的应用之上,这个小窗口在播放视频,而此时点击这个小窗口区域会弹出几个操作按钮,可以选择关闭,或者是重新打开 youtube 视频播放页,而且底部的几个按钮也是可以自定义的,非常方便。 这里需要提到的一点是,升级到 8.0 的系统后不是立马会激活这个功能,激活这个功能可能会有点复杂:
- 第一步开启 System UI Tuner 功能,开启的方式是下拉通知栏,长摁右下角的设置按钮,
直到系统提示 System UI Tuner 已开启;
- 第二步去设置页面 Settings > System > System UI Tuner > Navigation bar,去到 navigation bar 之后选择 extra left button type 或者 extra right button type,选择 keycode,选择完成之后返回到上一个页面填写 right/left keycode 为 171,代表将当前显示页面变为 PIP 模式窗口(如果不支持页面没有任何反应),然后选择一个 right/left icon:之后就会在导航栏上出现一个新增的按钮,这个按钮就是用来将页面进入 PIP 模式;
- 第三步再返回上一个System UI Tuner页面,选择 Picture-in-Picture 模式,进去之后将 Minimize 打开即可。
完成上面的操作之后,进入支持 PIP 模式的页面,比如 youtube 的视频播放页面,点击导航栏新增的那个按钮,页面就会缩小到一个小窗口播放,如上面的实例图片所示。 要指定 Activity 可以使用 PIP 模式,需要在 Manifest文件中将 android:supportsPictureInPicture 设置为 true,除了上面提到的用户手动将 Activity 变成 PIP 模式,还可以使用 Activity.enterPictureInPictureMode(PictureInPictureArgs args) 动态将 Activity 设置为 PIP 模式, PictureInPictureArgs 这个对象参数是用来指定 Activity 处于 PIP 模式时的行为,此对象还指定了各种属性,例如 Activity 的首选纵横比,同时还可以使用 Activity.setPictureInPictureArgs() 更新 Activity 的 PIP 配置设置,如果 Activity 目前处于 PIP 模式,则会更新此设置。 使用场景:这个功能就很贴心了,比起以前的 Multi-window,这个更强调两个应用的主次之分,比较适合的场景可能有视频播放页面的最小化,地图应用的最小化等等。针对 QQ 音乐来说可以使用在直播页面,MV 播放页面等等。
1.3 自适应图标
为了帮助开发者更好的与设备 UI 集成,Android O 支持创建自适应图标,系统可以基于设备选择的蒙版将这些图标显示为不同形状。系统还将实现与图标的自动交互,并在启动器、快捷方式、设置、共享对话框以及概览屏幕中使用它们:
可以通过定义两层图层(前景和背景)来指定桌面图标外观,必须提供没有形状和阴影的 PNG 格式图象作为图层:
在以前的 Android 版本中,图标大小定义为 48 x 48 dp,但是现在必须按照以下的规范定义图层大小:
- 两张图层大小都必须为 108 x 108 dp。
- 图层中心 72 x 72 dp 范围为可视范围。
- 系统会保留四周的 18dp 范围用于生成有趣的视觉效果(如视差和跳动):
创建自适应图标可以参考:Create adaptive icons with Android Studio(https://developer.android.com/preview/features/adaptive-icons.html#studio):
这个就将以前混乱的图标统一化了,现在 Android 很多应用的图标,有的是正方形的,有的带圆弧,而且这圆弧的弧度各有差异,有的图标还是圆形,有的则是不规则的图片,统一之后所有的应用图标将具有一致的风格,比较推荐。
1.4 自动填充框架
Android O 还引入了自动填充框架,简化了用户在账号创建、登录和信用卡表单之类的填写工作,在用户选择自动填充框架之后,新老用户都可以使用自动填充框架,我们使用 Chrome 的时候已经体验过了自动填充用户名和密码的功能,只不过这次是在系统层面提供了这样的一种功能,可以快速的填充用户名,地址甚至密码等,而且用户也不需要去担心安全问题。 同样自动填充框架也需要去设置页面打开: Settings > Apps & Notifications > Default apps > Autofill app,关于如何适配自动填充框架:Autofill Framework(https://developer.android.com/preview/features/autofill.html):
这个场景可以参考 Chrome 的记住账号和密码功能,例如现在的 QQ 登录其实是已经做了一个类似的 Auto-Fill 功能,比较适合用在账号密码等场景上。
1.5 xml 字体和可下载字体
Android O 推出了 xml 字体,可以在资源文件中建立 font 字体资源文件夹,放入相应的字体 ttf 文件,然后建立自己的字体 xml 文件,在 R 文件中编译,最终作为一种资源供 TextView 等使用,
<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
<font
android:fontStyle="normal"
android:fontWeight="400"
android:font="@font/lobster_regular" />
<font
android:fontStyle="italic"
android:fontWeight="400"
android:font="@font/lobster_italic" />
</font-family>
同时 Android O 和 Android support library 26 提供了一个 API,可以从另一个应用中获取字体资源,而不是将字体资源打包到 apk 中或者让 apk 去下载,通过 Android support library 26 版本可以让这个特性支持到 14 版本或者之上的设备上,具体的 API 可以看看这个:Downloadable Fonts(https://developer.android.com/preview/features/downloadable-fonts.html) 或者这个 android-DownloadableFonts(https://github.com/googlesamples/android-DownloadableFonts):
适用场景:这个比较适合在公司的一系列 APP 上使用,更换皮肤同时更换字体等等。
1.6 Pinned Shortcut
这个功能在 7.1.1 之后就已经有了,长摁桌面图标就会显示一个 App shortcuts 菜单栏,然后长摁菜单栏上的一项,就能把它拖下来成为单独的一个应用图标,被拖下来的单独的应用图标就是Pinned shortcuts,虽然这个功能在 7.1.1 引入的,但是在 O 版本我们可以通过提供的 API 按照一定的步骤去使用代码添加:Pinning Shortcuts and Widgets(https://developer.android.com/preview/features/pinning-shortcuts-widgets.html#shortcuts)。 适用场景:这个可以将某些应用使用频繁的小功能独立出来,比如 QQ 的最常用联系人,音乐的听歌识曲等功能。
1.7 TextView 字体自动适配
Android O 版本允许设置 TextView 的字体大小根据设置的初始大小自动放大或者缩小,这样就可以让字体的显示在不同的屏幕和不同的显示内容上达到最优的效果,而且使用 Android support library 26 中的 android.support.v4.widget.TextViewCompat 可以让该特性支持到 14 版本,Android O 版本的 TextView 已经可以支持 autosize 了,设置 autosize 特性也非常简单,在 O 版本上,只需要使用 setAutoSizeTextTypeWithDefaults(@AutoSizeTextType int autoSizeTextType) 或者
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autoSizeTextType="uniform"
/>
就可以了,关于使用的细节:Autosizing TextViews(https://developer.android.com/preview/features/autosizing-textview.html)。 适用场景:TextView 显示内容较多的时候,如果可以接受的话,适当的减小字体的大小,让显示的字数增加。
1.8 媒体增强
Android O 版本新增 VolumeShaper 类,用来为应用提供声音的淡入淡出等音效;新增AudioFocusRequest 类用来提供检测音频焦点的新功能;新增了以下的方法 getMetrics 方法用来返回一个包含配置和性能信息的 Bundle 对象:
- MediaPlayer.getMetrics()
- MediaRecorder.getMetrics()
- MediaCodec.getMetrics()
- MediaExtractor.getMetrics()
MediaPlayer 新增了一些新的方法,这些方法可以用来增强应用处理媒体播放的能力:
- 通过控制缓冲行为改进性能的功能;
- 在搜索帧时进行精细控制;
- 播放受数字版权管理保护的材料的功能(和 MediaDrm 类功能类似,但是不同的是这个不会暴露底层的提取器,版权和加密数据:DRM support(https://developer.android.com/preview/features/media-player.html#drm""))。
音频录制器 MediaRecorder 现在支持对流式传输有用的 MPEG2_TS 格式,MediaMuxer 现在可以处理任意数量的音频和视频流,而不再仅限于一个音频曲目和/或一个视频曲目。使用 addTrack() 可混录所需的任意数量的曲目,MediaMuxer 还可以添加一个或多个包含用户定义的每帧信息的元数据曲目。元数据的格式由应用定义。仅对 MP4 容器支持元数据曲目。
1.8.1 音频播放设置
Android O 允许应用查询和获取设备如何发出声音,应用可以通过 requestAudioFocus()函数来为设备范围的音频焦点提交一个细粒度的请求,比如传入一个 AudioFocusRequest 对象,设置对应的 type,就可以指定获取焦点的类型,同时可以设置当音频焦点被强占时候应用的行为,轻声继续播放还是彻底暂停。
1.8.2 LDAC 音质增强
值得一提的是,在 Android O 上引入了 sony “捐赠”的 LDAC 无线声音加密格式,用来进行高质量音乐的蓝牙通信,这样就可以通过蓝牙耳机播放真正的无损音乐了:
可以看到使用了 LDAC 无线声音加密协议之后,最高可以达到 990kbps 的传输速率,好消息是不是!但是可惜的是 LDAC 只能再 sony 制造的耳机上使用,比如 £330 MDR-1000X,高呼Sony大法好~~
1.9 其他特性
1. 可以设置 Activity 支持广色域; 2. 可以设置最大的屏幕宽高比; 3. 多屏幕支持,支持设备外接一个显示器; 4. 最新版本 emoji 支持,使用 EmojiCompat 类可以让应用在老版本的应用上显示新的 emoji; 5. 支持点击位置的捕捉; 6. 支持设置应用类别,这些类别用于将应用呈现给用户的用途或功能相同的应用归类在一起,例如按流量消耗、电池消耗和存储消耗将应用归类。 7. Smart Text Selection,这个功能有人可能在今年老罗的锤子手机发布会上看到过,思想是很类似的,复制一段数字,就会出现直接拨打电话的选项,复制一段地址就会弹出进入地图的选项,地图 APP 可以一下这个地方能否成为一个很方便入口。
2 Android O 版本行为变更
这个列举了当前可能会影响应用的几个行为变更。
2.1 后台执行限制
Android O 在当进程进入已缓存状态时,如果没有活动的组件,系统将解除应用具有的所有唤醒锁(已缓存状态指的是没有前台 Activity 或者正在执行的前台 Service)。同时 Android O 上运行在后台的应用将会有限制的使用后台的 Service,并且应用也不能在 Manifest 中注册一些不必要的隐式广播用来进行自启等操作:
- 在后台运行的应用对后台服务的访问受到限制;
- 应用无法使用其清单注册大部分隐式广播(即并非专门针对此应用的广播,比如 ACTION_PACKAGE_REPLACED(https://developer.android.com/reference/android/content/Intent.html#ACTION_PACKAGE_REPLACED) 针对所有应用是一个隐式广播,而ACTION_MY_PACKAGE_REPLACED(https://developer.android.com/reference/android/content/Intent.html#ACTION_MY_PACKAGE_REPLACED)只针对本应用就不是一个隐式广播)。
上面的限制针对 targetApi 为 O 和之上的应用生效,但是用户可以在设置页面设置让这个限制对所有 targetApi 的应用生效。
处于前台时,应用可以自由创建和运行前台服务与后台服务。 进入后台时,在某些情况下,在一个持续数分钟的时间窗内,应用仍可以创建和使用服务,这些情况包括:
- 正在处理高优先级别的 FCM 消息;
- 正在接收例如 SMS/MMS 的消息广播;
- 正在从通知处理 PendingIntent 消息;
但是在该时间窗结束后,应用将被视为处于空闲状态, 此时系统将停止应用的后台服务,就像应用已经调用服务的 Service.stopSelf() 方法一样。
官方建议多使用 JobScheduler 来处理后台任务,详细的适配指南:后台执行限制(https://developer.android.com/preview/features/background.html)。
2.2 安全性
Android O 包含以下与安全性有关的变更:
- 不再支持 SSLv3;
- 应用的 WebView 对象将在多进程模式下运行。网页内容在独立的进程中处理,此进程与包含应用的进程相隔离,以提高安全性;
- 在与未正确实现 TLS 协议版本协商的服务器建立 HTTPS 连接时,HttpsURLConnection 不再尝试回退到之前的 TLS 协议版本并重试的权宜方法;
- Android O 将使用安全计算 (SECCOMP) 过滤器来过滤所有应用。允许的系统调用列表仅限于通过 bionic 公开的系统调用。此外,还提供了其他几个后向兼容的系统调用,但我们不建议使用这些系统调用。
2.3 网络连接和 HTTP(S) 连接
Android O 对网络连接和 HTTP(S) 连接行为做出了不少变更,其中包括无正文的 OPTIONS 请求现在有 Content-Length: 0 标头;HttpURLConnection 在包含斜线的主机或颁发机构名称后面附加一条斜线,将 http://example.com 转化为 http://example.com/ ;通过 ProxySelector.setDefault() 设置的自定义代理选择器的范围变化;URI 不能包含空白标签;如果之前执行的 connect() 方法失败,send(java.net.DatagramPacket) 方法将会引发 SocketException;在回退到 TCP Echo 协议之前,InetAddress.isReachable() 会尝试执行 ICMP;隧道 HTTP(S) 连接处理进行了一些变更。 变更内容比较繁多:网络连接和 HTTP(S) 连接(https://developer.android.com/preview/behavior-changes.html#networking-all)。
2.4 权限
在 Android O 之前,如果应用在运行时请求权限并且被授予该权限,系统会错误地将属于同一权限组并且在清单中注册的其他权限也一起授予应用。对于针对 Android O 的应用,此行为已被纠正。系统只会授予应用明确请求的权限。然而,一旦用户为应用授予某个权限,则所有后续对该权限组中权限的请求都将被自动批准。
2.5 媒体变更
- 使用 AudioTrack 时,如果应用请求了足够大的音频缓冲区,则框架将尝试使用深度缓冲区输出(如果可用);
- 音频流类型应仅用于音量控制;所有其他流类型的使用(例如 AudioTrack 构造函数)仍有效,但系统会将其作为错误记录下来;
- 当用户打电话时,活动的媒体流将在通话期间静音;
- 所有与音频相关的 API 均使用 AudioAttributes 来描述音频播放用例;
- 框架会执行音频闪避,进行 AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK 时,应用不会失去焦点。新的 API 适用于需要暂停而不是闪避的应用。不过,Android O 中未提供此行为。
2.6 Native libraries
在针对 Android O 的应用中,如果 Native libraries 包含任何可写且可执行的代码段,则不会再加载 Native libraries,可写和可执行必须是在新版本必须是互斥的,倘若某些应用的 Native libraries 包含不正确的加载代码段,则此变更可能会导致这些应用停止工作,官方文档:Writable and Executable Segments(https://android.googlesource.com/platform/bionic/+/master/android-changes-for-ndk-developers.md#Writable-and-Executable-Segments-Enforced-for-API-level-26)。
2.7 其他
1. ContentProvider 支持分页,即获取内容的选中区域的子集; 2. ContentProvider 和 ContentResolver 增加 refresh 方法,用来让客户端更容易的知道数据是不是最新; 3. JobScheduler 更新,让应用更容易遵从后台执行限制; 4. 集合的处理的变化,AbstractCollection.removeAll() 和 AbstractCollection.retainAll() 始终引发 NullPointerException; 5. 语言区域和国际化变化(https://developer.android.com/preview/behavior-changes.html#lai); 6. 联系人提供程序使用情况统计方法的变更(https://developer.android.com/preview/behavior-changes.html#cpu); 7. 蓝牙 ScanRecord.getBytes() 方法检索的数据长度变更(https://developer.android.com/preview/behavior-changes.html#bt); 8. 输入和导航(https://developer.android.com/preview/behavior-changes.html#ian);
3 Android O 版本 API 变更
3.1 WebView 新 API
Android O 预览版本提供了几个新的 API 用来管理 WebView:
- Version API
- 第一个是提供获取 WebView 版本信息的 API:
PackageInfo webViewPackageInfo = WebView.getCurrentWebViewPackage();
Log.d("MY_APP_TAG", "WebView version: " + webViewPackageInfo.versionName);
- Google Safe Browsing API
- 可以再 Manifest 中配置 enable,然后在 WebView 打开未知不安全 url 的时候提示用户:
<manifest>
<meta-data android:name="android.webkit.WebView.EnableSafeBrowsing"
android:value="true" />
...
<application> ... </application>
</manifest>
- Termination Handle API
- WebView 绘制进程被杀或者 Crash 的回调;
- Renderer Importance API
- 用来设置 WebView 绘制进程的优先级别,为了提供应用的稳定性,一般情况下应用不需要去修改绘制进程优先级,如果需要使用请和
Termination Handle API
- 一起搭配使用;
3.2 findViewById
findViewById 函数现在返回的是 <T extends View>,所以以后 findViewById 就不需要强转了。
3.3 统一的 margins 和 padding
Android 引入了几个新的 xml 属性:
- layout_marginVertical,同时设置 layout_marginTop 和 layout_marginTop 属性;
- layout_marginHorizontal,同时设置 layout_marginLeft 和 layout_marginRight属性;
- paddingVertical,同时设置 paddingTop 和 paddingBottom属性;
- paddingHorizontal,同时设置 paddingLeft 和 paddingRight属性;
3.4 AnimationSet
Android O 中,AnimationSet API 现在支持了动画的 seek 和动画倒转播放,seek 操作可以设置 AnimationSet 从指定的点开始播放,倒转播放则将以前需要重复定义两个相反的动画操作简化成只需要定义一个动画即可。
3.5 提醒窗口
在 Android O 版本之前,应用如果不用 type_toast 显示悬浮窗,一般正常情况下都会使用声明 SYSTEM_ALERT_WINDOW 权限 + 使用 TYPE_SYSTEM_ERROR 的形式来显示悬浮窗,国内的第三方 ROM 也会对此有限制,Android 6.0 版本曾经对悬浮窗有过一次限制,必须要用户手动开启“在其他应用之上显示”的权限才能展示悬浮窗,在 Android O 之后 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 窗口类型显示的提醒窗口。