Android 8.1(API 级别 27)为用户和开发者引入了各种新功能。本文重点介绍面向开发者的新功能。
Android Oreo(Go 版本)
Android Go 是一项旨在为全球数十亿网络用户优化 Android 体验的计划。从 Android 8.1 开始,我们就在将 Android 打造成入门级设备的理想平台。Android Oreo(Go 版本)配置中的功能包括:
- 内存优化。 改进了整个平台的内存使用情况,可确保应用可以在内存不超过 1GB 的设备上高效运行。
- 灵活的定位选项。 新的硬件功能常量,可让您通过 Google Play 向正常内存或低内存设备分发应用。
- Google Play。尽管所有应用都可以在搭载 Android Oreo(Go 版本)的设备上使用,但 Google Play 仍会按照“为数十亿用户打造产品”指南展示经过开发者专门优化的应用,以便为数十亿用户提供出色的体验。
我们更新了“为数十亿用户打造产品”指南,加入了有关如何针对搭载 Android Oreo(Go 版本)的设备优化应用的指导。对于大多数开发者来说,优化现有的 APK,或使用 Google Play 的多 APK 功能将某个 APK 版本定位到低内存设备,是针对搭载 Android Oreo(Go 版本)的设备做好准备的最佳方式。请注意,无论您的受众使用何种设备,将应用打造得更加纤巧高效都对他们有益。
Neural Networks API
Neural Networks API 为设备上的机器学习框架提供加速计算和推断功能,这些机器学习框架包括 TensorFlow Lite(Google 面向移动设备推出的跨平台机器学习内容库)以及 Caffe2,等等。要获取下载内容和文档,请访问 TensorFlow Lite 开源代码库。TensorFlow Lite 可与 Neural Networks API 配合使用,在您的移动设备上高效地运行 MobileNets、Inception v3 和智能回复等模型。
自动填充框架更新
Android 8.1(API 级别 27)对自动填充框架进行了多项改进,您可以将这些改进整合到您的应用中。
BaseAdapter
类现在包括 setAutofillOptions()
方法,通过该方法,您可以在适配器中提供字符串形式的值。这对于在其适配器中动态生成值的旋转图标控件非常有用。例如,您可以使用 setAutofillOptions()
方法提供字符串形式的年份列表,供用户选择信用卡失效日期时使用。自动填充服务能够使用字符串表示法恰当填充需要数据的视图。
此外,AutofillManager
类还包括 notifyViewVisibilityChanged(View, int, boolean)
方法,当采用虚拟结构的视图的可见性发生改变时,您可以调用该方法来通知框架。对于非虚拟结构,也需要对该方法进行重载。不过,对于非虚拟结构,由于 View
类已调用该方法,因此通常无需明确通知框架。
Android 8.1 还可以在 SaveInfo
内添加对 CustomDescription
and
Validator
的支持,从而使自动填充服务能够更自如地自定义保存界面的可用性。
自定义说明可帮助自动填充服务说明正在保存的内容。例如,当界面包含信用卡时,它可以显示信用卡发卡行的徽标、信用卡号码的最后四位数以及信用卡的失效日期。要了解详情,请参阅
CustomDescription
类。
Validator
对象用于避免在不符合验证程序条件时显示自动填充保存界面。要了解详情,请参阅 Validator 类及其子类 LuhnChecksumValidator 和 RegexValidator。
通知
Android 8.1 针对通知做了以下更改:
- 现在,应用每秒只能发出一次通知提示音。超过此频率的提示音无法加入队列且会丢失。此项更改不会影响通知行为的其他方面,并且通知消息仍会正常发布。
-
低内存 Android 设备不支持
NotificationListenerService
和ConditionProviderService
,这些设备在调用ActivityManager.isLowRamDevice()
时会返回true
。
EditText 更新
从 API 级别 27 开始,EditText.getText()
方法会返回 Editable
;以前,它会返回 CharSequence
。此项更改可向后兼容,因为 Editable
会实现 CharSequence
。
Editable
接口提供重要的附加功能。例如,由于 Editable
还会实现 Spannable
接口,因此您可以对 EditText
实例中的内容应用标记。
程序化安全浏览操作
通过使用 Safe Browsing API 的 WebView
实现,您的应用可以在 WebView
实例尝试转到 Google 已归类为已知威胁的网址时检测到该行为。WebView
默认会显示一个插页,以警告用户存在已知威胁。通过该界面,用户可以选择仍然加载网址或返回到上一个安全的页面。
在 Android 8.1 中,您可以通过编程的方式定义应用如何响应已知的威胁:
- 您可以控制应用是否向安全浏览功能报告已知威胁。
- 您可以让应用在每次遇到被安全浏览功能归类为已知威胁的网址时,都自动执行特定操作(例如返回安全的页面)。
注意:为了防范已知的威胁,最好等到安全浏览功能完成初始化之后再调用 WebView
对象的 loadUrl()
方法。
以下代码段演示了如何指示应用的 WebView
实例在遇到已知威胁后始终返回安全页面:
AndroidManifest.xml
<manifest> <application> ... <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing" android:value="true" /> </application> </manifest>
MyWebActivity.java
Kotlin
private var superSafeWebView: WebView? = null private var safeBrowsingIsInitialized: Boolean = false // ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) superSafeWebView = WebView(this).apply { webViewClient = MyWebViewClient() safeBrowsingIsInitialized = false startSafeBrowsing(this@SafeBrowsingActivity, { success -> safeBrowsingIsInitialized = true if (!success) { Log.e("MY_APP_TAG", "Unable to initialize Safe Browsing!") } }) } }
Java
private WebView superSafeWebView; private boolean safeBrowsingIsInitialized; // ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); superSafeWebView = new WebView(this); superSafeWebView.setWebViewClient(new MyWebViewClient()); safeBrowsingIsInitialized = false; superSafeWebView.startSafeBrowsing(this, new ValueCallback<Boolean>() { @Override public void onReceiveValue(Boolean success) { safeBrowsingIsInitialized = true; if (!success) { Log.e("MY_APP_TAG", "Unable to initialize Safe Browsing!"); } } }); }
MyWebViewClient.java
Kotlin
class MyWebViewClient : WebViewClient() { // Automatically go "back to safety" when attempting to load a website that // Safe Browsing has identified as a known threat. An instance of WebView // calls this method only after Safe Browsing is initialized, so there's no // conditional logic needed here. override fun onSafeBrowsingHit( view: WebView, request: WebResourceRequest, threatType: Int, callback: SafeBrowsingResponse ) { // The "true" argument indicates that your app reports incidents like // this one to Safe Browsing. callback.backToSafety(true) Toast.makeText(view.context, "Unsafe web page blocked.", Toast.LENGTH_LONG).show() } }
Java
public class MyWebViewClient extends WebViewClient { // Automatically go "back to safety" when attempting to load a website that // Safe Browsing has identified as a known threat. An instance of WebView // calls this method only after Safe Browsing is initialized, so there's no // conditional logic needed here. @Override public void onSafeBrowsingHit(WebView view, WebResourceRequest request, int threatType, SafeBrowsingResponse callback) { // The "true" argument indicates that your app reports incidents like // this one to Safe Browsing. callback.backToSafety(true); Toast.makeText(view.getContext(), "Unsafe web page blocked.", Toast.LENGTH_LONG).show(); } }
视频缩略图提取器
MediaMetadataRetriever
类拥有一个新方法 getScaledFrameAtTime()
,它能够在给定时间值附近找到一个帧,并返回一个与源帧具有相同宽高比的位图,但会对该位图进行缩放,使其能够嵌入具有特定宽高度的矩形。这对于从视频生成缩略图非常有用。
我们建议使用此方法而不是 getFrameAtTime()
,因为后者会返回与源视频具有相同分辨率的位图,导致内存被浪费。例如,4K 视频的一帧是 16MB 的位图,远远大于您所需的缩略图大小。
Shared memory API
Android 8.1(API 级别 27)引入了新的 SharedMemory
API。通过该类,您可以创建、映射和管理匿名 SharedMemory
实例。您在 SharedMemory
对象上针对读取和/或写入设置内存保护,由于 SharedMemory
对象是可打包的,因此您可以通过 AIDL 轻松将其传递给其他进程。
SharedMemory
API 可以与 NDK 中的 ASharedMemory
工具进行互操作。ASharedMemory
提供对文件描述符的访问权限,然后即可映射文件描述符,以进行读取和写入。这是在多个应用之间或者一个应用的多个进程之间共享大量数据的理想方式。
WallpaperColors API
Android 8.1(API 级别 27)支持动态壁纸向系统界面提供颜色信息。为此,您可以从位图、可绘制对象或使用三种手动选择的颜色创建 WallpaperColors
对象。您还可以检索该颜色信息。
要创建 WallpaperColors
对象,请执行以下任一操作:
- 要使用三种颜色来创建
WallpaperColors
对象,请通过传递主要颜色、次要颜色和三级颜色来创建WallpaperColors
类的实例。主要颜色不能为空。 - 要从位图创建
WallpaperColors
对象,请传递位图来源作为参数来调用fromBitmap()
方法。 - 要从可绘制对象创建
WallpaperColors
对象,请传递可绘制对象来源作为参数来调用fromDrawable()
方法。
要从壁纸中检索主要颜色、次要颜色和三级颜色详细信息,请调用以下方法:
getPrimaryColor()
:返回壁纸中最具视觉代表性的颜色。getSecondaryColor()
:返回壁纸中第二主要的颜色。getTertiaryColor()
:返回壁纸中第三主要的颜色。
要在动态壁纸的任何突出颜色发生变化时通知系统,请调用 notifyColorsChanged()
方法。此方法会触发 onComputeColors()
生命周期事件,您可以通过该事件提供新的 WallpaperColors
对象。
要添加监听颜色变化的监听器,您可以调用 addOnColorsChangedListener()
方法。此外,您还可以调用 getWallpaperColors()
方法来检索壁纸的主要颜色。
指纹更新
FingerprintManager
类引入了以下错误代码:
-
FINGERPRINT_ERROR_LOCKOUT_PERMANENT
- 用户尝试使用指纹读取器解锁设备的次数过多。 -
FINGERPRINT_ERROR_VENDOR
- 发生了特定于供应商的指纹读取器错误。
加密更新
Android 8.1 在加密方面进行了多次更改。
- 在 Conscrypt 中实现了新的算法。系统会优先使用 Conscrypt 实现,而不是现有的 Bouncy Castle 实现。新算法包括:
AlgorithmParameters:GCM
KeyGenerator:AES
KeyGenerator:DESEDE
KeyGenerator:HMACMD5
KeyGenerator:HMACSHA1
KeyGenerator:HMACSHA224
KeyGenerator:HMACSHA256
KeyGenerator:HMACSHA384
KeyGenerator:HMACSHA512
SecretKeyFactory:DESEDE
Signature:NONEWITHECDSA
Cipher.getParameters().getParameterSpec(IvParameterSpec.class)
不再适用于使用 GCM 的算法。请改用getParameterSpec(GCMParameterSpec.class)
。- 许多与传输层安全协议 (TLS) 相关的内部 Conscrypt 类都进行了重构。由于开发者有时会需要访问之前的类,因此保留了 shim 以支持以前的使用方式,但一些详细信息已发生变化。例如,套接字以前为
OpenSSLSocketImpl
类型,但现在为ConscryptFileDescriptorSocket
或ConscryptEngineSocket
类型,两者都扩展了OpenSSLSocketImpl
。 - 之前,向
SSLSession
方法传递 null 引用值后,该方法会抛出IllegalArgumentException
,而现在则会抛出NullPointerException
。 - RSA
KeyFactory
不再允许从大于编码密钥的字节数组生成密钥。调用generatePrivate()
和generatePublic()
会提供KeySpec
(其中的密钥结构未填充整个缓冲区),这会导致InvalidKeySpecException
。 - 过去,当套接字读取因套接字被关闭而中断时,Conscrypt 会从读取返回 -1。现在该读取会抛出
SocketException
。 - 根 CA 证书集已发生变化,主要变化是移除了大量过时证书,但也移除了 WoSign 和 StartCom 的根证书。有关此决定的详细信息,请参阅 Google 安全博文:Final removal of trust in WoSign and StartCom Certificates(最终移除对 WoSign 和 StartCom 证书的信任)。