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 つとして、アプリがアクティブなコンポーネントのないキャッシュに保存された状態になると、そのアプリが保持しているすべての WakeLock が解放されます。

また、端末のパフォーマンスを改善するために、フォアグラウンドで実行されていないアプリの特定の動作はシステムによって制限されます。詳細は以下のとおりです。

  • バックグラウンドで実行されているアプリがバックグラウンド サービスにアクセスできる頻度と時間に制限が設定されました。
  • アプリはマニフェストを使用して、ほとんどの暗黙的ブロードキャスト(つまり、特定のアプリを対象としていないブロードキャスト)を登録できません。

デフォルトでは、これらの制限は O を対象とするアプリにのみ適用されます。アプリが O を対象としていない場合でも、ユーザーは [Settings] 画面でアプリに対してこれらの制限を有効にすることができます。

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 Measurements
  • Location Manager
  • Wi-Fi Manager

アプリが想定どおりに動作していることを確認するには、次の手順を実行します。

  • アプリのロジックをレビューし、最新の Location API を使用していることを確認します。
  • 各ユースケースに対して想定している動作がアプリで発生しているかをテストします。
  • ユーザーの現在地情報に応じたユースケースを処理するため、Fused Location Provider(FLP)または Geofencing を使用することをご検討ください。

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

アプリのショートカット

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 引数に指定された displayScript 値が利用できない場合、Locale.getDisplayScript(Locale)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 の自動入力フレームワークが、自動入力機能へのサポートを内蔵するようになったことを受け、WebView オブジェクトに関連する次のメソッドが変更されました。この変更は、Android 8.0(API レベル 26)を実行する端末にインストールされたアプリを対象としています。

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 を適切に使用していないと、次のような ADB メッセージが表示されます。「URI example..com has empty labels in the hostname. This is malformed and will not be accepted in future Android releases." Android 8.0 ではこの回避策が廃止されているため、不正な形式の URI に対しては null が返されます。

  • Android 8.0 の HttpsURLConnection 実装では、安全でない TLS/SSL プロトコル バージョンのフォールバックは行われません。
  • HTTP(S) 接続をトンネリングする処理は次のように変更されました。
    • システムではネットワーク上に HTTP(S) のトンネリング接続を確立するために、ポート番号(: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 を試みます。
    • google.com など、ポート 7(TCP Echo)をブロックする一部のホストは、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 設定メニュー。
  • 互換性のあるデバイスでは、高品質のネットワークとして保存されたネットワークが近くにある場合、自動的に Wi-Fi がアクティベートされます。

セキュリティ

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

  • このプラットフォームでは SSLv3 がサポートされなくなりました。
  • TLS プロトコル バージョンのネゴシエーションを適切に実装していないサーバーへの HTTPS 接続を確立する際に、HttpsURLConnection では古い TLS プロトコル バージョンにフォールバックしてリトライするという回避策を試みなくなります。
  • Android 8.0(API レベル 26)では、すべてのアプリに Secure Computing(SECCOMP)フィルタが適用されます。許可されたシステムコールのリストは、Bionic を通じて公開されたものに制限されます。他にも下位互換性を確保するために提供されているシステムコールがいくつかありますが、それらの使用は控えることをお勧めします。
  • アプリの WebView オブジェクトはマルチプロセス モードで実行されます。セキュリティを強化するために、ウェブ コンテンツは、そのコンテンツを含むアプリのプロセスとは別の独立したプロセスとして処理されます。
  • -1 や -2 などで終わる名前のディレクトリ内に APK があると想定することはできなくなりました。アプリでは 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)プラットフォームにおけるプライバシー関連の変更点は次のとおりです。

  • プラットフォームにおける識別子の処理方法が異なります。
    • 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 では、Contacts Provider コンポーネントによって各連絡先の利用統計を取得することが可能でした。この利用統計データには、連絡先に関連付けられた各メールアドレスや電話番号、その連絡先に連絡した回数、最後に連絡した日時などの情報が含まれます。READ_CONTACTS 権限をリクエストするアプリは、このデータを読み取ることができます。

アプリは、READ_CONTACTS 権限をリクエストすることで、引き続きこのデータを読み取ることができます。Android 8.0(API レベル 26)以降では、利用統計データをクエリすると、正確な値ではなく概算値が返されます。Android システム側では正確な値を内部的に保持しているため、この変更によってオートコンプリートの API に影響が生じることはありません。

この動作変更の影響を受けるクエリ パラメータは次のとおりです。

コレクションの処理

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

Android Enterprise

Android 8.0(API レベル 26)では、デバイス ポリシー コントローラ(DPC)などのエンタープライズ アプリに関して、複数の API と機能の動作を変更しています。変更点は次のとおりです。

  • 新しい動作によって、完全管理対象端末で、アプリが仕事用プロファイルに対応できるようにします。
  • システムアップデートの処理、アプリの検証と認証を変更し、端末とシステムの整合性を高めます。
  • プロビジョニング、通知、[最近] 画面、always-on 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)以降には、ビルド識別子文字列 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() を呼び出してそのアカウントにアクセスできるようになります。

LOGIN_ACCOUNTS_CHANGED_ACTION のサポートは Android 8.0 で終了しました。実行時にアカウントの更新情報を取得するには、代わりにアプリで addOnAccountsUpdatedListener() を使用してください。

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

プライバシー

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

  • プライバシー強化のため、このプラットフォームではシステム プロパティの net.dns1net.dns2net.dns3net.dns4 は利用できません。
  • DNS サーバーなどのネットワーク情報を取得するには、ACCESS_NETWORK_STATE 権限を持つアプリで 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 をリクエストした場合は、ユーザーにプロンプトを表示せずに、ただちにその権限を付与します。

メディア

  • フレームワークは、自動オーディオ ダッキングを独自に実行できます。この場合、別のアプリが 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 レベルよりも低いレベルを対象としている場合は、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() を呼び出す List 実装の構造変更と見なされるようになりました。たとえば、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; である必要があります。

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

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

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

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

Android では、すべてのクラスローダが並行処理可能と見なされます。複数のスレッドがクラスローダが同じである同じクラスを読み込む場合、最初のスレッドが最初に操作を完了し、その結果が他のスレッドに使用されます。この動作は、クラスローダが同じクラスを戻すか、別のクラスを戻すか、例外をスローするかどうかに関係なく発生します。プラットフォームは、このような例外を通知なく無視します。

注意: Android 8.0(API レベル 26)より前のプラットフォームのバージョンでは、これらの仮定に従っていない場合、同じクラスの複数回定義、クラスの混乱や他の望ましくない状況によるヒープ破壊につながる可能性があります。