動作の変更点: Android 17 以上をターゲットとするアプリ

これまでのリリースと同様、Android 17 には、アプリに影響する可能性がある動作変更が含まれています。下記の動作変更は、Android 17 以上をターゲットとするアプリにのみ適用されます。アプリが Android 17 以上をターゲットとする場合は、必要に応じてアプリを変更し、下記の動作に対応できるようにしてください。

アプリの targetSdkVersion に関係なく、Android 17 で実行されるすべてのアプリに影響する動作変更のリストも必ずご確認ください。

ユーザー エクスペリエンスとシステム UI

Android 17 には、より一貫性のある直感的なユーザー エクスペリエンスを実現するための、以下の変更が含まれています。

メモリ上限ウィジェット

Android 17 以降では、Android 17(API レベル 37)以降を対象とするアプリの RemoteViews の更新に、システムが厳格なメモリ上限を適用します。アプリが RemoteViews オブジェクトを AppWidgetManager.updateAppWidget に渡すと、system_server は、ペイロード内のすべての向きとサイズバケットにわたるすべての画像データの合計メモリ使用量を計算します。合計メモリがシステムの上限(mMaxWidgetBitmapMemory)を超えると、システムは更新を拒否し、IllegalArgumentException をスローします。

java.lang.IllegalArgumentException: RemoteViews for widget update exceeds maximum bitmap memory usage (used: XXXXX, max: YYYYY)

API レベル 36 以下を対象とするアプリの場合、システムはこのメモリ違反を警告(Slog.w)としてログに記録し、例外はスローしません。

システムがメモリの上限を計算する方法

システムは、アクティブなディスプレイ構成に対して、ウィジェットのビットマップ メモリ予算を 6 * width * height バイト(1.5 * 4 * width * height、全画面 ARGB_8888 バッファのサイズの 1.5 倍に相当)に設定します。API レベル 37 以降では、この計算に次の両方が含まれます。

  • RemoteViews.mBitmapCache に保存されている、メモリ内の Bitmap オブジェクトとビットマップを基盤とする Icon オブジェクト(Icon.TYPE_BITMAP と Icon.TYPE_ADAPTIVE_BITMAP)(setImageViewBitmap、Icon.createWithBitmap、Icon.createWithAdaptiveBitmap、Jetpack Glance ImageProvider(bitmap) への呼び出しなど)。mBitmapCache 内の一意の Bitmap インスタンスまたはビットマップを基盤とする Icon インスタンスは、RemoteViews 階層ごとに 1 回カウントされます。
  • URI ベースの画像(Icon.createWithContentUri、setImageViewUri、Glance ImageProvider(uri))は、system_server の RemoteViews IPC バイト上限にはカウントされませんが、ウィジェット ホスト プロセスは、参照された content:// ファイルをフル解像度で独自のヒープにデコードします。ダウンサンプリングされた画像は、FileProvider URI を介して公開する前に、必ず context.cacheDir に書き込みます。

緩和策

スマートフォン、タブレット、折りたたみ式デバイスでウィジェットの更新をメモリの上限内に抑えるには、次の操作を行います。

  1. WindowMetrics からランタイム メモリ予算を計算する: API レベル 30 以降では、resources.displayMetrics ではなく WindowManager.currentWindowMetrics.bounds からアクティブ ウィンドウの境界を読み取ります。マルチ解像度デバイスや折りたたみ式デバイスでは、displayMetrics が非アクティブなディスプレイのサイズを報告することがあります。次の例に示すように、ウィジェットの画像予算の合計を 6L * bounds.width() * bounds.height() と見積もります。

    private const val FALLBACK_MAX_BYTES = 15_000_000L
    
    fun calculateWidgetMemoryCapBytes(context: Context): Long {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            val wm = context.getSystemService(WindowManager::class.java)
                ?: return FALLBACK_MAX_BYTES
            val bounds = wm.currentWindowMetrics.bounds
            return 6L * bounds.width().toLong() * bounds.height().toLong()
        }
        val dm = context.resources.displayMetrics
        return 6L * dm.widthPixels.toLong() * dm.heightPixels.toLong()
    }
    
  2. ウィジェットの表示可能なサイズに画像をダウンサンプリングし、RGB_565 を使用する: ウィジェットの最大表示サイズ(maxWidthDp x maxHeightDp)に合わせた 2 のべき乗の BitmapFactory.Options.inSampleSize 値でビットマップをデコードし、不透明な写真やサムネイルには ARGB_8888(1 ピクセルあたり 4 バイト)ではなく Bitmap.Config.RGB_565(1 ピクセルあたり 2 バイト)を使用します。

  3. Jetpack Glance の provideContent の外部でビットマップ デコードをホイスティングする: SizeMode.Responsive または SizeMode.Exact を使用する場合、Glance はサイズバケットごとに 1 回 provideContent ラムダを呼び出します。provideContent を呼び出す前に、provideGlance 内で共有 Bitmap を 1 回デコードします。これにより、すべてのサイズバケットが RemoteViews.mBitmapCache 内の同じ Bitmap インスタンスを参照するようになります。

  4. 画像を置き換える場合は、完全な updateAppWidget 呼び出しを使用する: 従来の AppWidgetProvider 実装では、AppWidgetManager.partiallyUpdateAppWidget を呼び出して Bitmap ビューまたは Icon ビューをスワップしないでください。部分更新では、以前にキャッシュに保存されたイメージ アクションを削除せずに、新しいアクションを system_server の既存の RemoteViews ツリーにマージします。完全な RemoteViews レイアウトを作成し、代わりに updateAppWidget を呼び出します。

  5. エラー フォールバック レイアウトを提供する: Jetpack Glance で onCompositionError をオーバーライドして、更新が失敗した場合にゼロビットマップの RemoteViews フォールバックをレンダリングします。

接続されているデバイスでウィジェットの現在のシリアル化されたビットマップ メモリ使用量を検査するには、次のコマンドを実行します。

adb shell dumpsys appwidget

コア機能

Android 17 には、Android システムのさまざまなコア機能を変更または拡張する、以下の変更が含まれています。

MessageQueue の新しいロックフリー実装

Android 17 以降、Android 17(API レベル 37)以降をターゲットとするアプリは、android.os.MessageQueue の新しいロックフリー実装を受け取ります。新しい実装では、パフォーマンスが向上し、フレームの欠落が減少しますが、MessageQueue のプライベート フィールドとメソッドを反映するクライアントが破損する可能性があります。

緩和戦略などの詳細については、MessageQueue の動作変更に関するガイダンスをご覧ください。

静的 final フィールドが変更不可に

Android 17(API レベル 37)以降をターゲットとする Android 17 以降で動作するアプリは、static final フィールドを変更できません。アプリがリフレクションを使用して static final フィールドを変更しようとすると、IllegalAccessException が発生します。JNI API(SetStaticLongField() など)を介してこれらのフィールドのいずれかを変更しようとすると、アプリがクラッシュします。

ユーザー補助

Android 17 では、ユーザー補助機能を改善するために次の変更が加えられています。

複雑な IME 物理キーボード入力のユーザー補助サポート

This feature introduces new AccessibilityEvent and TextAttribute APIs to enhance screen reader spoken feedback for CJKV language input. CJKV IME apps can now signal whether a text conversion candidate has been selected during text composition. Apps with edit fields can specify text change types when sending text changed accessibility events. For example, apps can specify that a text change occurred during text composition, or that a text change resulted from a commit. Doing this enables accessibility services such as screen readers to deliver more precise feedback based on the nature of the text modification.

App adoption

  • IME Apps: When setting composing text in edit fields, IMEs can use TextAttribute.Builder.setTextSuggestionSelected() to indicate whether a specific conversion candidate was selected.

  • Apps with Edit Fields: Apps that maintain a custom InputConnection can retrieve candidate selection data by calling TextAttribute.isTextSuggestionSelected(). These apps should then call AccessibilityEvent.setTextChangeTypes() when dispatching TYPE_VIEW_TEXT_CHANGED events. Apps targeting Android 17 (API level 37) that use the standard TextView will have this feature enabled by default. (That is, TextView will handle retrieving data from the IME and setting text change types when sending events to accessibility services).

  • Accessibility Services: Accessibility services that process TYPE_VIEW_TEXT_CHANGED events can call AccessibilityEvent.getTextChangeTypes() to identify the nature of the modification and adjust their feedback strategies accordingly.

プライバシー

Android 17 では、ユーザーのプライバシーを強化するために、次の変更が加えられています。

ECH(Encrypted Client Hello)が有効

Android 17 では、Encrypted Client Hello(ECH)のプラットフォーム サポートが導入されています。ECH は、TLS handshake で Server Name Indication(SNI)を暗号化することで、ユーザーのプライバシーを強化する TLS 拡張機能です。この暗号化により、ネットワーク監視者がアプリの接続先である特定のドメインを簡単に特定できなくなります。

Android 17(API レベル 37)以降をターゲットとするアプリの場合、TLS 接続に ECH が使用されます。ECH は、アプリで使用されるネットワーキング ライブラリ(HttpEngine、WebView、OkHttp など)に ECH サポートが統合されており、リモート サーバーも ECH プロトコルをサポートしている場合にのみ有効になります。ECH をネゴシエートできない場合、クライアントはランダム化されたコンテンツを含む ECH 拡張機能を送信します(ECH GREASE と呼ばれるメカニズム)。ECH GREASE の仕組みについて詳しくは、RFC 9849 をご覧ください。

アプリでこの動作をカスタマイズできるように、Android 17 ではネットワーク セキュリティ構成ファイルに新しい <domainEncryption> 要素が追加されています。デベロッパーは、<base-config> タグまたは <domain-config> タグ内で <domainEncryption> を使用して、グローバルまたはドメインごとに ECH モード("enabled" や "disabled" など)を選択できます。

詳細については、Encrypted Client Hello のドキュメントをご覧ください。

Android 17 をターゲットとするアプリに必要なローカル ネットワーク権限

Android 17 では、不正なローカル ネットワーク アクセスからユーザーを保護するために、ACCESS_LOCAL_NETWORK 実行時の権限が導入されています。これは既存の NEARBY_DEVICES 権限グループに該当するため、他の NEARBY_DEVICES 権限をすでに付与しているユーザーには、再度プロンプトが表示されることはありません。この新しい要件により、悪意のあるアプリが制限のないローカル ネットワーク アクセスを悪用して、ユーザーの追跡やフィンガープリントを密かに行うことを防ぎます。この権限を宣言してリクエストすることで、アプリはスマートホーム デバイスやキャスト レシーバーなどのローカル エリア ネットワーク(LAN)上のデバイスを検出して接続できるようになります。

Android 17(API レベル 37)以降をターゲットとするアプリには、LAN デバイスとの通信を維持するための 2 つのパスがあります。システムを介したプライバシー保護デバイス選択ツールを採用して権限プロンプトをスキップするか、実行時にこの新しい権限を明示的にリクエストしてローカル ネットワーク通信を維持します。

詳細については、ローカル ネットワークの権限に関するドキュメントをご覧ください。

実機でパスワードを非表示にする

If an app targets Android 17 (API level 37) or higher and the user is using a physical input device (for example, an external keyboard), the Android operating system applies the new show_passwords_physical setting to all characters in the password field. By default, that setting hides all password characters.

The Android system shows the last-typed password character to help the user see if they mistyped the password. However, this is much less necessary with larger external keyboards. In addition, devices with external keyboards often have larger displays, which increases the danger of someone seeing the typed password.

If the user is using the device's touchscreen, the system applies the new show_passwords_touch setting.

標準の SMS メッセージの OTP 保護

Android 17 以降、Android は SMS OTP 保護を拡張し、標準の SMS メッセージ(WebOTP 形式または SMS Retriever 形式を使用しない OTP を含む SMS メッセージ)に適用します。Android 17(API レベル 37)以降をターゲットとするほとんどのアプリでは、これらの SMS メッセージは受信から 3 時間経過するまで利用できません。この遅延は、OTP のハイジャックを防ぐことを目的としています。この 3 時間の遅延の間、SMS_RECEIVED_ACTION ブロードキャストは保留され、SMS プロバイダのデータベース クエリはフィルタされます。SMS メッセージは、遅延後にこれらのアプリで利用できるようになります。

デフォルトの SMS アシスタント アプリ、接続済みデバイスのコンパニオン アプリなど、特定のアプリはこの遅延の対象外となります。OTP 抽出のために SMS メッセージの読み取りに依存しているすべてのアプリは、SMS Retriever API または SMS User Consent API を使用するように移行して、機能が継続されるようにする必要があります。

セキュリティ

Android 17 では、デバイスとアプリのセキュリティが次のように改善されています。

アクティビティのセキュリティ

Android 17 では、プラットフォームが「デフォルトで保護」アーキテクチャに移行し、フィッシング、インタラクション ハイジャック、混乱した代理攻撃などの重大度の高いエクスプロイトを軽減するように設計された一連の機能強化が導入されています。このアップデートでは、アプリの互換性とユーザー保護を維持するために、デベロッパーが新しいセキュリティ標準を明示的に有効にする必要があります。

デベロッパーへの主な影響は次のとおりです。

  • BAL の強化とオプトインの改善: バックグラウンド アクティビティの起動(BAL)の制限を改良し、IntentSender に保護を拡張しています。デベロッパーは、以前の MODE_BACKGROUND_ACTIVITY_START_ALLOWED 定数から移行する必要があります。代わりに、MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE などのきめ細かい制御を採用する必要があります。これにより、アクティビティの開始を呼び出し元アプリが表示されているシナリオに制限し、攻撃対象領域を大幅に縮小できます。
  • 導入ツール: デベロッパーは、厳格モードと更新された lint チェックを利用して、以前のパターンを特定し、将来のターゲット SDK 要件に備える必要があります。

CT をデフォルトで有効にする

Android 17(API レベル 37)以降をターゲットとするアプリの場合、Certificate Transparency(CT)がデフォルトで有効になります。(Android 16 では、CT は利用可能ですが、アプリはオプトインする必要がありました)。

より安全なネイティブ DCL - C

アプリが Android 17(API レベル 37)以降をターゲットとしている場合、Android 14 で DEX ファイルと JAR ファイルに導入された、より安全な動的コード読み込み(DCL)保護がネイティブ ライブラリにも適用されるようになりました。

System.load() を使用して読み込まれるすべてのネイティブ ファイルは、読み取り専用としてマークする必要があります。そうしないと、システムは UnsatisfiedLinkError をスローします。

アプリでは可能な限り、コードを動的に読み込まないようにすることをおすすめします。コードを動的に読み込むと、コード インジェクションやコードの改ざんによってアプリが不正使用されるリスクが大幅に高まります。

CP2 データビューで PII フィールドを制限する

Android 17(API レベル 37)以降をターゲットとするアプリの場合、連絡先プロバイダ 2(CP2)は、個人を特定できる情報(PII)を含む特定の列をデータビューから制限します。この変更が有効になると、ユーザーのプライバシーを強化するために、これらの列がデータビューから削除されます。制限付きの列は次のとおりです。

ContactsContract.Data のこれらの列を使用しているアプリは、RAW_CONTACT_ID と結合することで、代わりに ContactsContract.RawContacts から抽出できます。

CP2 で厳格な SQL チェックを適用する

For apps targeting Android 17 (API level 37) and higher, Contacts Provider 2 (CP2) enforces strict SQL query validation when the ContactsContract.Data table is accessed without READ_CONTACTS permission.

With this change, if an app doesn't have READ_CONTACTS permission, StrictColumns and StrictGrammar options are set when querying the ContactsContract.Data table. If a query uses a pattern that isn't compatible with these, it will be rejected and cause an exception to be thrown.

インテリジェンス

Android 17 では、システム インテリジェンスに次の変更が加えられています。

setContentCaptureEnabled のサポート終了

コンテンツ キャプチャは、特定のデバイスでデフォルトで有効になっており、オンデバイス AI 機能が画面コンテンツを分析してインテリジェントなエクスペリエンスを提供できるようにします。

Android 17 以降、ContentCaptureManager.setContentCaptureEnabled(boolean) API メソッドは非推奨になりました。Android 17(API レベル 37)以降をターゲットとするアプリの場合、setContentCaptureEnabled(false) を呼び出してもコンテンツ キャプチャが無効にならなくなりました。

アプリで引き続きコンテンツ キャプチャを無効にする必要がある場合や、画面コンテンツがシステムによってキャプチャされないように制限する必要がある場合は、FLAG_SECURE ウィンドウ レイアウト パラメータを使用するように移行する必要があります。

コンテンツ キャプチャを無効にするには、次の例に示すように、ウィンドウに FLAG_SECURE フラグを設定します。

Kotlin

window.setFlags(
    WindowManager.LayoutParams.FLAG_SECURE,
    WindowManager.LayoutParams.FLAG_SECURE
)

Java

getWindow().setFlags(
    WindowManager.LayoutParams.FLAG_SECURE,
    WindowManager.LayoutParams.FLAG_SECURE
);

詳細については、WindowManager.LayoutParams.FLAG_SECURE リファレンス ドキュメントをご覧ください。

メディア

Android 17 では、メディアの動作に次の変更が加えられています。

バックグラウンド音声の強化

Android 17 以降、オーディオ フレームワークは、オーディオ再生、オーディオ フォーカス リクエスト、音量変更 API などのバックグラウンド オーディオ インタラクションに制限を適用し、これらの変更がユーザーによって意図的に開始されるようにします。

一部のオーディオ制限はすべてのアプリに適用されます。ただし、アプリが Android 17(API レベル 37)をターゲットとしている場合は、制限がより厳しくなります。これらのアプリのいずれかがバックグラウンドでオーディオを操作する場合は、フォアグラウンド サービスを実行する必要があります。さらに、アプリは次の要件のいずれかまたは両方を満たす必要があります。

  • フォアグラウンド サービスには、使用中(WIU)機能が必要です。
  • アプリに正確なアラームの権限があり、USAGE_ALARM 音声ストリームを操作している。

緩和戦略などの詳細については、バックグラウンド オーディオの強化をご覧ください。

デバイスのフォーム ファクタ

Android 17 には、さまざまなデバイスサイズとフォーム ファクタでユーザー エクスペリエンスを向上させるための、以下の変更が含まれています。

大画面(sw>=600dp)で画面の向き、サイズ変更、アスペクト比の制約を無視するようにプラットフォーム API を変更

Android 16 では、対象 API レベル 36 以降をターゲットとするアプリに対して、大画面(sw >= 600dp)での画面の向き、サイズ変更、アスペクト比の制限を無視するようにプラットフォーム API が変更されました。デベロッパーは SDK 36 でこれらの変更をオプトアウトできますが、Android 17(API レベル 37)以降をターゲットとするアプリでは、このオプトアウトは利用できなくなります。

詳細については、向きとサイズ変更の制限が無視されるをご覧ください。

接続

Android 17 では、Bluetooth RFCOMM ソケットの標準的な Java InputStream 動作との整合性を高めるため、以下の変更が導入されています。

RFCOMM の一貫した BluetoothSocket read() 動作

Android 17(API レベル 37)をターゲットとするアプリでは、RFCOMM ベースの BluetoothSocket から取得した InputStream の read() メソッドは、ソケットが閉じられたとき、または接続が切断されたときに -1 を返すようになりました。

この変更により、RFCOMM ソケットの動作が LE CoC ソケットと整合し、ストリームの終わりに達すると -1 が返されるという標準の InputStream.read() ドキュメントに沿った動作になります。

IOException をキャッチして読み取りループを抜けることにのみ依存しているアプリは、この変更の影響を受ける可能性があります。BluetoothSocket の読み取りループを更新して、戻り値が -1 であることを明示的に確認する必要があります。これにより、リモート デバイスが切断されたとき、またはソケットが閉じられたときに、ループが正しく終了します。推奨される実装の例については、Bluetooth データを転送するガイドのコード スニペットをご覧ください。