Android Dev Summit, October 23-24: two days of technical content, directly from the Android team. Sign-up for livestream updates.

動作の変更点: すべてのアプリ

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 を実行する端末では、バックグラウンドで実行中のアプリに、次のような制約が適用されます。

  • アプリはマイクやカメラにアクセスできません。
  • 加速度計やジャイロスコープなど、継続的な報告モードを使用する Sensor は、イベントを受信しません。
  • 変化時またはワンショットの報告モードを使用するセンサーは、イベントを受信しません。

Android 9 を実行する端末でセンサー イベントを検出する必要がある場合は、フォアグラウンド サービスを使用してください。

通話履歴へのアクセスの制限

Android 9 では、CALL_LOG パーミッション グループが導入されており、このグループに READ_CALL_LOGWRITE_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 を通じて提供される電話番号フィールドは空になります。

電話の状態から電話番号を読み取るには、ユースケースに基づいて必要なパーミッションをリクエストするようにアプリをアップデートします。

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 を取得するには、端末でロケーション サービスを有効にする必要もあります([Settings] > [Location] で設定)。

Wi-Fi サービスのメソッドから削除された情報

Android 9 では、次のイベントとブロードキャストは、ユーザーのロケーションまたは個人を特定できるデータに関する情報を受け取りません。

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 で非推奨となりました。

注: EC パラメータの Conscrypt 実装は、名前つきの曲線のみをサポートします。

Android 8.1(API レベル 27)以前のバージョンをターゲットとするアプリの場合、これらの非推奨となったアルゴリズムの Bouncy Castle 実装をリクエストすると警告が出ます。 一方 Android 9 をターゲットとするアプリの場合は、このようなリクエストをするたびに、NoSuchAlgorithmException がスローされます。

その他の変更点

Android 9 では、暗号化に関する次のような変更も導入されています。

  • PBE 鍵を使用しており、Bouncy Castle に必要な初期化ベクトル(Ⅳ)をアプリが提供していない場合は、警告が発生します。
  • ARC4 暗号の Conscrypt 実装を使用すると、ARC4/ECB/NoPadding または ARC4/NONE/NoPadding を指定できます。
  • Crypto Java Cryptography Architecture(JCA)プロバイダは 削除されました。 そのため、アプリで SecureRandom.getInstance("SHA1PRNG", "Crypto") を呼び出すと、NoSuchProviderException が発生します。
  • アプリで、鍵構造よりも大きなバッファから RSA 鍵を解析する場合、例外は発生しません。

Android の暗号化機能の使用に関する詳細は、暗号化をご覧ください。

ASEC ファイルのサポート終了

Android 9 では、Android セキュア暗号化ファイル(ASEC)のサポートが完全に削除されています。

Android 2.2(API レベル 8)では、SD カード上にアプリを保存する機能をサポートするために ASEC が導入されました。 Android 6.0(API レベル 23)で、デベロッパーが ASEC の代わりに使用できる追加可能なストレージ デバイス テクノロジーがプラットフォームに導入されました。

ICU ライブラリの更新

Android 9 では、バージョン 60 の ICU ライブラリが使用されます。 Android 8.0(API レベル 26)と Android 8.1(API レベル 27)では、ICU 58 が使用されます。

ICU は、android.icu package 配下でパブリック API を提供し、 Android プラットフォーム内部で国際化をサポートするために利用されています。 たとえば、java.utiljava.textandroid.text.format 内で Android クラスを実装するために使用されます。

ICU 60 のアップデートには、ICU 59 および 60 のリリースノートに記載されている Emoji 5.0 のデータサポートや改善された日付 / 時刻フォーマットなど、役に立つ細かい変更が多く含まれています。

このアップデートの主な変更点は、次のとおりです。

  • プラットフォームによるタイムゾーンの処理方法が変更されました。
    • プラットフォームでの GMT や UTC の処理方法が改善され、UTC はもはや GMT の同義語ではなくなりました。

      現在、ICU では翻訳された GMT および UTC のゾーン名が提供されています。 この変更によって、android.icu のフォーマット処理や、"GMT"、"Etc/GMT"、"UTC"、"Etc/UTC"、"Zulu" などのゾーンの解析処理に影響が生じます。

    • 現在 java.text.SimpleDateFormat は、次のように ICU を使って UTC / GMT の表示名を提供しています。
      • zzzz をフォーマットすると、多くのロケール向けにローカライズされた長い文字列が生成されます。 以前は、UTC に対しては "UTC"、GMT に対しては "GMT+00:00" のような文字列を生成していました。
      • zzzz を解析すると、"Universal Coordinated Time" や "Greenwich Mean Time" などの文字列が認識されます。
      • すべての言語において zzzz の出力が "UTC" や "GMT+00:00" になると想定しているアプリでは、互換性の問題が発生する可能性があります。
    • java.text.DateFormatSymbols.getZoneStrings() の動作が次のように変更されました。
      • SimpleDateFormat と同様に、UTC と GMT は長い名称を持ちます。 "UTC" や "Etc/UTC"、"Zulu" など、UTC ゾーンのタイムゾーン名の DST 変数は、利用可能な名前がない場合、ハードコードされた文字列 UTC ではなく、標準フォールバックの GMT+00:00 になります。
      • 一部のゾーン ID は他のゾーンの同義語として正しく認識されるため、Android は、Eire などの以前は解決できなかった古いゾーン ID の文字列を探します。
    • Asia/Hanoi は、ゾーンとして認識されなくなりました。 そのため、この値は java.util.TimeZones.getAvailableIds() によって返されず、java.util.TimeZone.getTimeZone() で認識されません。 この動作は、既存の android.icu の動作に一致します。
  • 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.baseandroid.test.runnerandroid.test.mock の 3 つのライブラリに再構成されています。 この変更により、プロジェクトの依存関係で最適に動作する JUnit のバージョンに対してテストを実行することが可能になりました。 JUnit のこのバージョンは、android.jar が提供するバージョンと異なる場合があります。

JUnit ベースのクラスがこれらのライブラリに構成される方法と、テストの作成と実行に向けてアプリのプロジェクトを準備する方法の詳細については、Android テスト用にプロジェクトを設定するをご覧ください。

テストスイート ビルドの変更

TestSuiteBuilder クラスの addRequirements() メソッドは削除され、TestSuiteBuilder クラス自体は非推奨となりました。 addRequirements() メソッドは、デベロッパーに非公開 API の型の引数を要求し、その API を無効にしていました。

Java UTF デコーダ

UTF-8 は Android のデフォルトの文字セットです。 UTF-8 バイト シーケンスは、String(byte[] bytes) などの String コンストラクタによってデコードできます。

Android 9 の UTF-8 デコーダは、前のバージョンよりも厳密に Unicode に準拠しています。 変更点は、以下のとおりです。

  • <C0, AF> などの UTF-8 の非最短形式は、不正な形式として処理されます。
  • U+D800..U+DFFF などの UTF-8 のサロゲート形式は、不正な形式として処理されます。
  • 最大のサブパートは、単一の 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 つの方法が説明されています。subjectAltNameSAN)拡張機能で利用可能な名前を使用する方法と、SAN 拡張機能が存在しない場合に commonNameCN)にフォールバックする方法です。

ただし、CN へのフォールバックは RFC 2818 で非推奨となりました。そのため、Android では現在、フォールバックして CN を使用することはありません。 ホスト名を確認するには、対応する SAN を含む証明書をサーバー側が提示する必要があります。 ホスト名に対応する SAN が含まれない証明書は、今後は信頼されません。

ネットワーク アドレス検索に起因するネットワーク違反

名前解決が必要なネットワーク アドレスのルックアップは、ネットワークの入出力処理を含む場合があるため、ブロッキング処理として扱われます。 メインスレッドでのブロッキング処理は、一時停止やジャンクを引き起こす可能性があります。

StrictMode クラスを開発ツールとして利用すると、デベロッパーはコード内の問題を検出しやすくなります。

Android 9 以降では、StrictMode によって、名前解決が必要なネットワークアドレスのルックアップで生じたネットワーク違反が検出されます。

StrictMode を有効にした状態でアプリを公開しないでください。 このモードを有効にして公開すると、detectNetwork() メソッドや detectAll() メソッドを使用してネットワーク違反を検出するポリシーを取得した際に、アプリで NetworkOnMainThreadException などの例外が発生する可能性があります。

数値の IP アドレスからの名前解決はブロッキング処理として扱われず、 Android 9 よりも前のバージョンと同じように機能します。

ソケットのタグ付け

Android 9 よりも前のプラットフォーム バージョンでは、setThreadStatsTag() メソッドを使用してソケットにタグづけをしても、binder IPC を使用して ParcelFileDescriptor コンテナで別のプロセスにソケットを送ると、タグが外れていました。

Android 9 以降では、binder IPC でソケットを別のプロセスに送っても、タグは保持されるようになります。 この変更は、queryDetailsForUidTag() メソッドを使うときなどに、ネットワークトラフィックの統計情報に影響を与えます。

別のプロセスに送信されたソケットのタグが外されるという以前のバージョンの動作を保持する場合は、ソケットを送信する前に、untagSocket() を呼び出すことができます。

ソケットで利用可能なバイト数の報告

shutdownInput() メソッドを呼び出した後、available() メソッドを呼び出すと、0 が返されます。

より詳細な VPN 情報を報告するネットワーク機能

Android 8.1(API レベル 28)以前では、NetworkCapabilities クラスが報告する VPN の情報は、TRANSPORT_VPN などに限られており、NET_CAPABILITY_NOT_VPN は省略されていました。 情報が限られているため、VPN を使用するとアプリのユーザーが課金されることになるのかを判別するのが困難でした。 たとえば NET_CAPABILITY_NOT_METERED をチェックしても、基盤となるネットワークが従量制かどうかは判別できません。

Android 9 以降では、VPN が setUnderlyingNetworks() メソッドを呼び出すと、Android システムによって基盤ネットワークのトランスポートと機能がマージされ、VPN ネットワークの有効なネットワーク機能が結果として返されます。

すでにアプリで NET_CAPABILITY_NOT_METERED をチェックしている場合、Android 9 以降では 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 7.0(API レベル 24)より前のバージョンで適用されます。 Android 7.0 では、バグによりフラグ要件が適用されません。

画面回転の変更

Android 9 以降では、縦向きの回転モードが大幅に変更されています。 Android 8.0(API レベル 26)では、クイック設定タイルまたは画面設定から、ユーザーが回転モードを自動回転または縦向きに切り替えることができます。 ポートレート モードは回転ロックという名称に変更されました。このモードは、自動回転がオフになっている状態で有効になります。 自動回転モードに変更はありません。

端末が回転ロックモードのとき、ユーザーは、表示中のトップ Activity でサポートされている任意の回転状態に画面をロックできます。 Activity は、必ずしも縦向きにレンダリングされるとは限りません。 自動回転モードのときに、トップ Activity が複数の回転に応じてレンダリング可能な場合は、回転ロックモードでも同じオプションに対応する必要があります。ただし、Activity の screenOrientation の設定に応じて、例外がいくつかあります(以下の表を参照)。

具体的な画面の向き(screenOrientation=landscape など)を要求する Activity は、ユーザーによるロック設定を無視し、Android 8.0 と同じように動作します。

画面の向きの設定は、Android マニフェストを使用するか、プログラムで setRequestedOrientation() を使用すると、Activity レベルで指定できます。

回転ロックモードは、WindowManager が Activity の回転を処理する際に使用するユーザーの回転設定を指定することで有効になります。 このユーザーの回転設定は、次のケースにおいて変更される場合があります。 端末の自然な回転に戻るという先入観に注意してください。これは通常、スマートフォン フォーム ファクタ端末では縦向きです。

  • 回転に関する提案をユーザーが受け入れた場合、回転設定はその提案内容に変更されます。
  • 強制的に縦向きになるアプリ(ロック画面やランチャーを含む)にユーザーが切り替えた場合、回転設定は縦向きに変更されます。

以下の表に、一般的な画面の向きと回転動作の関係を示します。

画面の向き 動作
unspecified、user 自動回転および回転ロックモードにおいて、Activity は縦向きまたは横向き(および反転した向き)にレンダリング可能。 この場合、縦向きと横向きの両方のレイアウトをサポートする必要があります。
userLandscape 自動回転および回転ロックモードにおいて、Activity は横向き、または反転した横向きにレンダリング可能。 この場合、横向きのレイアウトのみをサポートする必要があります。
userPortrait 自動回転および回転ロックモードにおいて、Activity は縦向き、または反転した縦向きにレンダリング可能。 この場合、縦向きのレイアウトのみをサポートする必要があります。
fullUser 自動回転および回転ロックモードにおいて、Activity は縦向きまたは横向き(および反転した向き)にレンダリング可能。 この場合、縦向きおよび横向きの両方のレイアウトをサポートする必要があります。

回転ロックモードに設定しているユーザーは、反転した縦向き(主に 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 にデリゲートする場合、それらのクラスはシステムの ClassLoader によって認識されなくなっているため、Android 9 以降では、NoClassDefFoundError によりアプリの実行が失敗します。 今後、同様の問題を防止するために、アプリでは通常、システムの ClassLoader に直接アクセスせずに、アプリの ClassLoader を介してクラスを読み込む必要があります。

カメラの列挙

Android 9 端末で実行されるアプリでは、getCameraIdList() を呼び出して、利用可能なすべてのカメラを見つけることができます。 アプリでは、端末に単一の背面カメラまたは前面カメラのみがあると想定すべきではありません。

たとえば、前面カメラと背面カメラを切り替えるボタンがアプリにある場合、選択できる複数の前面カメラまたは背面カメラが存在する可能性があります。 カメラリストを確認して、各カメラの特徴を調べ、ユーザーに提示するカメラを決定する必要があります。