Android 9(API レベル 28)では、Android システムにさまざまな変更が加えられています。下記の動作変更は、ターゲットとする API レベルに関係なく、Android 9 プラットフォーム上で稼働するすべてのアプリに適用されます。すべてのデベロッパーは、これらの変更を確認し、アプリに該当する場合は、適切に対応するようにアプリを変更する必要があります。
API レベル 28 以降をターゲットとするアプリにのみ影響する変更については、動作の変更点: API レベル 28 以降をターゲットとするアプリをご覧ください。
電源管理
Android 9 では、デバイスの電源管理を改善する新機能が導入されています。これらの変更と、Android 9 より前にすでに存在していた機能により、システム リソースを最も必要とするアプリに確実に提供できるようになります。
詳しくは、電源管理をご覧ください。
プライバシーの変更点
ユーザーのプライバシーを強化するため、Android 9 では、バックグラウンド アプリによるデバイスのセンサーへのアクセスの制限、Wi-Fi スキャンから取得される情報の制限、通話、スマートフォンの状態、Wi-Fi スキャンに関連する新しい権限ルールと権限グループなど、いくつかの動作が変更されています。
これらの変更は、ターゲット SDK のバージョンに関係なく、Android 9 で実行されるすべてのアプリに影響します。
バックグラウンドでのセンサーへのアクセス制限
Android 9 では、バックグラウンド アプリがユーザー入力とセンサーデータにアクセスする機能が制限されています。Android 9 を搭載したデバイスでアプリがバックグラウンドで実行されている場合、アプリには次の制限が適用されます。
- アプリがマイクまたはカメラにアクセスできない。
- 連続レポートモードを使用するセンサー(加速度計やジャイロスコープなど)では、イベントが受信されません。
- 変化時報告モードやワンショット報告モードを使用するセンサーでは、イベントが受信されません。
Android 9 を搭載したデバイスでアプリがセンサー イベントを検出する必要がある場合は、フォアグラウンド サービスを使用します。
通話履歴へのアクセスを制限
Android 9 では、CALL_LOG
権限グループが導入され、READ_CALL_LOG
、WRITE_CALL_LOG
、PROCESS_OUTGOING_CALLS
権限がこのグループに移動されました。以前のバージョンの Android では、これらの権限は PHONE
権限グループにありました。
この CALL_LOG
権限グループにより、通話履歴の読み取りや電話番号の特定など、通話に関する機密情報へのアクセスが必要なアプリをユーザーがより細かく管理し、可視化できるようになります。
アプリで通話履歴へのアクセスが必要な場合や、発信を処理する必要がある場合は、CALL_LOG
権限グループからこれらの権限を明示的にリクエストする必要があります。それ以外の場合は、SecurityException
が発生します。
注: これらの権限はグループが変更され、実行時に付与されるため、ユーザーがアプリによる通話履歴情報へのアクセスを拒否できます。この場合、アプリは情報にアクセスできないことを適切に処理できる必要があります。
アプリがすでにランタイム権限のベスト プラクティスに準拠している場合は、権限グループの変更を処理できます。
電話番号へのアクセス制限
Android 9 で実行されているアプリは、アプリのユースケースで必要な他の権限に加えて、まず READ_CALL_LOG
権限を取得しない限り、電話番号やスマートフォンの状態を読み取ることができません。
着信や発信などの通話に関連付けられた電話番号は、電話の状態ブロードキャストに表示され、PhoneStateListener
クラスからアクセスできます。ただし、READ_CALL_LOG
権限がないと、PHONE_STATE_CHANGED
ブロードキャストおよび PhoneStateListener
で指定された電話番号フィールドは空になります。
スマートフォンの状態から電話番号を読み取るには、ユースケースに基づいて必要な権限をリクエストするようにアプリを更新します。
PHONE_STATE
インテント アクションから数値を読み取るには、READ_CALL_LOG
権限とREAD_PHONE_STATE
権限の両方が必要です。onCallStateChanged()
から数値を読み取るには、READ_CALL_LOG
権限のみが必要です。READ_PHONE_STATE
権限は必要ありません。
Wi-Fi の位置情報と接続情報へのアクセスが制限される
Android 9 では、アプリが Wi-Fi スキャンを実行するための権限要件が以前のバージョンよりも厳格になっています。詳しくは、Wi-Fi スキャンの制限事項をご覧ください。
同様の制限が getConnectionInfo()
メソッドにも適用されます。このメソッドは、現在の Wi-Fi 接続を記述する WifiInfo
オブジェクトを返します。このオブジェクトのメソッドを使用して SSID と BSSID の値を取得できるのは、呼び出し元のアプリに次の権限がある場合のみです。
- ACCESS_FINE_LOCATION または ACCESS_COARSE_LOCATION
- ACCESS_WIFI_STATE
SSID または BSSID を取得するには、デバイスで位置情報サービスを有効にする必要があります([設定] > [位置情報])。
Wi-Fi サービス メソッドから削除された情報
Android 9 では、次のイベントとブロードキャストはユーザーの位置情報や個人を特定できるデータを受信しません。
WifiManager
のgetScanResults()
メソッドとgetConnectionInfo()
メソッド。WifiP2pManager
のdiscoverServices()
メソッドとaddServiceRequest()
メソッド。NETWORK_STATE_CHANGED_ACTION
ブロードキャスト。
Wi-Fi からの NETWORK_STATE_CHANGED_ACTION
システム ブロードキャストには、SSID(旧 EXTRA_SSID)、BSSID(旧 EXTRA_BSSID)、接続情報(旧 EXTRA_NETWORK_INFO)が含まれなくなりました。アプリでこの情報が必要になる場合は、代わりに getConnectionInfo()
を呼び出します。
テレフォニー情報の取得にデバイスの位置情報の設定が使用されるようになりました
Android 9 を搭載したデバイスでユーザーがデバイスの位置情報を無効にしている場合、次の方法では結果が得られません。
非 SDK インターフェースの使用制限
アプリの安定性と互換性を確保するため、プラットフォームでは一部の非 SDK メソッドとフィールドの使用が制限されています。これらの制限は、これらのメソッドとフィールドにリフレクション経由で直接アクセスしようとした場合や、JNI を使用してアクセスしようとした場合に適用されます。Android 9 では、アプリは引き続きこれらの制限付きインターフェースにアクセスできます。プラットフォームはトーストとログエントリを使用して、これらのインターフェースに注意を促します。アプリにこのようなトーストが表示される場合は、制限付きインターフェース以外の実装戦略を検討することが重要です。代替戦略が実行可能でないと思われる場合は、バグを報告して制限の再検討をリクエストできます。
非 SDK インターフェースの制限に、その他の重要な情報が記載されています。アプリが引き続き正しく機能することを確認する必要があります。
セキュリティ動作の変更
デバイスのセキュリティの変更
Android 9 では、アプリのターゲット バージョンに関係なく、アプリのセキュリティを強化する機能がいくつか追加されています。
TLS 実装の変更
Android 9 では、システムの TLS 実装にいくつかの変更が加えられています。
SSLSocket
のインスタンスが作成中に接続に失敗すると、システムはNullPointerException
ではなくIOException
をスローします。SSLEngine
クラスは、発生したclose_notify
アラートをクリーンな方法で処理します。
Android アプリで安全なウェブリクエストを行う方法については、HTTPS の例をご覧ください。
厳格な SECCOMP フィルタ
Android 9 では、アプリで使用できるシステム呼び出しがさらに制限されています。この動作は、Android 8.0(API レベル 26)に含まれる SECCOMP フィルタの拡張機能です。
暗号化の変更
Android 9 では、暗号アルゴリズムの実装と処理にいくつかの変更が加えられています。
パラメータとアルゴリズムの Conscrypt 実装
Android 9 では、Conscrypt でアルゴリズム パラメータの追加実装が提供されています。これらのパラメータには、AES、DESEDE、OAEP、EC などがあります。これらのパラメータと多くのアルゴリズムの Bouncy Castle バージョンは、Android 9 で非推奨になりました。
アプリが Android 8.1(API レベル 27)以前をターゲットとしている場合、これらの非推奨のアルゴリズムの Bouncy Castle 実装をリクエストすると、警告が表示されます。ただし、Android 9 をターゲットとしている場合、これらのリクエストはそれぞれ NoSuchAlgorithmException
をスローします。
その他の変更点
Android 9 では、暗号化に関連するその他の変更もいくつか導入されています。
- PBE キーを使用する場合、Bouncy Castle が初期化ベクトル(IV)を想定していて、アプリが IV を提供しない場合は、警告が表示されます。
- ARC4 暗号の Conscrypt 実装では、ARC4/ECB/NoPadding または ARC4/NONE/NoPadding を指定できます。
- Crypto Java Cryptography Architecture(JCA)プロバイダは削除されました。その結果、アプリが
SecureRandom.getInstance("SHA1PRNG", "Crypto")
を呼び出すと、NoSuchProviderException
が発生します。 - アプリが鍵構造よりも大きいバッファから RSA 鍵を解析しても、例外は発生しなくなりました。
Android の暗号機能の使用の詳細については、暗号化をご覧ください。
Android の暗号化された安全なファイルのサポート終了
Android 9 では、Android セキュア暗号化ファイル(ASEC)のサポートが完全に削除されます。
Android 2.2(API レベル 8)では、SD カード上のアプリ機能をサポートするために ASEC が導入されました。Android 6.0(API レベル 23)では、デベロッパーが ASEC の代わりに使用できる適応型ストレージ デバイス技術がプラットフォームに導入されました。
ICU ライブラリの更新
Android 9 では、ICU ライブラリのバージョン 60 が使用されます。Android 8.0(API レベル 26)と Android 8.1(API レベル 27)では ICU 58 が使用されます。
ICU は、android.icu package
の下で公開 API を提供するために使用され、国際化のサポートのために Android プラットフォーム内で内部的に使用されます。たとえば、java.util
、java.text
、android.text.format
で Android クラスを実装するために使用されます。
ICU 60 への更新には、ICU 59 と ICU 60 のリリースノートに記載されているように、絵文字 5.0 データのサポートや日時形式の改善など、小さいながらも有用な変更が多数含まれています。
このアップデートの主な変更点:
- プラットフォームでタイムゾーンを処理する方法が変更されました。
- プラットフォームで GMT と UTC が適切に処理されるようになりました。UTC は GMT の同義語ではなくなりました。
ICU で、GMT と UTC の翻訳されたゾーン名が提供されるようになりました。この変更は、「GMT」、「Etc/GMT」、「UTC」、「Etc/UTC」、「Zulu」などのゾーンの
android.icu
の形式設定と解析動作に影響します。 java.text.SimpleDateFormat
で ICU を使用して UTC /GMT の表示名が提供されるようになりました。つまり、次のように表示されます。zzzz
をフォーマットすると、多くのロケールで長いローカライズ文字列が生成されます。以前は、UTC の場合は「UTC」、GMT の場合は「GMT+00:00」などの文字列が生成されていました。zzzz
の解析では、「協定世界時」や「グリニッジ標準時」などの文字列が認識されます。- すべての言語で
zzzz
に「UTC」または「GMT+00:00」が出力されると想定しているアプリは、互換性の問題が発生する可能性があります。
java.text.DateFormatSymbols.getZoneStrings()
の動作が変更されました。SimpleDateFormat
と同様に、UTC と GMT に長い名前が付けられました。UTC ゾーンのタイムゾーン名の DST バリアント(「UTC」、「Etc/UTC」、「Zulu」など)は GMT+00:00 になります。これは、使用可能な名前がない場合に標準のフォールバックであり、ハードコードされた文字列UTC
ではありません。- 一部のゾーン ID は、他のゾーンの同義語として正しく認識されるため、以前は解決できなかった古いゾーン ID(
Eire
など)の文字列が Android で検出されます。
- Asia/Hanoi は認識されるゾーンではなくなりました。このため、
java.util.TimeZones.getAvailableIds()
はこの値を返さず、java.util.TimeZone.getTimeZone()
は認識しません。この動作は、既存のandroid.icu
の動作と一致します。
- プラットフォームで GMT と UTC が適切に処理されるようになりました。UTC は GMT の同義語ではなくなりました。
android.icu.text.NumberFormat.getInstance(ULocale, PLURALCURRENCYSTYLE).parse(String)
メソッドは、正当な通貨テキストを解析している場合でもParseException
をスローすることがあります。この問題を回避するには、PLURALCURRENCYSTYLE
スタイルの通貨テキストに Android 7.0(API レベル 24)以降で利用可能なNumberFormat.parseCurrency
を使用します。
Android テストの変更点
Android 9 では、Android テスト フレームワークのライブラリとクラス構造にいくつかの変更が加えられています。これらの変更により、デベロッパーはフレームワークでサポートされている公開 API を使用できますが、サードパーティ製ライブラリやカスタム ロジックを使用してテストをビルドおよび実行する際にも柔軟性が向上します。
フレームワークから削除されたライブラリ
Android 9 では、JUnit ベースのクラスが android.test.base、android.test.runner、android.test.mock の 3 つのライブラリに再編成されています。この変更により、プロジェクトの依存関係に最適なバージョンの JUnit に対してテストを実行できるようになります。このバージョンの JUnit は、android.jar
が提供するバージョンとは異なる場合があります。
JUnit ベースのクラスがこれらのライブラリにどのように編成されているか、およびテストの作成と実行のためにアプリのプロジェクトを準備する方法について詳しくは、Android Test 用にプロジェクトをセットアップするをご覧ください。
テストスイートのビルド変更
TestSuiteBuilder
クラスの addRequirements()
メソッドが削除され、TestSuiteBuilder
クラス自体が非推奨になりました。addRequirements()
メソッドでは、デベロッパーがタイプが非公開 API の引数を指定する必要があり、API が無効になっていました。
Java UTF デコーダ
Android のデフォルトの文字セットは UTF-8 です。UTF-8 バイト シーケンスは、String(byte[] bytes)
などの String
コンストラクタでデコードできます。
Android 9 の UTF-8 デコーダは、以前のバージョンよりも厳密に Unicode 標準に準拠しています。変更内容は次のとおりです。
<C0, AF>
など、UTF-8 の最短形式以外の形式は、不正な形式として扱われます。- UTF-8 のサロゲート形式(
U+D800
..U+DFFF
など)は、不正な形式として扱われます。 - 最大サブパートは 1 つの
U+FFFD
に置き換えられます。たとえば、バイト シーケンス「41 C0 AF 41 F4 80 80 41
」では、最大サブパートは「C0
」、「AF
」、「F4 80 80
」です。「F4 80 80
」は「F4 80 80 80
」の最初のサブシーケンスにできますが、「C0
」は適切な形式のコード単位シーケンスの最初のサブシーケンスにできません。出力は「A\ufffd\ufffdA\ufffdA
」になります。 - Android 9 以降で変更された UTF-8 / CESU-8 シーケンスをデコードするには、
DataInputStream.readUTF()
メソッドまたはNewStringUTF()
JNI メソッドを使用します。
証明書を使用したホスト名の検証
RFC 2818 では、ドメイン名と証明書を照合する 2 つの方法が説明されています。subjectAltName
(SAN
)拡張機能内で使用可能な名前を使用する方法と、SAN
拡張機能がない場合の commonName
(CN
)へのフォールバックです。
ただし、CN
へのフォールバックは RFC 2818 で非推奨になりました。このため、Android は CN
を使用するフォールバックを行いなくなりました。ホスト名を検証するには、サーバーが一致する SAN
を含む証明書を提示する必要があります。ホスト名に一致する SAN
が含まれていない証明書は、信頼されなくなります。
ネットワーク アドレスのルックアップによりネットワーク違反が発生する可能性がある
名前解決を必要とするネットワーク アドレス ルックアップにはネットワーク I/O が関与する可能性があるため、ブロッキング オペレーションと見なされます。メインスレッドでブロッキング オペレーションを実行すると、一時停止やジャンクが発生する可能性があります。
StrictMode
クラスは、デベロッパーがコードの問題を検出できるようにする開発ツールです。
Android 9 以降では、StrictMode
は、名前解決を必要とするネットワーク アドレスのルックアップによって発生したネットワーク違反を検出します。
StrictMode
を有効にしてアプリを配信しないでください。ネットワーク違反を検出するポリシーを取得するために detectNetwork()
メソッドまたは detectAll()
メソッドを使用すると、アプリで例外(NetworkOnMainThreadException
など)が発生する可能性があります。
数値の IP アドレスを解決することは、ブロック オペレーションとは見なされません。数値 IP アドレスの解決は、Android 9 より前のバージョンと同じように機能します。
ソケットのタグ付け
Android 9 より前のプラットフォーム バージョンでは、setThreadStatsTag()
メソッドを使用してソケットにタグが付けられている場合、ParcelFileDescriptor
コンテナを使用して バインダー IPC で別のプロセスに送信されると、ソケットのタグ付けが解除されます。
Android 9 以降では、バインダー IPC を使用して別のプロセスに送信されるときに、ソケットタグが保持されます。この変更は、queryDetailsForUidTag()
メソッドを使用する場合など、ネットワーク トラフィックの統計情報に影響する可能性があります。
別のプロセスに送信されるソケットのタグを解除する、以前のバージョンの動作を維持する場合は、ソケットを送信する前に untagSocket()
を呼び出すことができます。
ソケットで使用可能なバイト数の報告
available()
メソッドは、shutdownInput()
メソッドの呼び出し後に呼び出されると 0
を返します。
VPN のより詳細なネットワーク機能レポート
Android 8.1(API レベル 27)以前では、NetworkCapabilities
クラスは VPN に関する限定された情報セット(TRANSPORT_VPN
など)のみを報告し、NET_CAPABILITY_NOT_VPN
は報告しませんでした。この情報の制限により、VPN の使用によってアプリのユーザーに請求が発生するかどうかを判断することが困難でした。たとえば、NET_CAPABILITY_NOT_METERED
を確認しても、基盤となるネットワークが課金対象かどうかは判断できません。
Android 9 以降では、VPN が setUnderlyingNetworks()
メソッドを呼び出すと、Android システムは基盤となるネットワークのトランスポートと機能を統合し、結果を VPN ネットワークの有効なネットワーク機能として返します。
Android 9 以降では、すでに NET_CAPABILITY_NOT_METERED
を確認しているアプリは、VPN と基盤となるネットワークのネットワーク機能を受け取ります。
xt_qtaguid フォルダ内のファイルをアプリで使用できなくなりました
Android 9 以降では、アプリが /proc/net/xt_qtaguid
フォルダ内のファイルに直接読み取りアクセスすることは許可されません。これは、これらのファイルがまったくない一部のデバイスとの整合性を確保するためです。
これらのファイルに依存する公開 API(TrafficStats
と NetworkStatsManager
)は、引き続き意図したとおりに動作します。ただし、qtaguid_tagSocket()
などのサポートされていない cutils 関数は、デバイスによっては想定どおりに動作しないか、まったく動作しない可能性があります。
FLAG_ACTIVITY_NEW_TASK の要件が適用されるようになりました
Android 9 では、インテント フラグ FLAG_ACTIVITY_NEW_TASK
を渡さない限り、アクティビティ以外のコンテキストからアクティビティを開始できません。このフラグを渡さずにアクティビティを開始しようとすると、アクティビティは開始されず、システムはログにメッセージを出力します。
画面の回転の変更
Android 9 以降、縦向き回転モードに大幅な変更が加えられています。Android 8.0(API レベル 26)では、QuickSettings タイルやディスプレイの設定を使用して、自動回転モードと縦向き回転モードを切り替えることができました。縦向きモードの名称を回転ロックに変更しました。回転ロックは、画面の自動回転がオフの場合に有効になります。自動回転モードに変更はありません。
デバイスが回転ロックモードになっている場合、ユーザーは最前面に表示されているアクティビティに応じて画面の向きを固定できます。アクティビティは、常に縦向きでレンダリングされると想定すべきではありません。最前面のアクティビティを自動回転モードで複数の向きにレンダリングできる場合、回転ロックモードでも同じ選択肢を使用できますが、アクティビティの screenOrientation
設定に基づいた例外もいくつかあります(下記の表を参照)。
特定の画面の向きをリクエストするアクティビティ(screenOrientation=landscape
など)は、ユーザー ロックの設定を無視し、Android 8.0 と同じように動作します。
画面の向きの設定は、Android マニフェストのアクティビティ レベルで設定するか、プログラムで setRequestedOrientation() を使用して設定できます。
回転ロック モードは、WindowManager がアクティビティの回転を処理する際に使用するユーザーの画面の向きの設定を設定することで機能します。ユーザーの画面の向きの設定は、次のような場合に変更されることがあります。デバイスの自然な回転(通常はスマートフォン フォーム ファクタのデバイスでは縦向き)に戻る傾向があります。
- ユーザーが画面の向きの候補を承認すると、画面の向きの設定が候補に変更されます。
- ユーザーが強制縦向きアプリ(ロック画面やランチャーなど)に切り替えると、画面の向きの設定が縦向きに変更されます。
次の表に、一般的な画面の向きの回転動作の概要を示します。
画面の向き | 動作 |
---|---|
未指定、ユーザー | 自動回転と回転ロックでは、アクティビティを縦向きまたは横向き(またはその逆)でレンダリングできます。縦向きと横向きの両方のレイアウトをサポートする必要があります。 |
userLandscape | 自動回転と回転ロックでは、アクティビティを横向きまたは反転横向きでレンダリングできます。横向きレイアウトのみをサポートすることを想定してください。 |
userPortrait | 自動回転と回転ロックでは、アクティビティを縦向きまたは縦向き反転のいずれかでレンダリングできます。縦向きレイアウトのみをサポートすることを想定してください。 |
fullUser | 自動回転と回転ロックでは、アクティビティを縦向きまたは横向き(またはその逆)でレンダリングできます。縦向きと横向きの両方のレイアウトに対応する予定です。 画面の向きのロックを設定しているユーザーは、縦向き(通常は 180°)にロックするオプションを選択できます。 |
sensor、fullSensor、sensorPortrait、sensorLandscape | 回転ロック モードの設定は無視され、自動回転が有効になっている場合と同様に扱われます。例外的な状況でのみ使用し、UX を慎重に検討してください。 |
Apache HTTP クライアントのサポート終了が、標準以外の ClassLoader を使用するアプリに影響
Android 6.0 では、Apache HTTP クライアントのサポートが削除されました。この変更は、Android 9 以降をターゲットとしていないほとんどのアプリには影響しません。ただし、この変更は、Android 9 以降をターゲットとしていないアプリであっても、非標準の ClassLoader
構造を使用する特定のアプリに影響する可能性があります。
アプリが、システムの ClassLoader
を明示的に委任する標準外の ClassLoader
を使用している場合、アプリは影響を受ける可能性があります。このようなアプリは、org.apache.http.*
でクラスを検索するときに、アプリ
ClassLoader
に委任する必要があります。システム ClassLoader
に委任すると、Android 9 以降では、これらのクラスがシステム ClassLoader
に認識されなくなるため、アプリは NoClassDefFoundError
で失敗します。今後同様の問題が発生しないように、アプリは通常、システム ClassLoader
に直接アクセスするのではなく、アプリ ClassLoader
を介してクラスを読み込む必要があります。
カメラの列挙
Android 9 デバイスで実行されているアプリは、getCameraIdList()
を呼び出して、使用可能なすべてのカメラを検出できます。アプリは、デバイスに背面カメラが 1 つしかない、または前面カメラが 1 つしかないと想定してはなりません。
たとえば、アプリに前面カメラと背面カメラを切り替えるボタンがある場合、選択できる前面カメラまたは背面カメラが複数あることがあります。カメラリストを走査し、各カメラの特性を確認して、ユーザーに公開するカメラを決定する必要があります。