これまでのリリースと同様、Android 14 には、アプリに影響する可能性がある動作変更が含まれています。下記の動作変更は、Android 14(API レベル 34)以上をターゲットとするアプリにのみ適用されます。アプリが Android 14 以上をターゲットとする場合は、必要に応じてアプリを変更し、下記の動作に適切に対応できるようにしてください。
アプリの targetSdkVersion
に関係なく、Android 14 で実行されるすべてのアプリに影響する動作変更のリストも必ずご確認ください。
コア機能
フォアグラウンド サービス タイプは必須
Android 14(API レベル 34)以降をターゲットとするアプリの場合は、アプリ内のフォアグラウンド サービスごとにフォアグラウンド サービス タイプを 1 つ以上指定する必要があります。フォアグラウンド サービスのタイプには、アプリのユースケースを表すものを選択する必要があります。システムは、特定のタイプのフォアグラウンド サービスが特定のユースケースを満たすことを想定しています。
アプリのユースケースがこれらのタイプのいずれにも関連していない場合は、WorkManager またはユーザーが開始するデータ転送ジョブを使用するようにロジックを移行することを強くおすすめします。
BluetoothAdapter での BLUETOOTH_CONNECT 権限の適用
Android 14 では、Android 14(API レベル 34)以降をターゲットとするアプリで BluetoothAdapter
getProfileConnectionState()
メソッドを呼び出すときに、BLUETOOTH_CONNECT
権限が適用されます。
このメソッドにはすでに BLUETOOTH_CONNECT
権限が必要でしたが、適用されていませんでした。次のスニペットに示すように、アプリの AndroidManifest.xml
ファイルで BLUETOOTH_CONNECT
を宣言し、getProfileConnectionState
を呼び出す前にユーザーが権限を付与していることを確認します。
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
OpenJDK 17 の更新
Android 14 では、最新の OpenJDK LTS リリースの機能に合わせて Android のコアライブラリを更新する取り組みが引き続き行われています。これには、アプリ デベロッパーとプラットフォーム デベロッパー向けのライブラリの更新と Java 17 言語のサポートが含まれます。
これらの変更のいくつかは、アプリの互換性に影響する可能性があります。
- 正規表現の変更: 無効なグループ参照は、OpenJDK のセマンティクスに厳密に従うことができなくなりました。
java.util.regex.Matcher
クラスがIllegalArgumentException
をスローする新しいケースが発生する可能性があるため、正規表現を使用する領域について必ずアプリのテストを行ってください。テスト中にこの変更を有効または無効にするには、互換性フレームワーク ツールを使用してDISALLOW_INVALID_GROUP_REFERENCE
フラグを切り替えます。 - UUID 処理:
java.util.UUID.fromString()
メソッドで入力引数を検証する際に、より厳格なチェックが行われるようになりました。これにより、シリアル化解除中にIllegalArgumentException
が表示される場合があります。テスト中にこの変更を有効または無効にするには、互換性フレームワーク ツールを使用してENABLE_STRICT_VALIDATION
フラグを切り替えます。 - ProGuard の問題:
java.lang.ClassValue
クラスの追加により、ProGuard を使用するアプリの圧縮、難読化、最適化をしようとすると問題が発生することがあります。この問題は、Class.forName("java.lang.ClassValue")
がクラスを返すかどうかに基づいてランタイムの動作を変更する Kotlin ライブラリに起因します。java.lang.ClassValue
クラスを利用できない古いバージョンのランタイムを対象にアプリが開発されている場合、これらの最適化により、java.lang.ClassValue
から派生したクラスからcomputeValue
メソッドが削除されることがあります。
JobScheduler がコールバックとネットワークの動作を強化
JobScheduler の導入以来、アプリは onStartJob
または onStopJob
から数秒以内に戻ることが想定されています。Android 14 より前のバージョンでは、
ジョブの実行時間が長すぎると、ジョブは停止し、通知なく失敗します。
アプリが Android 14(API レベル 34)以降をターゲットとし、メインスレッドで許可された時間が超過すると、アプリは「onStartJob
への応答なし」または「onStopJob
への応答なし」というエラー メッセージとともに ANR をトリガーします。
この ANR は、次の 2 つのシナリオの結果である可能性があります。
1. メインスレッドをブロックする処理があり、コールバック onStartJob
または onStopJob
が想定された時間制限内に実行されず、完了しません。2. デベロッパーが JobScheduler コールバック onStartJob
または onStopJob
内でブロッキング処理を実行しているため、コールバックが想定された制限時間内に完了していません。
1 の問題に対処するには、メインスレッドをブロックしているものをさらにデバッグする必要があります。
アラートのタイムスタンプを
ApplicationExitInfo#getTraceInputStream()
: tombstone を取得します
トレースをトリガーできますANR を手動で再現できる場合は
システム トレースを記録し、次のいずれかの方法でトレースを検査できます。
Android Studio または Perfetto を使用して、何が
メインスレッドで待機します。
これは、JobScheduler API を直接使用する場合や、androidx ライブラリの WorkManager を使用する場合に発生する可能性があります。
2 に対処するには、WorkManager への移行を検討してください。
onStartJob
または onStopJob
での処理をラップするためのサポート
呼び出されることがあります
JobScheduler
には、サービス アカウント キーの
ACCESS_NETWORK_STATE
権限(setRequiredNetworkType
または
setRequiredNetwork
制約。アプリがジョブのスケジュール設定時に ACCESS_NETWORK_STATE
権限を宣言しておらず、Android 14 以降をターゲットとしている場合、SecurityException
が発生します。
Tiles launch API
Android 14 以降をターゲットとするアプリの場合、TileService#startActivityAndCollapse(Intent)
のサポートが終了し、呼び出されると例外がスローされるようになりました。アプリがタイルからアクティビティを起動する場合は、代わりに TileService#startActivityAndCollapse(PendingIntent)
を使用してください。
プライバシー
写真と動画への部分的なアクセス
Android 14 引入了所选照片访问权限,可让用户授权应用访问其媒体库中的特定图片和视频,而不是授予对指定类型的所有媒体的访问权限。
仅当您的应用以 Android 14(API 级别 34)或更高版本为目标平台时,才会启用此变更。如果您还没有使用照片选择器,建议您在应用中实现该选择器,以便在选择图片和视频时提供一致的体验,同时还可以加强用户隐私保护,而无需请求任何存储权限。
如果您使用存储权限维护自己的图库选择器,并且需要完全控制您的实现,请调整您的实现,以使用新的 READ_MEDIA_VISUAL_USER_SELECTED
权限。如果您的应用不使用新权限,系统会在兼容模式下运行应用。
ユーザー エクスペリエンス
全画面インテントの通知を保護する
Android 11(API レベル 30)では、どのアプリでも、スマートフォンがロックされているときに Notification.Builder.setFullScreenIntent
を使用して全画面インテントを送信することができました。AndroidManifest で USE_FULL_SCREEN_INTENT
権限を宣言することで、アプリのインストール時にこの権限を自動的に付与できます。
全画面表示のインテント通知は、着信やユーザー設定によるアラームなど、ユーザーがすぐに確認する必要がある非常に優先度の高い通知向けに設計されています。Android 14(API レベル 34)以降をターゲットとするアプリの場合、この権限の使用が許可されるアプリは、通話とアラームのみを提供するアプリに限定されます。Google Play ストアでは、このプロファイルに一致しないアプリのデフォルトの USE_FULL_SCREEN_INTENT
権限が取り消されます。ポリシー変更の期限は 2024 年 5 月 31 日です。
ユーザーが Android 14 にアップデートする前にスマートフォンにインストールしていたアプリについては、この権限は有効なままになります。ユーザーはこの権限のオンとオフを切り替えることができます。
新しい API の NotificationManager.canUseFullScreenIntent
を使用して、アプリに権限があるかどうかを確認できます。権限がない場合、アプリは新しいインテント ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT
を使用して、ユーザーが権限を付与できる設定ページを起動できます。
セキュリティ
暗黙的インテントとペンディング インテントの制限
Android 14(API レベル 34)以降をターゲットとするアプリの場合、Android は、アプリが内部アプリ コンポーネントに暗黙的インテントを送信することを次の方法で制限します。
- 暗黙的インテントは、エクスポートされたコンポーネントにのみ配信されます。アプリは、明示的インテントを使用してエクスポートされていないコンポーネントに配信するか、コンポーネントをエクスポート済みとしてマークする必要があります。
- アプリがコンポーネントまたはパッケージを指定しないインテントで可変ペンディング インテントを作成した場合、システムは例外をスローするようになりました。
この変更により、アプリの内部コンポーネントによる使用を目的とした暗黙的インテントを、悪意のあるアプリがインターセプトするのを防ぐことができます。
たとえば、アプリのマニフェスト ファイルで宣言できるインテント フィルタは次のようになります。
<activity
android:name=".AppActivity"
android:exported="false">
<intent-filter>
<action android:name="com.example.action.APP_ACTION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
アプリが暗黙的インテントを使用してこのアクティビティを起動しようとすると、ActivityNotFoundException
例外がスローされます。
Kotlin
// Throws an ActivityNotFoundException exception when targeting Android 14. context.startActivity(Intent("com.example.action.APP_ACTION"))
Java
// Throws an ActivityNotFoundException exception when targeting Android 14. context.startActivity(new Intent("com.example.action.APP_ACTION"));
エクスポートされていないアクティビティをアプリが起動するには、代わりに明示的インテントを使用する必要があります。
Kotlin
// This makes the intent explicit. val explicitIntent = Intent("com.example.action.APP_ACTION") explicitIntent.apply { package = context.packageName } context.startActivity(explicitIntent)
Java
// This makes the intent explicit. Intent explicitIntent = new Intent("com.example.action.APP_ACTION") explicitIntent.setPackage(context.getPackageName()); context.startActivity(explicitIntent);
実行時に登録されるブロードキャスト レシーバでは、エクスポート動作を指定する必要がある
Android 14(API レベル 34)以降をターゲットとし、コンテキスト登録されたレシーバを使用するアプリとサービスでは、レシーバをデバイス上のすべてのアプリにエクスポートするかどうかを示すフラグ(それぞれ RECEIVER_EXPORTED
または RECEIVER_NOT_EXPORTED
)を指定する必要があります。この要件は、Android 13 で導入されたこれらのレシーバー用の機能を利用して、アプリをセキュリティの脆弱性から保護するのに役立ちます。
システム ブロードキャストのみを受信するレシーバの例外
アプリが Context#registerReceiver()
などの Context#registerReceiver
メソッドを介してシステム ブロードキャストのレシーバのみを登録する場合は、レシーバの登録時にフラグを指定しないでください。
動的コードの読み込みの安全性を改善
アプリが Android 14(API レベル 34)以降をターゲットとし、動的コードの読み込み(DCL)を使用している場合、動的に読み込まれるファイルはすべて読み取り専用としてマークする必要があります。そうしないと、システムは例外をスローします。アプリでは可能な限り、コードを動的に読み込まないようにすることをおすすめします。コードを動的に読み込むと、コード インジェクションやコードの改ざんによってアプリが不正使用されるリスクが大幅に高まります。
コードを動的に読み込む必要がある場合は、次の方法を使用して、ファイルを開いた直後、コンテンツが書き込まれる前に、動的読み込みファイル(DEX、JAR、APK ファイルなど)を読み取り専用ファイルとして設定します。
Kotlin
val jar = File("DYNAMICALLY_LOADED_FILE.jar") val os = FileOutputStream(jar) os.use { // Set the file to read-only first to prevent race conditions jar.setReadOnly() // Then write the actual file content } val cl = PathClassLoader(jar, parentClassLoader)
Java
File jar = new File("DYNAMICALLY_LOADED_FILE.jar"); try (FileOutputStream os = new FileOutputStream(jar)) { // Set the file to read-only first to prevent race conditions jar.setReadOnly(); // Then write the actual file content } catch (IOException e) { ... } PathClassLoader cl = new PathClassLoader(jar, parentClassLoader);
既存の動的読み込みファイルを処理する
既存の動的読み込みファイルに対して例外がスローされないようにするには、ファイルを削除して再作成してから、アプリでファイルを動的に読み込み直すことをおすすめします。ファイルを再作成するときは、上記のガイダンスに沿って書き込み時にファイルを読み取り専用としてマークしてください。既存のファイルに読み取り専用として再度ラベルを付けることもできますが、その場合は、信頼できる値に照らしてファイルの署名を確認するなど、最初にファイルの整合性を確認することを強くおすすめします。これにより、悪意のあるアクションからアプリを保護できます。
バックグラウンドからのアクティビティの起動に関する追加の制限
Android 14(API レベル 34)以上をターゲットとするアプリでは、アプリがバックグラウンドからアクティビティを開始できるタイミングがさらに制限されます。
- アプリが
PendingIntent#send()
などのメソッドを使用してPendingIntent
を送信する際、自身のバックグラウンド アクティビティを開始する権限を付与してペンディング インテントを開始する場合、オプトインが必須になりました。オプトインするには、アプリでsetPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
を含むActivityOptions
バンドルを渡す必要があります。 - 可視アプリが、バックグラウンドにある別のアプリのサービスをバインドしている場合
bindService()
メソッドを使用するため、表示されるアプリで 固有のバックグラウンド アクティビティの起動権限を バインドされたサービスになります。オプトインするには、アプリにBIND_ALLOW_ACTIVITY_STARTS
フラグ(bindService()
メソッドを使用します。
これらの変更により、既存の制限セットが拡張され、 悪意のあるアプリが API を悪用して破壊的な活動を開始するのを防ぐことで、 バックグラウンドから移行できます。
zip パス トラバーサル
Android 14(API レベル 34)以降をターゲットとするアプリの場合、Android は次の方法で ZIP パス トラバーサルの脆弱性を回避します。ZIP ファイルのエントリ名に「..」が含まれるか「/」で始まる場合、ZipFile(String)
と ZipInputStream.getNextEntry()
は ZipException
をスローします。
アプリは dalvik.system.ZipPathValidator.clearCallback()
を呼び出すことで、この検証をオプトアウトできます。
MediaProjection キャプチャ セッションごとにユーザーの同意が必要
Android 14(API レベル 34)以降をターゲットとするアプリでは、次のいずれかのシナリオにおいて SecurityException
が MediaProjection#createVirtualDisplay
によってスローされます。
- アプリは、
MediaProjectionManager#createScreenCaptureIntent
から返されたIntent
をキャッシュに保存し、MediaProjectionManager#getMediaProjection
に複数回渡します。 - アプリが同じ
MediaProjection
インスタンスでMediaProjection#createVirtualDisplay
を複数回呼び出している。
アプリは、各キャプチャ セッションの前にユーザーに同意を求める必要があります。単一キャプチャ セッションは、MediaProjection#createVirtualDisplay
に対する 1 回の呼び出しです。各 MediaProjection
インスタンスは 1 回だけ使用する必要があります。
構成の変更に対処する
アプリで構成の変更(画面の向きや画面サイズの変更など)を処理するために MediaProjection#createVirtualDisplay
を呼び出す必要がある場合は、次の手順で既存の MediaProjection
インスタンスの VirtualDisplay
を更新できます。
- 新しい幅と高さで
VirtualDisplay#resize
を呼び出します。 - 新しい幅と高さが設定された新しい
Surface
をVirtualDisplay#setSurface
に指定します。
コールバックを登録する
アプリはコールバックを登録して、ユーザーがキャプチャ セッションの続行に同意しない場合に対処する必要があります。そのためには、Callback#onStop
を実装し、アプリで関連リソース(VirtualDisplay
や Surface
など)を解放します。
アプリがこのコールバックを登録しない場合、MediaProjection#createVirtualDisplay
は、アプリがこのコールバックを呼び出したときに IllegalStateException
をスローします。
非 SDK の制限の更新
Android 14 では、Android デベロッパーの協力と直近の内部テストに基づいて、制限を受ける非 SDK インターフェースのリストが更新されています。Google は、非 SDK インターフェースを制限する前に、可能な限り、その代わりとなる公開インターフェースを利用可能にしています。
Android 14 をターゲットとしないアプリでは、この変更の一部はすぐには影響しない可能性があります。ただし、現時点で(アプリのターゲット API レベルに応じて)一部の非 SDK インターフェースを利用できていても、非 SDK のメソッドまたはフィールドをそのまま使用し続けると、将来的にアプリが機能しなくなるリスクが高くなります。
アプリが非 SDK インターフェースを使用しているかどうか不明な場合は、アプリをテストして確認できます。アプリが非 SDK インターフェースに依存している場合は、SDK の代替インターフェースへの移行を計画してください。ただし Google も、一部のアプリには非 SDK インターフェースを使用する正当なユースケースがあると承知しています。アプリの機能に使用している非 SDK インターフェースの代わりが見つからない場合は、新しい公開 API をリクエストしてください。
Android の今回のリリースの変更について詳しくは、非 SDK インターフェースの制限に関する Android 14 での変更点をご覧ください。非 SDK インターフェース全般について詳しくは、非 SDK インターフェースの制限をご覧ください。