Android 8.1 の機能と API

Android 8.1(API レベル 27)では、ユーザーとデベロッパー向けのさまざまな新機能が導入されています。このドキュメントでは、デベロッパー向けの新機能について説明します。

Android Oreo(Go バージョン)

Android Go は、世界中でインターネットを利用する何十億人もの人々のために Android のエクスペリエンスを最適化するための Google の取り組みです。Android 8.1 以降、Google は Android をエントリレベルのデバイスに最適なプラットフォームにしています。Android Oreo(Go バージョン)構成の機能は次のとおりです。

  • メモリの最適化。プラットフォーム全体のメモリ使用量が改善され、1 GB 以下の RAM を搭載したデバイスでアプリが効率的に実行されるようにしました。
  • 柔軟なターゲティング オプション。新しいハードウェア機能定数を使用することで、Google Play を通じて通常のデバイスまたは低 RAM デバイスへのアプリの配信のターゲットを設定できます。
  • Google Play。すべてのアプリは Android Oreo(Go バージョン)を搭載したデバイスで利用できますが、Google Play では、数十億人を対象としたビルドに関する ガイドラインに沿って、デベロッパーが特に最適化されたアプリを公開します。

何十億人ものユーザー向けにビルドに関する ガイドラインを更新し、 Android Oreo(Go バージョン)を搭載したデバイス向けにアプリを最適化する方法についてのガイダンスを追加しました。ほとんどのデベロッパーにとって、Android Oreo(Go バージョン)を搭載したデバイスに対応するには、既存の APK を最適化するか、Google Play の マルチ APK 機能を使用して、APK の特定のバージョンを低 RAM デバイスにすることをおすすめします。なお、アプリの 軽量化と効率化は、デバイスに関係なくすべてのユーザーにとって有益であることを忘れないでください。

ニューラル ネットワーク API

Neural Networks API は、TensorFlow Lite(Google のモバイル用クロスプラットフォーム ML ライブラリ)や 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 のサポートを追加することで、自動入力サービスで保存 UI アフォーダンスをカスタマイズできるようになりました。

カスタムの説明は、自動入力サービスが保存内容を明確にするのに便利です。たとえば、画面にクレジット カードが含まれている場合は、クレジット カード銀行のロゴ、クレジット カード番号の下 4 桁、有効期限番号を表示できます。詳細については、 CustomDescription クラスをご覧ください。

Validator オブジェクトは、Validator 条件が満たされない場合に自動入力保存 UI が表示されないようにするために使用されます。詳しくは、 Validator クラスとそのサブクラスの LuhnChecksumValidator および RegexValidator をご覧ください。

通知

Android 8.1 では、通知が次のように変更されています。

  • 通知アラート音を 1 秒間に 1 回だけ鳴らすことができるようになりました。このレートを超えるアラート音はキューに追加されず、失われます。この変更は通知動作の他の要素には影響せず、通知メッセージは引き続き想定どおりに送信されます。
  • NotificationListenerServiceConditionProviderService は、ActivityManager.isLowRamDevice() が呼び出されたときに true を返す低 RAM の Android 搭載デバイスではサポートされていません。

EditText の更新

API レベル 27 以降では、EditText.getText() メソッドは Editable を返します。以前は CharSequence を返していました。EditableCharSequence を実装するため、この変更には下位互換性があります。

Editable インターフェースには、重要な追加機能が用意されています。たとえば、EditableSpannable インターフェースも実装しているため、EditText のインスタンス内のコンテンツにマークアップを適用できます。

プログラマティックなセーフ ブラウジング アクション

アプリは、Safe Browsing API の WebView 実装を使用することで、Google が既知の脅威として分類した URL に WebView のインスタンスが移動しようとしたタイミングを検出できます。デフォルトでは、WebView はユーザーに既知の脅威を警告するインタースティシャルを表示します。この画面では、この URL を読み込むか、安全な前のページに戻るかを選択できます。

Android 8.1 では、既知の脅威に対するアプリの対応をプログラムで定義できます。

  • アプリからセーフ ブラウジングに既知の脅威を報告するかどうかは、ご自身で管理できます。
  • セーフ ブラウジングが既知の脅威に分類した URL にアクセスするたびに、安全なページに戻るなどの特定のアクションをアプリに自動的に実行させることができます。

注: 既知の脅威から最適な保護を行うには、セーフ ブラウジングを初期化してから 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 動画のフレームはビットマップが 16 MB あり、サムネイル画像に必要なサイズよりもはるかに大きくなります。

SharedMemory 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)では、ライブ壁紙からシステム UI に色情報を提供できます。そのためには、ビットマップやドローアブルから WallpaperColors オブジェクトを作成するか、手動で選択した 3 つの色を使用します。この色情報を取得することもできます。

WallpaperColors オブジェクトを作成するには、次のいずれかを行います。

  • 3 色を使用して WallpaperColors オブジェクトを作成するには、プライマリ カラー、セカンダリ カラー、ターシャリ カラーを渡して、WallpaperColors クラスのインスタンスを作成します。プライマリ カラーを null にすることはできません。
  • ビットマップから WallpaperColors オブジェクトを作成するには、ビットマップ ソースをパラメータとして渡して fromBitmap() メソッドを呼び出します。
  • ドローアブルから WallpaperColors オブジェクトを作成するには、ドローアブル ソースをパラメータとして渡して fromDrawable() メソッドを呼び出します。

壁紙からプライマリ カラー、セカンダリ カラー、ターシャリ カラーの詳細を取得するには、次のメソッドを呼び出します。

ライブ壁紙の色の大幅な変化をシステムに通知するには、notifyColorsChanged() メソッドを呼び出します。このメソッドは、新しい WallpaperColors オブジェクトを指定可能な onComputeColors() ライフサイクル イベントをトリガーします。

色の変化のリスナーを追加するには、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 を拡張します。
  • null 参照が渡されたときに IllegalArgumentException をスローするために使用されていた SSLSession メソッドが、NullPointerException をスローするようになりました。
  • RSA KeyFactory では、エンコードされた鍵より大きいバイト配列から鍵を生成できなくなりました。キー構造がバッファ全体を埋めない KeySpec を提供する generatePrivate() および generatePublic() を呼び出すと、InvalidKeySpecException になります。
  • ソケットが閉じられることでソケットの読み取りが中断された場合、Conscrypt は読み取りから -1 を返します。読み取りでは SocketException がスローされるようになりました。
  • ルート CA 証明書のセットが変更されました。ほとんどの場合、古い証明書が多数削除され、WoSign と StartCom のルート証明書も削除されました。この決定について詳しくは、Google セキュリティ ブログの投稿「Final removal of trust in WoSign and StartCom Certificates」をご覧ください。