これまでのリリースと同様、Android 14 には、アプリに影響する可能性がある動作変更が含まれています。下記の動作変更は、Android 14(API レベル 34)以上をターゲットとするアプリにのみ適用されます。アプリが Android 14 以上をターゲットとする場合は、必要に応じてアプリを変更し、下記の動作に適切に対応できるようにしてください。
アプリの targetSdkVersion
に関係なく、Android 14 で実行されるすべてのアプリに影響する動作変更のリストも必ずご確認ください。
コア機能
フォアグラウンド サービス タイプは必須
If your app targets Android 14 (API level 34) or higher, it must specify at least one foreground service type for each foreground service within your app. You should choose a foreground service type that represents your app's use case. The system expects foreground services that have a particular type to satisfy a particular use case.
If a use case in your app isn't associated with any of these types, it's strongly recommended that you migrate your logic to use WorkManager or user-initiated data transfer jobs.
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 では、Selected Photos Access が導入され、特定のタイプのすべてのメディアへのアクセス権を付与するのではなく、ライブラリ内の特定の画像および動画へのアクセス権をアプリに付与できるようになりました。
この変更は、アプリが Android 14(API レベル 34)以降をターゲットとする場合にのみ有効になります。写真選択ツールをまだ使用していない場合は、アプリに実装して、ストレージの権限をリクエストしなくても、画像や動画を選択する際に一貫性のあるエクスペリエンスを提供することをおすすめします。これにより、ユーザーのプライバシーも強化されます。
ストレージの権限を使用して独自のギャラリー選択ツールを管理しており、実装を完全に制御する必要がある場合は、新しい READ_MEDIA_VISUAL_USER_SELECTED
権限を使用するように実装を調整します。アプリが新しい権限を使用しない場合、システムはアプリを互換モードで実行します。
ユーザー エクスペリエンス
全画面インテントの通知を保護する
With Android 11 (API level 30), it was possible for any app to use
Notification.Builder.setFullScreenIntent
to send full-screen
intents while the phone is locked. You could auto-grant this on app install by
declaring USE_FULL_SCREEN_INTENT
permission in the
AndroidManifest.
Full-screen intent notifications are designed for extremely high-priority
notifications demanding the user's immediate attention, such as an incoming
phone call or alarm clock settings configured by the user. For apps targeting
Android 14 (API level 34) or higher, apps that are allowed to use this
permission are limited to those that provide calling and alarms only. The Google
Play Store revokes default USE_FULL_SCREEN_INTENT
permissions for any apps
that don't fit this profile. The deadline for these policy changes is May 31,
2024.
This permission remains enabled for apps installed on the phone before the user updates to Android 14. Users can turn this permission on and off.
You can use the new API
NotificationManager.canUseFullScreenIntent
to check if your app
has the permission; if not, your app can use the new intent
ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT
to launch the settings
page where users can grant the permission.
セキュリティ
暗黙的インテントとペンディング インテントの制限
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
メソッドを介してシステム ブロードキャストのレシーバのみを登録する場合は、レシーバの登録時にフラグを指定しないでください。
動的コードの読み込みの安全性を改善
If your app targets Android 14 (API level 34) or higher and uses Dynamic Code Loading (DCL), all dynamically-loaded files must be marked as read-only. Otherwise, the system throws an exception. We recommend that apps avoid dynamically loading code whenever possible, as doing so greatly increases the risk that an app can be compromised by code injection or code tampering.
If you must dynamically load code, use the following approach to set the dynamically-loaded file (such as a DEX, JAR, or APK file) as read-only as soon as the file is opened and before any content is written:
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);
Handle dynamically-loaded files that already exist
To prevent exceptions from being thrown for existing dynamically-loaded files, we recommend deleting and recreating the files before you try to dynamically load them again in your app. As you recreate the files, follow the preceding guidance for marking the files read-only at write time. Alternatively, you can re-label the existing files as read-only, but in this case, we strongly recommend that you verify the integrity of the files first (for example, by checking the file's signature against a trusted value), to help protect your app from malicious actions.
バックグラウンドからのアクティビティの起動に関する追加の制限
For apps targeting Android 14 (API level 34) or higher, the system further restricts when apps are allowed to start activities from the background:
- When an app sends a
PendingIntent
usingPendingIntent#send()
or similar methods, the app must opt in if it wants to grant its own background activity launch privileges to start the pending intent. To opt in, the app should pass anActivityOptions
bundle withsetPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
. - When a visible app binds a service of another app that's in the background
using the
bindService()
method, the visible app must now opt in if it wants to grant its own background activity launch privileges to the bound service. To opt in, the app should include theBIND_ALLOW_ACTIVITY_STARTS
flag when calling thebindService()
method.
These changes expand the existing set of restrictions to protect users by preventing malicious apps from abusing APIs to start disruptive activities from the background.
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 includes updated lists of restricted non-SDK interfaces based on collaboration with Android developers and the latest internal testing. Whenever possible, we make sure that public alternatives are available before we restrict non-SDK interfaces.
If your app does not target Android 14, some of these changes might not immediately affect you. However, while you can currently use some non-SDK interfaces (depending on your app's target API level), using any non-SDK method or field always carries a high risk of breaking your app.
If you are unsure if your app uses non-SDK interfaces, you can test your app to find out. If your app relies on non-SDK interfaces, you should begin planning a migration to SDK alternatives. Nevertheless, we understand that some apps have valid use cases for using non-SDK interfaces. If you cannot find an alternative to using a non-SDK interface for a feature in your app, you should request a new public API.
Android の今回のリリースの変更について詳しくは、非 SDK インターフェースの制限に関する Android 14 での変更点をご覧ください。非 SDK インターフェース全般について詳しくは、非 SDK インターフェースの制限をご覧ください。