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

以前のリリースと同様に、Android 14 にはアプリに影響する可能性のある動作変更が含まれています。以下の動作変更は、Android 14(API レベル 34)以降をターゲットとするアプリにのみ適用されます。Android 14 以降をターゲットとするアプリについては、必要に応じてアプリを変更して、下記の動作に適切に対応できるようにしてください。

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

コア機能

フォアグラウンド サービス タイプは必須

如果您的应用以 Android 14(API 级别 34)或更高版本为目标平台,则必须为应用中的每项前台服务指定至少一个前台服务类型。您应该选择一个能够代表应用用例的前台服务类型。系统需要特定类型的前台服务满足特定用例。

如果应用中的用例与这些类型均不相关,强烈建议您迁移逻辑以使用 WorkManager用户发起的数据传输作业

BluetoothAdapter での BLUETOOTH_CONNECT 権限の適用

Android 14 enforces the BLUETOOTH_CONNECT permission when calling the BluetoothAdapter getProfileConnectionState() method for apps targeting Android 14 (API level 34) or higher.

This method already required the BLUETOOTH_CONNECT permission, but it was not enforced. Make sure your app declares BLUETOOTH_CONNECT in your app's AndroidManifest.xml file as shown in the following snippet and check that a user has granted the permission before calling 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 をトリガーします。非同期処理をサポートするか、負荷の高い作業をバックグラウンド スレッドに移行する WorkManager への移行を検討してください。

JobScheduler では、setRequiredNetworkType または setRequiredNetwork の制約を使用する場合に、ACCESS_NETWORK_STATE 権限を宣言する要件も導入されます。ジョブのスケジュール時にアプリが ACCESS_NETWORK_STATE 権限を宣言せず、Android 14 以降をターゲットとしている場合、SecurityException が発生します。

ユーザー エクスペリエンス

安全な全画面インテント通知

在 Android 11(API 级别 30)中,任何应用都可以在手机处于锁定状态时使用 Notification.Builder.setFullScreenIntent 发送全屏 intent。您可以通过在 AndroidManifest 中声明 USE_FULL_SCREEN_INTENT 权限,在应用安装时自动授予此权限。

全屏 intent 通知适用于需要用户立即注意的极高优先级通知,例如用户来电或用户配置的闹钟设置。对于以 Android 14(API 级别 34)或更高版本为目标平台的应用,获准使用此权限的应用仅限于提供通话和闹钟的应用。对于不适合此资料的任何应用,Google Play 商店会撤消其默认的 USE_FULL_SCREEN_INTENT 权限。这些政策变更的截止日期为 2024 年 5 月 31 日

在用户更新到 Android 14 之前,在手机上安装的应用仍拥有此权限。用户可以开启和关闭此权限。

您可以使用新 API NotificationManager.canUseFullScreenIntent 检查应用是否具有该权限;如果没有,应用可以使用新 intent ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT 启动设置页面,在该页面中,用户可以授予权限。

セキュリティ

暗黙的インテントとペンディング インテントの制限

对于以 Android 14(API 级别 34)或更高版本为目标平台的应用,Android 会通过以下方式限制应用向内部应用组件发送隐式 intent:

  • 隐式 intent 只能传送到导出的组件。应用必须使用显式 intent 传送到未导出的组件,或将该组件标记为已导出。
  • 如果应用通过未指定组件或软件包的 intent 创建可变待处理 intent,系统会抛出异常。

这些变更可防止恶意应用拦截意在供应用内部组件使用的隐式 intent。

例如,下面是可以在应用的清单文件中声明的 intent 过滤器

<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>

如果应用尝试使用隐式 intent 启动此 activity,则系统会抛出异常:

Kotlin

// Throws an exception when targeting Android 14.
context.startActivity(Intent("com.example.action.APP_ACTION"))

Java

// Throws an exception when targeting Android 14.
context.startActivity(new Intent("com.example.action.APP_ACTION"));

如需启动非导出的 activity,应用应改用显式 intent:

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_EXPORTEDRECEIVER_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)或更高版本为目标平台的应用,系统会进一步限制允许应用何时从后台启动 activity:

这些变更扩展了一组现有限制,以防止恶意应用滥用 API 以在后台启动干扰性活动,从而保护用户。

zip パス トラバーサル

Android 14(API レベル 34)以降をターゲットとするアプリの場合、Android は次の方法で ZIP パス トラバーサルの脆弱性を回避します。ZIP ファイルのエントリ名に「..」が含まれるか「/」で始まる場合、ZipFile(String)ZipInputStream.getNextEntry()ZipException をスローします。

アプリは dalvik.system.ZipPathValidator.clearCallback() を呼び出すことで、この検証をオプトアウトできます。

对于以 Android 14(API 级别 34)或更高版本为目标平台的应用,在以下任一情况下,MediaProjection#createVirtualDisplay 会抛出 SecurityException

您的应用必须在每次捕获会话之前征求用户同意。单次拍摄会话是指对 MediaProjection#createVirtualDisplay 的单次调用,且每个 MediaProjection 实例只能使用一次。

处理配置变更

如果您的应用需要调用 MediaProjection#createVirtualDisplay 来处理配置更改(例如屏幕方向或屏幕尺寸更改),您可以按照以下步骤更新现有 MediaProjection 实例的 VirtualDisplay

  1. 使用新的宽度和高度调用 VirtualDisplay#resize
  2. VirtualDisplay#setSurface 提供具有新宽度和高度的新 Surface

注册回调

您的应用应注册一个回调,以处理用户不同意继续拍摄会话的情况。为此,请实现 Callback#onStop 并让您的应用发布所有相关资源(例如 VirtualDisplaySurface)。

如果您的应用未注册此回调,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 インターフェースの制限をご覧ください。