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)がアプリで指定されていない場合は、警告が表示されます。
- ARC4 暗号の Conscrypt 実装では、ARC4/ECB/NoPadding または ARC4/NONE/NoPadding を指定できます。
- Crypto Java 暗号化アーキテクチャ(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 の代わりに使用できる Adoptable Storage デバイス テクノロジーがプラットフォームに導入されました。
ICU ライブラリの更新
Android 9 は、バージョン 60 の ICU ライブラリを使用します。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 のアップデートには、絵文字 5.0 データのサポートや日時形式の改善など、小さなながらも有用な変更が多数含まれています(ICU 59 と ICU 60 のリリースノートに記載)。
今回の更新の重要な変更点:
- プラットフォームによるタイムゾーンの処理方法が変更されました。
- プラットフォームが 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」、「Etc/UTC」、「Zulu」などの UTC ゾーンのタイムゾーン名の DST バリアントは GMT+00:00 になります。これは、ハードコードされた文字列UTC
ではなく、利用可能な名前がない場合の標準的なフォールバックです。- 一部のゾーン ID は他のゾーンの類義語として正しく認識されるため、Android は、以前は解決できなかった古いゾーン ID(
Eire
など)の文字列を検出します。
- アジア/ハノイは認識されたゾーンではなくなりました。このため、
java.util.TimeZones.getAvailableIds()
はこの値を返せず、java.util.TimeZone.getTimeZone()
はこの値を認識しません。この動作は既存のandroid.icu
の動作と同じです。
- プラットフォームが GMT と UTC を適切に処理するため、UTC は GMT の同義語ではなくなりました。
android.icu.text.NumberFormat.getInstance(ULocale, PLURALCURRENCYSTYLE).parse(String)
メソッドが正規の通貨テキストを解析している場合でもParseException
をスローすることがあります。この問題を回避するには、Android 7.0(API レベル 24)以降で利用可能なNumberFormat.parseCurrency
をPLURALCURRENCYSTYLE
スタイルの通貨テキストに使用します。
Android テストの変更
Android 9 では、Android テスト フレームワークのライブラリとクラスの構造がいくつか変更されています。これらの変更により、フレームワークでサポートされる公開 API を使用できるようになりますが、サードパーティのライブラリやカスタム ロジックを使用したテストのビルドと実行の柔軟性も向上します。
フレームワークから削除されたライブラリ
Android 9 では、JUnit ベースのクラスが 3 つのライブラリ(android.test.base、android.test.runner、android.test.mock)に再編成されています。この変更により、プロジェクトの依存関係で最適に動作する JUnit のバージョンに対してテストを実行できます。このバージョンの JUnit は、android.jar
が提供するバージョンとは異なる場合があります。
JUnit ベースのクラスをこれらのライブラリにまとめる方法と、テストの作成と実行用にアプリのプロジェクトを準備する方法の詳細については、Android Test 用にプロジェクトをセットアップするをご覧ください。
テストスイートのビルド変更
TestSuiteBuilder
クラスの addRequirements()
メソッドが削除され、TestSuiteBuilder
クラス自体のサポートが終了しました。addRequirements()
メソッドでは、型が非表示 API の引数を指定する必要があり、API が無効になっていました。
Java UTF デコーダ
UTF-8 は Android のデフォルトの文字セットです。UTF-8 バイト シーケンスは String
コンストラクタ(String(byte[] bytes)
など)でデコードできます。
Android 9 の UTF-8 デコーダは、以前のバージョンよりも Unicode 標準に厳密に準拠しています。変更内容は次のとおりです。
- UTF-8 の最短でない形式(
<C0, AF>
など)は、不正な形式として扱われます。 - UTF-8 のサロゲート形式(
U+D800
..U+DFFF
など)は、不正な形式として扱われます。 - 最大サブパートは単一の
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 つの方法が記述されています。1 つは subjectAltName
(SAN
)拡張内で使用可能な名前を使用する方法で、もう 1 つは 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
クラスは TRANSPORT_VPN
など、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
)は、引き続き意図したとおりに機能します。ただし、サポートされていない cutils 関数(qtaguid_tagSocket()
など)は、別のデバイスでは想定どおりに動作しない(またはまったく動作しない)場合があります。
FLAG_ACTIVITY_NEW_TASK 要件が適用されるようになりました
Android 9 では、インテント フラグ FLAG_ACTIVITY_NEW_TASK
を渡さない限り、アクティビティ以外のコンテキストからアクティビティを開始することはできません。このフラグを渡さずにアクティビティを起動しようとすると、アクティビティは開始されず、ログにメッセージが出力されます。
画面の回転の変更
Android 9 以降、縦向きの回転モードが大幅に変更されています。Android 8.0(API レベル 26)では、クイック設定タイルまたはディスプレイ設定を使用して、自動回転と縦向きの回転モードを切り替えることができました。ポートレート モードは回転ロックという名称に変更されました。このモードは自動回転がオフになっているときに有効になります。自動回転モードに変更はありません。
デバイスが回転ロックモードのとき、ユーザーは上部に表示されているアクティビティでサポートされている任意の回転に画面をロックできます。アクティビティは常に縦向きにレンダリングされるとは限りません。一番上のアクティビティを自動回転モードで複数の回転でレンダリングできる場合は、アクティビティの screenOrientation
設定に基づく例外を除き、回転ロックモードで同じオプションを使用できます(以下の表を参照)。
特定の向きを要求するアクティビティ(screenOrientation=landscape
など)は、ユーザーのロック設定を無視し、Android 8.0 と同じように動作します。
画面の向きの設定は、Android マニフェスト内でアクティビティ レベルで行うか、setRequestedOrientation() を使用してプログラムで設定できます。
回転ロックモードは、WindowManager がアクティビティの回転を処理するときに使用するユーザーの回転設定を指定することで機能します。ユーザーのローテーション設定は、次の場合に変更される可能性があります。なお、デバイスの自然な回転に戻るバイアスがあります。これは通常、スマートフォンのフォーム ファクタ デバイスでは縦向きです。
- ユーザーが回転の提案を承認すると、回転設定は提案に変わります。
- ユーザーが強制的な縦向きのアプリ(ロック画面やランチャーを含む)に切り替えると、回転設定が縦向きに変更されます。
次の表は、一般的な画面の向きでの回転動作をまとめたものです。
画面の向き | 動作 |
---|---|
指定なし、ユーザー | 自動回転と回転ロックでは、アクティビティを縦向きまたは横向き(およびその逆)にレンダリングできます。縦向きと横向きの両方のレイアウトをサポートすることが想定されます。 |
ユーザーランドスケープ | 自動回転と回転ロックでは、アクティビティを横向きまたは逆の横向きにレンダリングできます。横向きのレイアウトのみをサポートすると想定してください。 |
ユーザーポートレート | 自動回転と回転ロックでは、アクティビティを縦向きまたは逆の縦向きにレンダリングできます。縦向きのレイアウトのみをサポートすると想定してください。 |
フルユーザー | 自動回転と回転ロックでは、アクティビティを縦向きまたは横向き(およびその逆)にレンダリングできます。縦向きと横向きの両方のレイアウトがサポートされる予定です。 回転ロックでは、逆の縦向き(多くの場合 180 度)にロックするオプションが提供されます。 |
sensor、fullSensor、sensorPortrait、sensorLandscape | 回転ロックモードの設定は無視され、自動回転がアクティブなものとして扱われます。UX について細心の注意を払って、例外的な状況でのみ使用してください。 |
Apache HTTP クライアントの非推奨が、非標準の ClassLoader を使用するアプリに影響する
Android 6.0 で、Apache HTTP クライアントのサポートが削除されました。この変更は、Android 9 以降をターゲットとしていない大多数のアプリには影響しません。ただし、標準以外の ClassLoader
構造を使用する特定のアプリは、Android 9 以降をターゲットとしていなくても、この変更の影響を受ける可能性があります。
システムの ClassLoader
に明示的に委任する標準以外の ClassLoader
を使用しているアプリは、影響を受ける可能性があります。このようなアプリは、org.apache.http.*
でクラスを検索するときに、代わりにアプリ
ClassLoader
にデリゲートする必要があります。アプリがシステム ClassLoader
にデリゲートすると、Android 9 以降では、これらのクラスがシステム ClassLoader
に認識されなくなるため、NoClassDefFoundError
で失敗します。今後同様の問題を防ぐため、通常は、システムの ClassLoader
に直接アクセスするのではなく、アプリ ClassLoader
を介してクラスを読み込む必要があります。
カメラの列挙
Android 9 デバイスで実行されるアプリは、getCameraIdList()
を呼び出すことで、利用可能なすべてのカメラを検出できます。アプリは、デバイスの背面カメラまたは前面カメラが 1 つのみであると想定すべきではありません。
たとえば、アプリに前面カメラと背面カメラを切り替えるボタンがある場合、複数の前面カメラまたは背面カメラを選択できます。カメラリストを確認し、各カメラの特性を調べて、ユーザーに公開するカメラを決定する必要があります。