Android 8.0 の動作の変更点

新機能に加えて、Android 8.0(API レベル 26)では、さまざまなシステムおよび API の動作が変更されています。このドキュメントでは、アプリで把握して考慮すべき主な変更点について説明します。

これらの変更のほとんどは、ターゲットとする Android のバージョンに関係なく、すべてのアプリに影響します。ただし、Android 8.0 をターゲットとするアプリにのみ影響する変更点もあります。わかりやすくするため、このページはすべてのアプリに関する変更Android 8.0 をターゲットとするアプリの変更点の 2 つのセクションに分かれています。

すべてのアプリ向けの変更

これらの動作変更は、ターゲットとする API レベルに関係なく、Android 8.0(API レベル 26)プラットフォームで実行されるすべてのアプリに適用されます。すべてのデベロッパーは、これらの変更を確認し、該当する場合はアプリを修正して適切に反映させる必要があります。

バックグラウンド実行の上限

バッテリー駆動時間を改善するために Android 8.0(API レベル 26)に導入された変更の 1 つは、アプリがアクティブなコンポーネントがない状態でキャッシュ状態になったとき、アプリが保持しているウェイクロックをすべて解放することです。

また、デバイスのパフォーマンスを改善するため、フォアグラウンドで実行されていないアプリによる特定の動作は、システムによって制限されます。以下にご紹介します。

  • バックグラウンドで実行されているアプリに対して、バックグラウンド サービスに自由にアクセスできる回数に制限が課されるようになりました。
  • アプリは、マニフェストを使用してほとんどの非明示的ブロードキャスト(つまり、アプリが対象となっていないブロードキャスト)を登録することはできません。

デフォルトでは、これらの制限は O をターゲットとするアプリにのみ適用されます。ただし、アプリが O をターゲットとしていなくても、ユーザーは [設定] 画面からすべてのアプリに対してこれらの制限を有効にできます。

Android 8.0(API レベル 26)では、特定のメソッドが次のように変更されています。

  • Android 8.0 をターゲットとするアプリがバックグラウンド サービスの作成が許可されていない状況でこのメソッドを使用しようとすると、startService() メソッドは IllegalStateException をスローするようになりました。
  • 新しい Context.startForegroundService() メソッドは、フォアグラウンド サービスを開始します。アプリがバックグラウンドにあっても、Context.startForegroundService() を呼び出すことができます。ただし、アプリはサービスが作成されてから 5 秒以内に、そのサービスの startForeground() メソッドを呼び出す必要があります。

詳細については、バックグラウンド実行制限をご覧ください。

Android のバックグラウンドでの位置情報の制限

バッテリー、ユーザー エクスペリエンス、システムの健全性を維持するため、Android 8.0 搭載デバイスで使用するバックグラウンド アプリが位置情報の更新データを受信する頻度は下がります。この動作変更は、Google Play 開発者サービスを含め、位置情報の更新を受信するすべてのアプリに影響します。

これらの変更は、次の API に影響します。

  • Fused Location Provider(FLP)
  • ジオフェンス
  • GNSS 測定
  • Location Manager
  • Wi-Fi Manager

アプリが想定どおりに実行されるようにするには、次の手順を行います。

  • アプリのロジックを見直し、最新の Location API を使用していることを確認してください。
  • 各ユースケースで想定される動作をアプリが示すかどうかをテストします。
  • ユーザーの現在地に依存するユースケースを処理するには、Fused Location Provider(FLP)またはジオフェンスの使用を検討してください。

これらの変更について詳しくは、バックグラウンドでの位置情報の制限をご覧ください。

アプリのショートカット

Android 8.0(API レベル 26)では、アプリのショートカットが次のように変更されています。

  • com.android.launcher.action.INSTALL_SHORTCUT ブロードキャストは、非公開の暗黙的ブロードキャストになったため、アプリに影響しません。代わりに、ShortcutManager クラスの requestPinShortcut() メソッドを使用してアプリのショートカットを作成する必要があります。
  • これで、ACTION_CREATE_SHORTCUT インテントで、ShortcutManager クラスを使用して管理するアプリ ショートカットを作成できるようになりました。このインテントでは、ShortcutManager とやり取りしないレガシー ランチャー ショートカットを作成することもできます。以前は、このインテントではレガシー ランチャー ショートカットのみを作成できました。
  • requestPinShortcut() を使用して作成されたショートカットと、ACTION_CREATE_SHORTCUT インテントを処理するアクティビティで作成されたショートカットは、本格的なアプリ ショートカットになりました。その結果、アプリは ShortcutManager のメソッドを使用してアプリを更新できるようになりました。
  • 以前のショートカットは、以前のバージョンの Android の機能が維持されていますが、アプリで手動でアプリのショートカットに変換する必要があります。

アプリのショートカットの変更について詳しくは、ショートカットとウィジェットの固定機能ガイドをご覧ください。

ロケールと国際化

Android 7.0(API レベル 24)では、デフォルトのカテゴリ ロケールを指定できるというコンセプトが導入されましたが、一部の API では、デフォルトの DISPLAY カテゴリ ロケールを使用すべき場合、引数なしで汎用 Locale.getDefault() メソッドを引き続き使用しています。Android 8.0(API レベル 26)では、以下のメソッドが Locale.getDefault() ではなく Locale.getDefault(Category.DISPLAY) を使用するようになりました。

Locale.getDisplayScript(Locale) は、Locale 引数で指定された displayScript 値を使用できない場合も Locale.getDefault() にフォールバックします。

追加のロケールと国際化に関連する変更は次のとおりです。

  • Currency.getDisplayName(null) を呼び出すと、ドキュメントに記載されている動作と同じように NullPointerException がスローされます。
  • タイムゾーン名の解析が変更されました。以前の Android デバイスでは、起動時にサンプリングされたシステム クロック値を使用して、日時の解析に使用されるタイムゾーン名がキャッシュされていました。その結果、起動時などのまれなケースでシステム クロックが正しくない場合、解析に悪影響が及ぶ可能性があります。

    現在では、一般的に解析ロジックでタイムゾーン名を解析する際に、ICU と現在のシステム クロック値が使用されます。この変更により、アプリが SimpleDateFormat などのクラスを使用している場合、より正確な結果が得られ、以前の Android バージョンとは異なる場合があります。

  • Android 8.0(API レベル 26)では、ICU のバージョンがバージョン 58 にアップデートされています。

アラート期間

アプリが SYSTEM_ALERT_WINDOW 権限と次のいずれかのウィンドウ タイプを使用して、他のアプリやシステム ウィンドウの上にアラート ウィンドウを表示しようとしている場合:

これらのウィンドウは常に TYPE_APPLICATION_OVERLAY ウィンドウ タイプを使用するウィンドウの下に表示されます。Android 8.0(API レベル 26)をターゲットとするアプリの場合、アプリは TYPE_APPLICATION_OVERLAY ウィンドウ タイプを使用してアラート ウィンドウを表示します。

詳しくは、Android 8.0 をターゲットとするアプリの動作変更に含まれるアラート ウィンドウの一般的なウィンドウ タイプのセクションをご覧ください。

入力とナビゲーション

ChromeOS やその他の大規模フォーム ファクタ(タブレットなど)で Android アプリが登場する中、Android アプリ内でのキーボード ナビゲーションの使用が復活しています。Android 8.0(API レベル 26)では、キーボードをナビゲーション入力デバイスとして使用するように再対応しました。これにより、矢印ベースのナビゲーションとタブベースのナビゲーションの、信頼性が高く予測可能なモデルになりました。

特に、要素のフォーカス動作に次の変更を加えました。

  • View オブジェクト(フォアグラウンドとバックグラウンド ドローアブルのいずれか)にフォーカス状態の色を定義していない場合、フレームワークは View のデフォルトのフォーカス ハイライトの色を設定するようになりました。このフォーカス ハイライトは、アクティビティのテーマに基づく波紋ドローアブルです。

    View オブジェクトがフォーカスを取得したときにこのデフォルトのハイライトを使用しない場合は、View を含むレイアウト XML ファイルで android:defaultFocusHighlightEnabled 属性を false に設定するか、アプリの UI ロジックで falsesetDefaultFocusHighlightEnabled() に渡します。

  • キーボード入力が UI 要素のフォーカスにどのように影響するかをテストするには、[Drawing] > [Show layout bounds] 開発者向けオプションを有効にします。Android 8.0 でこのオプションを指定すると、現在フォーカスされている要素の上に「X」アイコンが表示されます。

また、Android 8.0 のツールバー要素はすべて、自動的にキーボード ナビゲーション クラスタになり、ユーザーは各ツールバー全体を簡単に内外で移動できるようになります。

アプリ内のキーボード ナビゲーションのサポートを改善する方法について詳しくは、キーボード ナビゲーションのサポートのガイドをご覧ください。

ウェブフォームの自動入力

Android 自動入力フレームワークが自動入力機能の組み込みサポートを提供するようになったため、Android 8.0(API レベル 26)を搭載したデバイスにインストールされているアプリにおいて、WebView オブジェクトに関連する以下のメソッドが変更されました。

WebSettings
  • getSaveFormData() メソッドが false を返すようになりました。これまでは、このメソッドは代わりに true を返していました。
  • setSaveFormData() を呼び出しても効果はなくなりました。
WebViewDatabase
  • clearFormData() を呼び出しても効果はなくなりました。
  • hasFormData() メソッドが false を返すようになりました。これまでは、フォームにデータが含まれている場合、このメソッドは true を返していました。

ユーザー補助

Android 8.0(API レベル 26)では、ユーザー補助機能が次のように変更されています。

  • ユーザー補助フレームワークは、すべてのダブルタップ ジェスチャーを ACTION_CLICK アクションに変換するようになりました。この変更により、TalkBack は他のユーザー補助サービスと同じように動作できるようになります。

    アプリの View オブジェクトがカスタムタップ処理を使用している場合、TalkBack で引き続き動作することを確認してください。View オブジェクトが使用するクリック ハンドラの登録のみが必要な場合もあります。これらの View オブジェクトで実行されたジェスチャーを TalkBack が引き続き認識できない場合は、performAccessibilityAction() をオーバーライドします。

  • ユーザー補助サービスは、アプリの TextView オブジェクト内のすべての ClickableSpan インスタンスを認識するようになりました。

アプリのユーザー補助機能を強化する方法について詳しくは、ユーザー補助機能をご覧ください。

ネットワークと HTTP(S) 接続

Android 8.0(API レベル 26)では、ネットワークと HTTP(S) 接続に関して次のような動作が変更されています。

  • 本文のない OPTIONS リクエストには Content-Length: 0 ヘッダーが含まれます。以前は、Content-Length ヘッダーがありませんでした。
  • HttpURLConnection は、ホスト名またはオーソリティ名の後にスラッシュを付加して、空のパスを含む URL を正規化します。たとえば、http://example.comhttp://example.com/ に変換します。
  • ProxySelector.setDefault() で設定されたカスタム プロキシ セレクタは、リクエストされた URL のアドレス(スキーム、ホスト、ポート)のみをターゲットにします。そのため、プロキシの選択はこれらの値のみに基づいて行われる場合があります。カスタム プロキシ セレクタに渡される URL に、リクエストされた URL のパス、クエリ パラメータ、フラグメントは含まれません。
  • URI に空のラベルを含めることはできません。

    以前のプラットフォームでは、ホスト名に空のラベルを受け入れる回避策がサポートされていました。これは URI の不正な使用です。この回避策は、古い libcore リリースとの互換性を確保するためでした。誤ってこの API を使用しているデベロッパーには、「URI example..com has empty labels in the hostname. これは不正な形式であり、今後の Android リリースでは受け入れられません。」 Android 8.0 ではこの回避策が削除され、不正な形式の URI に対しては null が返されます。

  • Android 8.0 の HttpsURLConnection 実装では、安全でない TLS/SSL プロトコル バージョンのフォールバックは実行されません。
  • トンネリング HTTP(S) 接続の処理が次のように変更されました。
    • 接続で HTTPS 接続をトンネリングする場合、この情報を中間サーバーに送信する際に、ポート番号(:443)が Host 行に正しく配置されます。以前は、ポート番号は CONNECT 行でのみ発生していました。
    • システムは、トンネリング リクエストからプロキシ サーバーにユーザー エージェントとプロキシ認証ヘッダーを送信しなくなりました。

      トンネルの設定時に、トンネリングされた Http(s)URLConnection 上のプロキシ認証ヘッダーがプロキシに送信されなくなりました。代わりに、プロキシ認証ヘッダーが生成され、プロキシが最初のリクエストへのレスポンスとして HTTP 407 を送信したときに、そのヘッダーがプロキシに送信されます。

      同様に、システムは、トンネリング リクエストからトンネルを設定するプロキシ リクエストにユーザー エージェント ヘッダーをコピーしなくなります。代わりに、ライブラリはそのリクエストのユーザー エージェント ヘッダーを生成します。

  • 以前に実行された connect() メソッドが失敗した場合、send(java.net.DatagramPacket) メソッドは SocketException をスローします。
    • DatagramSocket.connect() は、内部エラーが発生した場合に PendingSocketException を設定します。Android 8.0 より前のバージョンでは、send() の呼び出しが成功していても、後続の recv() 呼び出しでは SocketException がスローされていました。一貫性を確保するため、両方の呼び出しで SocketException がスローされるようになりました。
  • InetAddress.isReachable() は、TCP Echo プロトコルにフォールバックする前に ICMP を試みます。
    • ポート 7(TCP Echo)をブロックする一部のホスト(google.com など)は、ICMP Echo プロトコルを受け入れると、到達可能になりました。
    • 真に到達不能なホストの場合、この変更により、呼び出しが戻るまでに費やされる時間が 2 倍になります。

Bluetooth

Android 8.0(API レベル 26)では、ScanRecord.getBytes() メソッドが取得するデータの長さに対して次の変更が行われています。

  • getBytes() メソッドは、受信するバイト数を推定しません。そのため、返されるバイト数の最小または最大に依存しないようにしてください。代わりに、結果の配列の長さを評価する必要があります。
  • Bluetooth 5 対応デバイスから、以前の最大 60 バイトを超えるデータ長が返されることがあります。
  • リモート デバイスがスキャン応答を提供しない場合も、60 バイト未満が返される場合があります。

シームレスな接続

Android 8.0(API レベル 26)では、Wi-Fi 設定にいくつかの改善が行われており、最適なユーザー エクスペリエンスを提供する Wi-Fi ネットワークを簡単に選択できるようになっています。具体的には、次のような変更が行われています。

  • 安定性と信頼性が向上しました。
  • より直感的に読みやすい UI。
  • Wi-Fi 設定メニューが 1 つに統合されている。
  • 互換性のあるデバイスで、高品質の保存済みネットワークが近くにある場合に Wi-Fi を自動的に有効にする。

セキュリティ

Android 8.0 では、セキュリティに関する次の変更が行われています。

  • このプラットフォームでは SSLv3 がサポートされなくなりました。
  • TLS プロトコル バージョンのネゴシエーションが正しく実装されていないサーバーへの HTTPS 接続を確立する場合、HttpsURLConnection は以前の TLS プロトコル バージョンにフォールバックして再試行するという回避策を試みなくなりました。
  • Android 8.0(API レベル 26)では、すべてのアプリにセキュア コンピューティング(SECCOMP)フィルタを適用します。許可されるシステムコールのリストは、bionic を通じて公開されるシステムコールに限定されます。下位互換性を確保するために提供されているシステムコールが他にもいくつかありますが、使用することはおすすめしません。
  • アプリの WebView オブジェクトがマルチプロセス モードで実行されるようになりました。ウェブ コンテンツは、セキュリティ強化のため、ウェブ コンテンツを含むアプリのプロセスとは別の分離されたプロセスで処理されます。
  • APK が、名前が -1 または -2 で終わるディレクトリに存在すると想定できなくなりました。アプリは、ディレクトリ形式に直接依存するのではなく、sourceDir を使用してディレクトリを取得する必要があります。
  • ネイティブ ライブラリの使用に関連するセキュリティ機能の強化については、ネイティブ ライブラリをご覧ください。

さらに、Android 8.0(API レベル 26)では、提供元不明のアプリのインストールに関して以下の変更が行われています。

  • 従来の設定 INSTALL_NON_MARKET_APPS の値は常に 1 になりました。パッケージ インストーラを使用して不明な提供元がアプリをインストールできるかどうかを判断するには、代わりに canRequestPackageInstalls() の戻り値を使用する必要があります。
  • setSecureSetting() を使用して INSTALL_NON_MARKET_APPS の値を変更しようとすると、UnsupportedOperationException がスローされます。ユーザーが提供元不明のアプリをインストールできないようにするには、ユーザー制限として DISALLOW_INSTALL_UNKNOWN_SOURCES を適用する必要があります。
  • Android 8.0(API レベル 26)を搭載したデバイスで作成された管理対象プロファイルでは、DISALLOW_INSTALL_UNKNOWN_SOURCES ユーザー制限が自動的に有効になります。Android 8.0 にアップグレードされたデバイス上の既存の管理対象プロファイルの場合、プロファイルの所有者が(アップグレード前に)INSTALL_NON_MARKET_APPS を 1 に設定してこの制限を明示的に無効にしない限り、DISALLOW_INSTALL_UNKNOWN_SOURCES ユーザー制限が自動的に有効になります。

不明なアプリのインストールについて詳しくは、不明なアプリのインストール権限に関するガイドをご覧ください。

アプリのセキュリティを強化するためのその他のガイドラインについては、Android デベロッパー向けのセキュリティをご覧ください。

プライバシー

Android 8.0(API レベル 26)では、プラットフォームに対して次のようなプライバシー関連の変更が行われています。

  • 現在は、ID の処理方法が異なります。
    • Android 8.0(API レベル 26)(API レベル 26)への OTA の前にインストールされたアプリの場合、ANDROID_ID の値は、アンインストールして OTA 後に再インストールしない限り変わりません。OTA 後のアンインストール後も値を保持するには、 Key-Value バックアップを使用して、古い値と新しい値を関連付けることができます。
    • Android 8.0 を搭載しているデバイスにインストールされているアプリの場合、ANDROID_ID の値が、ユーザーごととアプリ署名鍵ごとにスコープされるようになりました。ANDROID_ID の値は、アプリ署名鍵、ユーザー、デバイスの各組み合わせで一意です。 その結果、同じデバイスで実行されている異なる署名鍵を持つアプリには、(同じユーザーであっても)同じ Android ID が表示されなくなります。
    • 署名鍵が同じである(Android 8.0 バージョンへの OTA の前にアプリがインストールされていない)限り、パッケージのアンインストールまたは再インストールによって ANDROID_ID の値は変更されません。
    • システム アップデートによってパッケージ署名鍵が変更されても、ANDROID_ID の値は変わりません。
    • Google Play 開発者サービスと広告 ID が搭載されたデバイスでは、 広告 ID を使用する必要があります。アプリを収益化するためのシンプルな標準システムである広告 ID は、ユーザーがリセットできる広告用の一意の ID です。これは Google Play 開発者サービスから提供されます。

      他のデバイス メーカーは、引き続き ANDROID_ID を提供する必要があります。

  • net.hostname システム プロパティのクエリを実行すると、null の結果が生成されます。

キャッチされなかった例外のロギング

デフォルトの Thread.UncaughtExceptionHandler を呼び出しない Thread.UncaughtExceptionHandler をアプリがインストールした場合、キャッチされない例外が発生しても、システムはアプリを強制終了しません。Android 8.0(API レベル 26)以降では、この状況で例外スタックトレースがログに記録されます。これより前のバージョンのプラットフォームでは、例外スタックトレースはログに記録されていませんでした。

カスタム Thread.UncaughtExceptionHandler の実装では、常にデフォルト ハンドラを呼び出すことをおすすめします。この推奨事項に従うアプリは、Android 8.0 での変更の影響を受けません。

findViewById() 署名の変更

findViewById() メソッドのすべてのインスタンスが、View ではなく <T extends View> T を返すようになりました。この変更による影響は次のとおりです。

  • これにより、既存のコードの戻り値の型が不明瞭になる可能性があります。たとえば、findViewById() の呼び出し結果を受け取る someMethod(View)someMethod(TextView) の両方がある場合などです。
  • Java 8 ソース言語を使用する場合、戻り値の型に制約がない場合(例: assertNotNull(findViewById(...)).someViewMethod()))は、View への明示的なキャストが必要です。
  • 非 final の findViewById() メソッドをオーバーライドする(Activity.findViewById() など)場合、戻り値の型を更新する必要があります。

連絡先プロバイダの使用統計情報の変更

以前のバージョンの Android では、デベロッパーは連絡先プロバイダ コンポーネントを使用して各連絡先の使用状況データを取得できます。この使用状況データにより、連絡先に関連付けられた各メールアドレスと各電話番号の情報(連絡先への連絡回数や最終連絡先など)が公開されます。READ_CONTACTS 権限をリクエストするアプリは、このデータを読み取ることができます。

アプリが READ_CONTACTS 権限をリクエストすれば、引き続きこのデータを読み取ることができます。Android 8.0(API レベル 26)以降では、使用状況データのクエリを実行すると、正確な値ではなく概算値が返されます。正確な値は Android システムが内部で保持するため、この変更はオートコンプリート API には影響しません。

この動作変更は、次のクエリ パラメータに影響します。

コレクションの処理

AbstractCollection.removeAll()AbstractCollection.retainAll() が常に NullPointerException をスローするようになりました。以前は、コレクションが空の場合に NullPointerException はスローされませんでした。この変更により、動作がドキュメントと整合するようになります。

Android Enterprise

Android 8.0(API レベル 26)では、Device Policy Controller(DPC)など、エンタープライズ アプリ向けの一部の API と機能の動作が変更されています。変更内容は次のとおりです。

  • 完全管理対象デバイスでアプリが仕事用プロファイルをサポートできるようにするための新しい動作。
  • デバイスとシステムの整合性を高めるため、システム アップデートの処理、アプリの確認、認証に関する変更を行います。
  • プロビジョニング、通知、履歴画面、常時接続 VPN のユーザー エクスペリエンスが改善されました。

Android 8.0(API レベル 26)におけるエンタープライズ向けのすべての変更と、それがアプリに与える影響を確認するには、 エンタープライズにおける Android をご覧ください。

Android 8.0 をターゲットとするアプリ

これらの動作変更は、Android 8.0(API レベル 26)以降をターゲットとするアプリにのみ適用されます。Android 8.0 でコンパイルするアプリ、または targetSdkVersion を Android 8.0 以上に設定するアプリは、必要に応じて、これらの動作を適切にサポートするようにアプリを変更する必要があります。

アラート期間

SYSTEM_ALERT_WINDOW 権限を使用するアプリは、以下のウィンドウ タイプを使用して他のアプリやシステム ウィンドウの上にアラート ウィンドウを表示できなくなりました。

代わりに、TYPE_APPLICATION_OVERLAY という新しいウィンドウ タイプを使用する必要があります。

TYPE_APPLICATION_OVERLAY ウィンドウ タイプを使用してアプリのアラート ウィンドウを表示する場合は、新しいウィンドウ タイプの次の特性に留意してください。

  • アプリのアラート ウィンドウは、ステータスバーや IME などの重要なシステム ウィンドウに常に表示されます。
  • 画面の表示を改善するために、TYPE_APPLICATION_OVERLAY ウィンドウ タイプを使用するウィンドウの移動やサイズ変更は、システムによって行われます。
  • ユーザーは通知シェードを開くことで、TYPE_APPLICATION_OVERLAY ウィンドウ タイプを使用して表示されるアラート ウィンドウをアプリが表示しないようにする設定にアクセスできます。

コンテンツの変更に関する通知

Android 8.0(API レベル 26)では、Android 8.0 をターゲットとするアプリに対する ContentResolver.notifyChange()registerContentObserver(Uri, boolean, ContentObserver) の動作が変更されています。

これらの API では、すべての URI のオーソリティに有効な ContentProvider を定義することが必要になりました。関連する権限を使用して有効な ContentProvider を定義すると、悪意のあるアプリからのコンテンツ変更からアプリを保護し、非公開のデータが悪意のあるアプリに漏洩することを防ぐことができます。

View のフォーカス

クリック可能な View オブジェクトもデフォルトでフォーカス可能になりました。View オブジェクトをクリック可能にし、フォーカスできないようにするには、View を含むレイアウト XML ファイルで android:focusable 属性を false に設定するか、アプリの UI ロジックで falsesetFocusable() に渡します。

ブラウザ検出におけるユーザー エージェント マッチング

Android 8.0(API レベル 26)以降には、ビルド ID の文字列 OPR が含まれています。一部のパターン一致では、ブラウザ検出ロジックによって Opera 以外のブラウザが Opera と誤って認識されることがあります。 このようなパターン一致の例を次に示します。

if(p.match(/OPR/)){k="Opera";c=p.match(/OPR\/(\d+.\d+)/);n=new Ext.Version(c[1])}

このような誤認識に起因する問題を回避するには、Opera ブラウザのパターン マッチングに OPR 以外の文字列を使用します。

セキュリティ

Android 8.0(API レベル 26)のセキュリティに影響する変更は次のとおりです。

  • アプリのネットワーク セキュリティ設定でクリアテキスト トラフィックのサポートをオプトアウトしている場合、アプリの WebView オブジェクトは HTTP 経由でウェブサイトにアクセスできません。各 WebView オブジェクトでは、代わりに HTTPS を使用する必要があります。
  • [提供元不明のアプリを許可する] システム設定が削除されました。代わりに [不明なアプリのインストール] 権限を使用して、提供元不明のアプリ インストールを管理します。この新しい権限の詳細については、不明なアプリのインストール権限のガイドをご覧ください。

アプリのセキュリティを強化するためのその他のガイドラインについては、Android デベロッパー向けのセキュリティをご覧ください。

アカウントへのアクセスと見つけやすさ

Android 8.0(API レベル 26)では、認証システムがアカウントを所有しているか、ユーザーがそのアクセスを許可しない限り、アプリはユーザー アカウントにアクセスできません。GET_ACCOUNTS 権限では不十分になりました。アカウントへのアクセス権が付与されるには、AccountManager.newChooseAccountIntent() または認証システム固有のメソッドを使用する必要があります。アカウントへのアクセス権を取得した後、アプリは AccountManager.getAccounts() を呼び出してアカウントにアクセスできます。

Android 8.0 では LOGIN_ACCOUNTS_CHANGED_ACTION のサポートが終了しました。実行時にアカウントに関する最新情報を取得するには、代わりに addOnAccountsUpdatedListener() を使用する必要があります。

アカウント アクセスと検出可能性のために追加された新しい API とメソッドについては、このドキュメントの新しい API セクションのアカウントのアクセスと検出可能性をご覧ください。

プライバシー

Android 8.0(API レベル 26)のプライバシーに影響する変更点は次のとおりです。

  • システム プロパティの net.dns1net.dns2net.dns3net.dns4 は使用できなくなりました。これは、プラットフォームのプライバシーを向上させる変更です。
  • ACCESS_NETWORK_STATE 権限を持つアプリは、DNS サーバーなどのネットワーク情報を取得するために、NetworkRequest または NetworkCallback オブジェクトを登録できます。これらのクラスは Android 5.0(API レベル 21)以降で使用できます。
  • Build.SERIAL が非推奨になりました。 ハードウェアのシリアル番号を知る必要があるアプリは、代わりに新しい Build.getSerial() メソッドを使用してください。このメソッドには READ_PHONE_STATE 権限が必要です。
  • LauncherApps API では、仕事用プロファイルのアプリがプライマリ プロファイルに関する情報を取得できなくなりました。ユーザーが仕事用プロファイルに登録されている場合、LauncherApps API は、同じプロファイル グループ内の他のプロファイルにアプリがインストールされていないかのように動作します。前述のように、無関係なプロファイルにアクセスしようとすると、SecurityException が発生します。

権限

Android 8.0(API レベル 26)より前では、アプリが実行時に権限をリクエストして権限が付与されている場合、同じ権限グループに属し、マニフェストに登録されている残りの権限も、誤ってアプリに付与されます。

Android 8.0 をターゲットとするアプリでは、この動作は修正されています。アプリには、明示的にリクエストした権限のみが付与されます。ただし、ユーザーがアプリに権限を付与すると、その権限グループ内の権限に対する後続のリクエストはすべて自動的に許可されます。

たとえば、あるアプリのマニフェストに READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE の両方が含まれているとします。 アプリが READ_EXTERNAL_STORAGE をリクエストし、ユーザーがそれを許可します。API レベル 25 以前をターゲットとしているアプリの場合、WRITE_EXTERNAL_STORAGE も同時に付与されます。これは、このアプリが同じ STORAGE 権限グループに属しており、マニフェストにも登録されているためです。Android 8.0(API レベル 26)をターゲットとするアプリの場合、システムはその時点で READ_EXTERNAL_STORAGE のみを付与します。ただし、アプリが後で WRITE_EXTERNAL_STORAGE をリクエストすると、ユーザーにプロンプトが表示されることなく、その権限が直ちに付与されます。

Media

  • フレームワークだけで自動オーディオ ダッキングを実行できます。この場合、別のアプリが AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK でフォーカスをリクエストした場合、フォーカスされているアプリは音量を下げますが、通常は onAudioFocusChange() コールバックを受信せず、音声フォーカスが失われることはありません。ダッキングではなく一時停止を必要とするアプリでこの動作をオーバーライドする新しい API を利用できます。
  • ユーザーが電話に出ると、アクティブなメディア ストリームは通話中の間ミュートされます。
  • すべての音声関連 API では、音声ストリーム タイプではなく AudioAttributes を使用して、音声再生のユースケースを記述する必要があります。引き続き、音量調節にのみ音声ストリーム タイプを使用します。ストリーム タイプの他の使用方法(非推奨の AudioTrack コンストラクタの streamType 引数など)は引き続き機能しますが、これはエラーとしてログに記録されます。
  • AudioTrack を使用している場合、アプリが十分なサイズのオーディオ バッファをリクエストすると、フレームワークはディープ バッファ出力を利用できる場合にそのバッファ出力の使用を試みます。
  • Android 8.0(API レベル 26)では、メディアボタン イベントの処理が次のように異なります。
    1. UI アクティビティでのメディアボタンの処理は変更されていません。メディアボタン イベントの処理では、引き続きフォアグラウンド アクティビティが優先されます。
    2. フォアグラウンド アクティビティがメディアボタン イベントを処理しない場合、システムは最後にローカルで音声を再生したアプリにイベントをルーティングします。どのアプリがメディアボタン イベントを受け取るかを決定する際には、メディア セッションのアクティブ ステータス、フラグ、再生状態は考慮されません。
    3. アプリのメディア セッションが解放されると、アプリの MediaButtonReceiver にメディアボタン イベントが送信されます(アプリに存在する場合)。
    4. それ以外の場合は、メディアボタン イベントは破棄されます。

ネイティブ ライブラリ

Android 8.0(API レベル 26)をターゲットとするアプリでは、書き込み可能かつ実行可能の両方のロード セグメントがネイティブ ライブラリに含まれていると、ネイティブ ライブラリの読み込みが行われなくなりました。一部のアプリで、ネイティブ ライブラリに誤った読み込みセグメントがある場合、この変更により動作を停止する可能性があります。これはセキュリティ強化策です。

詳細については、 書き込み可能かつ実行可能なセグメントをご覧ください。

リンカーの変更は、アプリがターゲットとする API レベルに関連付けられています。対象 API レベルでリンカーの変更があった場合、アプリはライブラリを読み込むことができません。リンカーの変更が発生する API レベルよりも低い API レベルを対象としている場合、logcat に警告が表示されます。

コレクションの処理

Android 8.0(API レベル 26)では、Collections.sort()List.sort() の上に実装されています。これとは逆に、Android 7.x(API レベル 24、25)では List.sort() のデフォルト実装である Collections.sort() でした。

この変更により、Collections.sort() で最適化された List.sort() の実装を使用できるようになりますが、次の制約があります。

  • List.sort() の実装で Collections.sort() を呼び出さないでください。呼び出すと、無限再帰によってスタック オーバーフローが発生する可能性があります。List の実装でデフォルトの動作を使用する場合は、sort() をオーバーライドしないでください。

    親クラスが sort() を適切に実装していない場合、通常は List.toArray()Arrays.sort()ListIterator.set() の上に構築された実装で List.sort() をオーバーライドしても問題ありません。次に例を示します。

    @Override
    public void sort(Comparator<? super E> c) {
      Object[] elements = toArray();
      Arrays.sort(elements, c);
      ListIterator<E> iterator = (ListIterator<Object>) listIterator();
      for (Object element : elements) {
        iterator.next();
        iterator.set((E) element);
      }
    }
    

    ほとんどの場合、API レベルに応じて異なるデフォルト実装に委任する実装で List.sort() をオーバーライドすることもできます。次に例を示します。

    @Override
    public void sort(Comparator<? super E> comparator) {
      if (Build.VERSION.SDK_INT <= 25) {
        Collections.sort(this);
      } else {
        super.sort(comparator);
      }
    }
    

    すべての API レベルで sort() メソッドを使用できるようにするために後者のみを行う場合は、sort() をオーバーライドするのではなく、sortCompat() などの一意の名前を付けることを検討してください。

  • Collections.sort() は、sort() を呼び出すリスト実装では構造変更としてカウントされるようになりました。たとえば、Android 8.0(API レベル 26)より前のバージョンのプラットフォームでは、ArrayList を反復処理し、途中で sort() を呼び出すと、List.sort() を呼び出して並べ替えを行うと ConcurrentModificationException がスローされていました。Collections.sort() が例外をスローしませんでした。

    この変更により、プラットフォームの動作の一貫性が向上しました。どちらの方法でも ConcurrentModificationException が返されるようになりました。

クラス読み込みの動作

Android 8.0(API レベル 26)では、新しいクラスを読み込む際に、クラスローダがランタイムの想定を損なわないことを確認します。このチェックは、クラスが Java(forName() から)、Dalvik バイトコード、JNI から参照されているかどうかで実行されます。プラットフォームは、Java から loadClass() メソッドの直接呼び出しをインターセプトせず、そのような呼び出しの結果もチェックしません。この動作は、正常なクラスローダーの機能には影響しません。

プラットフォームは、クラスローダーが返すクラスの記述子が、想定される記述子と一致することを確認します。返された記述子が一致しない場合、プラットフォームは NoClassDefFoundError エラーをスローし、不一致を示す詳細なメッセージを例外に格納します。

プラットフォームでは、要求されたクラスの記述子が有効かどうかもチェックされます。このチェックは、GetFieldID() などのクラスを間接的に読み込み、無効な記述子をそれらのクラスに渡す JNI 呼び出しをキャッチします。たとえば、シグネチャ java/lang/String を持つフィールドは、シグネチャが無効であるため見つかりません。これは Ljava/lang/String; である必要があります。

これは、java/lang/String が有効な完全修飾名である FindClass() への JNI 呼び出しとは異なります。

Android 8.0(API レベル 26)では、複数のクラスローダーが同じ DexFile オブジェクトを使用してクラスを定義することはできません。そのように設定すると、Android ランタイムは「Attempt to register dex file <filename> with multiple class loaders」というメッセージとともに InternalError エラーをスローします。

DexFile API は非推奨になりました。PathClassLoaderBaseDexClassLoader などのプラットフォーム クラスローダーを代わりに使用することを強くおすすめします。

注: ファイル システムの同じ APK または JAR ファイル コンテナを参照する複数のクラスローダーを作成できます。通常、コンテナ内の DEX ファイルが圧縮されずに保存されている場合、プラットフォームは DEX ファイルを直接抽出するのではなく、mmap オペレーションを実行できます。ただし、プラットフォームでコンテナから DEX ファイルを抽出する必要がある場合、この方法で DEX ファイルを参照すると、大量のメモリが消費される可能性があります。

Android では、すべてのクラスローダーが並列対応とみなされます。複数のスレッドが同じクラスローダーで同じクラスを読み込むために競合した場合、オペレーションを最初に完了したスレッドが優先し、その結果が他のスレッドに使用されます。この動作は、クラスローダーが同じクラスを返したかどうか、別のクラスを返したかどうか、例外をスローしたかどうかに関係なく発生します。プラットフォームはそのような例外を暗黙的に無視します。

注意: Android 8.0(API レベル 26)より前のバージョンのプラットフォームでは、上記の想定を破ると、同じクラスが複数回定義されたり、クラスの混乱によるヒープの破損などの望ましくない影響が発生する可能性があります。