Android 8.1 功能和 API

Android 8.1(API 级别 27)面向用户和开发者引入了各种新功能。 本文档重点介绍了面向开发者的最新资讯。

Android Oreo(Go 版本)

Android Go 计划旨在为全球数十亿新晋网民优化 Android 体验。从 Android 8.1 开始,我们将 Android 打造为适合入门级设备的出色平台。Android Oreo(Go 版)配置中的功能包括:

  • 内存优化。改进了整个平台的内存用量,以确保应用可以在 RAM 不超过 1GB 的设备上高效运行。
  • 灵活的定位选项。新的硬件功能常量,可让您通过 Google Play 将应用分发到正常或低 RAM 设备。
  • Google Play。虽然所有应用都可在搭载 Android Oreo(Go 版)的设备上使用,但 Google Play 会重点展示经过开发者专门优化、可为数十亿用户提供出色体验的应用(这些应用符合“为数十亿用户打造应用” 指南)。

我们更新了“面向数十亿用户进行构建” 指南,其中新增了有关如何 针对搭载 Android Oreo(Go 版本)的设备优化应用的指导。对于大多数开发者来说,优化现有 APK 或使用 Google Play 的 多 APK 功能来针对低 RAM 设备提供 APK 版本,是为搭载 Android Oreo(Go 版)的设备做好准备的最佳方式。请注意,让应用 更轻巧、更高效可让所有观众受益,无论他们使用哪种设备。

Neural Networks API

Neural Networks API 可为设备端机器学习框架(如 TensorFlow Lite [Google 的跨平台移动设备 ML 库])以及 Caffe2 等提供加速计算和推理。访问 TensorFlow Lite 开源代码库,下载相关内容并查看文档。 TensorFlow Lite 可与 Neural Networks API 搭配使用,在移动设备上高效运行 MobileNet、Inception v3 和 Smart Reply 等模型。

自动填充框架更新

Android 8.1(API 级别 27)对自动填充框架进行了多项改进,您可以将这些改进纳入到自己的应用中。

BaseAdapter 类现在包含 setAutofillOptions() 方法,该方法允许您在适配器中提供值的字符串表示形式。这对于动态生成其适配器中值的 spinner 控件非常有用。例如,您可以使用 setAutofillOptions() 方法来提供用户可以选择的年份列表的字符串表示形式,作为信用卡失效日期的一部分。自动填充服务可以使用字符串表示形式来适当填充需要相应数据的视图。

此外,AutofillManager 类还包含 notifyViewVisibilityChanged(View, int, boolean) 方法,您可以调用该方法来通知框架虚拟结构中视图的可见性发生了变化。此外,该方法还针对非虚拟结构进行了重载。不过,非虚拟结构通常不需要您明确通知框架,因为该方法已由 View 类调用。

Android 8.1 还通过在 SaveInfo 中添加对 CustomDescription and Validator 的支持,让自动填充服务能够更好地自定义保存界面。

自定义说明有助于自动填充服务明确保存的内容;例如,当屏幕包含信用卡时,它可以显示信用卡银行的徽标、信用卡号的后四位数字及其失效日期。如需了解详情,请参阅 CustomDescription 类。

Validator 对象用于在验证器条件未满足时避免显示自动填充保存界面。如需了解详情,请参阅 Validator 类及其子类 LuhnChecksumValidator 和 RegexValidator。

通知

Android 8.1 对通知进行了以下更改:

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 对象是 Parcelable,因此您可以通过 AIDL 轻松将其传递给另一个进程。

SharedMemory API 可与 NDK 中的 ASharedMemory 设施互操作。ASharedMemory 可用于访问文件描述符,然后可将该描述符映射为读取和写入。这是一种在应用之间或单个应用内的多个进程之间共享大量数据的绝佳方式。

WallpaperColors API

Android 8.1(API 级别 27)允许动态壁纸向系统界面提供颜色信息。为此,您可以从位图或可绘制对象创建 WallpaperColors 对象,也可以使用三种手动选择的颜色。 您还可以检索此颜色信息。

如需创建 WallpaperColors 对象,请执行以下任一操作:

如需从壁纸中检索主色、辅色或第三色详细信息,请调用以下方法:

如需将动态壁纸中的任何重大颜色变化通知给系统,请调用 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。read now 会抛出 SocketException。
  • 根 CA 证书集已更改,主要是移除了大量过时的证书,但也移除了 WoSign 和 StartCom 的根证书。如需详细了解此决定,请参阅 Google 安全博客文章最终移除对 WoSign 和 StartCom 证书的信任。