これまでのリリースと同様、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 continues the work of refreshing Android's core libraries to align with the features in the latest OpenJDK LTS releases, including both library updates and Java 17 language support for app and platform developers.
A few of these changes can affect app compatibility:
- Changes to regular expressions: Invalid group references are now
disallowed to more closely follow the semantics of OpenJDK. You might see
new cases where an
IllegalArgumentExceptionis thrown by thejava.util.regex.Matcherclass, so make sure to test your app for areas that use regular expressions. To enable or disable this change while testing, toggle theDISALLOW_INVALID_GROUP_REFERENCEflag using the compatibility framework tools. - UUID handling: The
java.util.UUID.fromString()method now does more strict checks when validating the input argument, so you might see anIllegalArgumentExceptionduring deserialization. To enable or disable this change while testing, toggle theENABLE_STRICT_VALIDATIONflag using the compatibility framework tools. - ProGuard issues: In some cases, the addition of the
java.lang.ClassValueclass causes an issue if you try to shrink, obfuscate, and optimize your app using ProGuard. The problem originates with a Kotlin library that changes runtime behaviour based on whetherClass.forName("java.lang.ClassValue")returns a class or not. If your app was developed against an older version of the runtime without thejava.lang.ClassValueclass available, then these optimizations might remove thecomputeValuemethod from classes derived fromjava.lang.ClassValue.
JobScheduler がコールバックとネットワークの動作を強化
Since its introduction, JobScheduler expects your app to return from
onStartJob or onStopJob within a few seconds. Prior to Android 14,
if a job runs too long, the job is stopped and fails silently.
If your app targets Android 14 (API level 34) or higher and
exceeds the granted time on the main thread, the app triggers an ANR
with the error message "No response to onStartJob" or
"No response to onStopJob".
This ANR may be a result of 2 scenarios:
1. There is work blocking the main thread, preventing the callbacks onStartJob
or onStopJob from executing and completing within the expected time limit.
2. The developer is running blocking work within the JobScheduler
callback onStartJob or onStopJob, preventing the callback from
completing within the expected time limit.
To address #1, you will need to further debug what is blocking the main thread
when the ANR occurs, you can do this using
ApplicationExitInfo#getTraceInputStream() to get the tombstone
trace when the ANR occurs. If you're able to manually reproduce the ANR,
you can record a system trace and inspect the trace using either
Android Studio or Perfetto to better understand what is running on
the main thread when the ANR occurs.
Note that this can happen when using JobScheduler API directly
or using the androidx library WorkManager.
To address #2, consider migrating to WorkManager, which provides
support for wrapping any processing in onStartJob or onStopJob
in an asynchronous thread.
JobScheduler also introduces a requirement to declare the
ACCESS_NETWORK_STATE permission if using setRequiredNetworkType or
setRequiredNetwork constraint. If your app does not declare the
ACCESS_NETWORK_STATE permission when scheduling the job and is targeting
Android 14 or higher, it will result in a SecurityException.
Tiles のリリース 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);
実行時に登録されるブロードキャスト レシーバでは、エクスポート動作を指定する必要がある
Apps and services that target Android 14 (API level 34) or higher and use
context-registered receivers are required to specify a flag
to indicate whether or not the receiver should be exported to all other apps on
the device: either RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED, respectively.
This requirement helps protect apps from security vulnerabilities by leveraging
the features for these receivers introduced in Android 13.
Exception for receivers that receive only system broadcasts
If your app is registering a receiver only for
system broadcasts through Context#registerReceiver
methods, such as Context#registerReceiver(), then it
shouldn't specify a flag when registering the receiver.
動的コードの読み込みの安全性を改善
アプリが 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()メソッドを使用してバックグラウンドにある別のアプリのサービスをバインドする場合、バインドされたサービスに自身のバックグラウンド アクティビティを開始する権限を付与するには、表示されているアプリがオプトインする必要があります。アプリがオプトインするには、bindService()メソッドを呼び出す際にBIND_ALLOW_ACTIVITY_STARTSフラグを含める必要があります。
この変更により、既存の制限セットが拡張されるため、悪意のあるアプリが API を悪用してバックグラウンドで破壊的なアクティビティを開始することを防止し、ユーザーを保護できます。
zip パス トラバーサル
Android 14(API レベル 34)以降をターゲットとするアプリの場合、Android は zip パス トラバーサルの脆弱性を回避するために、zip ファイルのエントリ名に「..」が含まれる場合、またはエントリ名が「/」で始まる場合、ZipFile(String) と ZipInputStream.getNextEntry() は ZipException をスローします。
アプリは dalvik.system.ZipPathValidator.clearCallback() を呼び出すことで、この検証をオプトアウトできます。
MediaProjection キャプチャ セッションごとにユーザーの同意が必要
For apps targeting Android 14 (API level 34) or higher, a SecurityException is
thrown by MediaProjection#createVirtualDisplay in either of the following
scenarios:
- Your app caches the
Intentthat is returned fromMediaProjectionManager#createScreenCaptureIntent, and passes it multiple times toMediaProjectionManager#getMediaProjection. - Your app invokes
MediaProjection#createVirtualDisplaymultiple times on the sameMediaProjectioninstance.
Your app must ask the user to give consent before each capture session. A single
capture session is a single invocation on
MediaProjection#createVirtualDisplay, and each MediaProjection instance must
be used only once.
Handle configuration changes
If your app needs to invoke MediaProjection#createVirtualDisplay to handle
configuration changes (such as the screen orientation or screen size changing),
you can follow these steps to update the VirtualDisplay for the existing
MediaProjection instance:
- Invoke
VirtualDisplay#resizewith the new width and height. - Provide a new
Surfacewith the new width and height toVirtualDisplay#setSurface.
Register a callback
Your app should register a callback to handle cases where the user doesn't grant
consent to continue a capture session. To do this, implement
Callback#onStop and have your app release any related resources (such as
the VirtualDisplay and Surface).
If your app doesn't register this callback,
MediaProjection#createVirtualDisplay throws an IllegalStateException
when your app invokes it.
非 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 インターフェースの制限をご覧ください。