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 或低 RAM 设备。
  • Google Play。虽然所有应用都可以在搭载 Android Oreo(Go 版本)的设备上使用,但 Google Play 会按照“为数十亿用户打造产品” 指南展示经过开发者专门优化的应用,以便为数十亿用户提供出色的体验。

我们更新了“为数十亿用户打造产品” 指南,添加了有关如何 针对搭载 Android Oreo(Go 版本)的设备优化应用的指导。对于大多数开发者来说,优化现有 APK 或使用 Google Play 的 多 APK 功能将某个 APK 版本定位到低 RAM 设备是让搭载 Android Oreo(Go 版本)的设备做好准备的最佳方式。请注意,让您的应用 更精简、更高效对您的所有受众都有益,无论他们使用何种设备。

Neural Networks API

Neural Networks API 为设备上的机器学习框架提供加速计算和推断,例如 Google 面向移动设备的跨平台机器学习库 TensorFlow Lite 以及 Caffe2 等。如需获取下载内容和文档,请访问 TensorFlow Lite 开源代码库。 TensorFlow Lite 可与 Neural Networks API 搭配使用,在您的移动设备上高效运行 MobileNetsInception v3 智能回复等模型。

自动填充框架更新

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

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

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

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

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

Validator 对象用于避免在不符合验证器条件时显示自动填充保存界面。如需了解详情,请参阅 Validator 类及其子类 LuhnChecksumValidatorRegexValidator

通知

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 对象,请执行以下任一操作:

  • 如需使用三种颜色创建 WallpaperColors 对象,请通过传递主色、辅色和第三色来创建 WallpaperColors 类的实例。主要颜色不得为 null。
  • 如需基于位图创建 WallpaperColors 对象,请通过将位图来源作为参数传递来调用 fromBitmap() 方法。
  • 如需基于可绘制对象创建 WallpaperColors 对象,请通过将可绘制对象来源作为参数传递来调用 fromDrawable() 方法。

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

如需将动态壁纸出现的任何显著颜色变化告知系统,请调用 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 类型,但现在是 ConscryptFileDescriptorSocketConscryptEngineSocket 类型,这两者都会扩展 OpenSSLSocketImpl
  • 过去,传递 null 引用时抛出 IllegalArgumentExceptionSSLSession 方法现在会抛出 NullPointerException
  • RSA KeyFactory 不再允许从大于编码密钥的字节数组生成密钥。如果调用 generatePrivate()generatePublic() 时提供了 KeySpec(其中键结构没有填充整个缓冲区),则会导致 InvalidKeySpecException
  • 过去,当套接字读取因套接字被关闭而中断时,Conscrypt 会从读取返回 -1。现在,该读取会抛出 SocketException
  • 根 CA 证书集已更改,主要移除的是大量过时的证书,但还移除了 WoSign 和 StartCom 的根证书。如需详细了解此决定,请参阅 Google 安全博文:最终移除对 WoSign 和 StartCom 证书的信任