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)では、特定のメソッドが次のように変更されています。
startService()
メソッドは、バックグラウンド サービスの作成が許可されていない状況で Android 8.0 をターゲットとするアプリが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
引数に指定された 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 ロジックでfalse
をsetDefaultFocusHighlightEnabled()
に渡します。 - キーボード入力が 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.com
をhttp://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。
- 1 つに統合された Wi-Fi 設定メニュー。
- 互換性のあるデバイスで、高品質の保存済みネットワークが近くにある場合に Wi-Fi が自動的に有効になります。
セキュリティ
Android 8.0 では、セキュリティ関連の次の変更が行われています。
- このプラットフォームでは SSLv3 がサポートされなくなりました。
- TLS プロトコル バージョンのネゴシエーションが正しく実装されていないサーバーと HTTPS 接続を確立する場合、
HttpsURLConnection
は以前の TLS プロトコル バージョンにフォールバックして再試行するという回避策を試みなくなりました。 - Android 8.0(API レベル 26)では、すべてのアプリに Secure Computing(SECCOMP)フィルタが適用されます。許可される syscall のリストは、bionic を介して公開されるものに制限されます。下位互換性を確保するために提供されている syscall は他にもいくつかありますが、その使用はおすすめしません。
- アプリの
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
を提供する必要があります。
-
Android 8.0(API レベル 26)(API レベル 26)のバージョンへの OTA より前にインストールされたアプリの場合、
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
に明示的にキャストする必要があります。 - 非最終
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 ロジックで false
を setFocusable()
に渡します。
ブラウザ検出におけるユーザー エージェントのマッチング
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.dns1
、net.dns2
、net.dns3
、net.dns4
は使用できなくなりました。これにより、プラットフォームのプライバシーが向上します。 -
DNS サーバーなどのネットワーク情報を取得するために、
ACCESS_NETWORK_STATE
権限を持つアプリは、NetworkRequest
オブジェクトまたはNetworkCallback
オブジェクトを登録できます。これらのクラスは Android 5.0(API レベル 21)以降で使用できます。 -
Build.SERIAL が非推奨になりました。
ハードウェア シリアル番号を知る必要があるアプリは、代わりに
READ_PHONE_STATE
権限を必要とする新しいBuild.getSerial()
メソッドを使用する必要があります。 -
LauncherApps
API では、仕事用プロファイルのアプリがプライマリ プロファイルに関する情報を取得できなくなりました。ユーザーが仕事用プロファイルに登録されている場合、LauncherApps
API は、同じプロファイル グループ内の他のプロファイルにアプリがインストールされていないかのように動作します。前と同様に、無関係なプロファイルにアクセスしようとすると SecurityException が発生します。
権限
Android 8.0(API レベル 26)より前では、アプリが実行時に権限をリクエストしてその権限が付与された場合、同じ権限グループに属し、マニフェストに登録されている残りの権限も、システムがアプリに誤って付与していました。
Android 8.0 をターゲットとするアプリでは、この動作は修正されています。アプリには、明示的にリクエストした権限のみが付与されます。ただし、ユーザーがアプリに権限を付与すると、その権限グループ内の権限に対する後続のリクエストはすべて自動的に許可されます。
たとえば、アプリのマニフェストに READ_EXTERNAL_STORAGE
と WRITE_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)では、メディアボタン イベントの処理が異なります。
- UI アクティビティでのメディアボタンの処理に変更はありません。メディアボタン イベントの処理では引き続きフォアグラウンド アクティビティが優先されます。
- フォアグラウンド アクティビティがメディアボタン イベントを処理しない場合、システムは最後にローカルで音声を再生したアプリにイベントをルーティングします。メディアボタン イベントを受け取るアプリを決定する際は、メディア セッションのアクティブ ステータス、フラグ、再生状態は考慮されません。
- アプリのメディア セッションが解放されると、アプリの
MediaButtonReceiver
にメディアボタン イベントが送信されます(存在する場合)。 - それ以外の場合は、メディアボタン イベントは破棄されます。
ネイティブ ライブラリ
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()
と呼ばれていました。
この変更により、最適化された List.sort()
実装を Collections.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 ランタイムが InternalError
エラーをスローし、「Attempt to register dex file <filename>
withmultiple class loaders」というメッセージを表示します。
DexFile API は非推奨になりました。代わりに、PathClassLoader
や BaseDexClassLoader
など、いずれかのプラットフォーム クラスローダーを使用することを強くおすすめします。
注: ファイル システムの同じ APK または JAR ファイル コンテナを参照する複数のクラスローダーを作成できます。コンテナ内の DEX ファイルを圧縮せずに保存した場合、プラットフォームはファイルを直接抽出するのではなく、mmap
オペレーションを実行できます。ただし、プラットフォームでコンテナから DEX ファイルを抽出する必要がある場合、この方法で DEX ファイルを参照すると、大量のメモリが消費される可能性があります。
Android では、すべてのクラスローダーが並列対応とみなされます。複数のスレッドが同じクラスローダーを使用して同じクラスを読み込む競合が発生した場合、最初にオペレーションを完了したスレッドが優先し、結果が他のスレッドに使用されます。この動作は、クラスローダーが同じクラスを返したのか、別のクラスを返したのか、または例外をスローしたのかにかかわらず発生します。プラットフォームはこのような例外を通知なく無視します。
注意: Android 8.0(API レベル 26)より前のバージョンのプラットフォームでは、この前提を破ると、同じクラスが複数回定義される、クラス混乱によるヒープの破損など、望ましくない影響が生じる可能性があります。