Änderungen beim Verhalten: Apps, die auf Android 14 oder höher ausgerichtet sind

Wie bei früheren Releases umfasst auch Android 14 Verhaltensänderungen, die sich auf deine App auswirken können. Die folgenden Änderungen gelten ausschließlich für Apps, die auf Android 14 (API-Level 34) oder höher ausgerichtet sind. Wenn Ihre App auf Android 14 oder höher ausgerichtet ist, sollten Sie sie gegebenenfalls so anpassen, dass diese Verhaltensweisen korrekt unterstützt werden.

Sieh dir unbedingt auch die Liste der Verhaltensänderungen an, die sich auf alle Apps unter Android 14 auswirken, unabhängig vom targetSdkVersion der App.

Hauptfunktion

Typen von Diensten im Vordergrund sind erforderlich

Wenn deine App auf Android 14 (API-Level 34) oder höher ausgerichtet ist, muss mindestens ein Diensttyp im Vordergrund für jeden Dienst im Vordergrund innerhalb deiner App angegeben werden. Du solltest einen Typ auswählen, der den Anwendungsfall deiner App im Vordergrund repräsentiert. Das System erwartet Dienste im Vordergrund eines bestimmten Typs, die einem bestimmten Anwendungsfall entsprechen.

Wenn ein Anwendungsfall in Ihrer Anwendung keinem dieser Typen zugeordnet ist, sollten Sie Ihre Logik auf die Verwendung von WorkManager oder vom Nutzer initiierten Datenübertragungsjobs migrieren.

Erzwingung der Berechtigung BLUETOOTH_CONNECT im BluetoothAdapter

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

Unter Android 14 werden die Kernbibliotheken von Android fortlaufend aktualisiert, damit sie den Funktionen der neuesten OpenJDK-LTS-Releases entsprechen. Dazu gehören sowohl Bibliotheksupdates als auch die Java 17-Sprachunterstützung für App- und Plattformentwickler.

Einige dieser Änderungen können sich auf die Kompatibilität der App auswirken:

  • Änderungen an regulären Ausdrücken: Ungültige Gruppenverweise dürfen jetzt nicht mehr der Semantik von OpenJDK mehr entsprechen. Es kann vorkommen, dass ein IllegalArgumentException von der Klasse java.util.regex.Matcher ausgegeben wird. Testen Sie Ihre Anwendung daher auf Bereiche, in denen reguläre Ausdrücke verwendet werden. Wenn Sie diese Änderung beim Testen aktivieren oder deaktivieren möchten, aktivieren oder deaktivieren Sie das Flag DISALLOW_INVALID_GROUP_REFERENCE mit den Kompatibilitäts-Framework-Tools.
  • UUID-Verarbeitung: Die Methode java.util.UUID.fromString() führt jetzt bei der Validierung des Eingabearguments strengere Prüfungen durch. Daher wird während der Deserialisierung möglicherweise ein IllegalArgumentException angezeigt. Wenn Sie diese Änderung während des Tests aktivieren oder deaktivieren möchten, aktivieren oder deaktivieren Sie das Flag ENABLE_STRICT_VALIDATION mit den Kompatibilitäts-Framework-Tools.
  • ProGuard-Probleme: In einigen Fällen verursacht das Hinzufügen der Klasse java.lang.ClassValue ein Problem, wenn Sie versuchen, Ihre App mit ProGuard zu verkleinern, zu verschleiern und zu optimieren. Das Problem beruht auf einer Kotlin-Bibliothek, die das Laufzeitverhalten abhängig davon ändert, ob Class.forName("java.lang.ClassValue") eine Klasse zurückgibt oder nicht. Wenn Ihre App für eine ältere Version der Laufzeit ohne verfügbare java.lang.ClassValue-Klasse entwickelt wurde, wird durch diese Optimierungen möglicherweise die Methode computeValue aus Klassen entfernt, die von java.lang.ClassValue abgeleitet sind.

JobScheduler verstärkt Callback- und Netzwerkverhalten

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, it stops 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". Consider migrating to WorkManager, which provides support for asynchronous processing or migrating any heavy work into a background 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 Launch API

Für Apps, die auf 14 und höher ausgerichtet sind, wurde TileService#startActivityAndCollapse(Intent) verworfen und löst beim Aufruf eine Ausnahme aus. Wenn Ihre App Aktivitäten über Kacheln startet, verwenden Sie stattdessen TileService#startActivityAndCollapse(PendingIntent).

Datenschutz

Teilweiser Zugriff auf Fotos und Videos

Android 14 引入了所选照片访问权限,可让用户授权应用访问其媒体库中的特定图片和视频,而不是授予对指定类型的所有媒体的访问权限。

仅当您的应用以 Android 14(API 级别 34)或更高版本为目标平台时,才会启用此变更。如果您还没有使用照片选择器,建议您在应用中实现该选择器,以便在选择图片和视频时提供一致的体验,同时还可以加强用户隐私保护,而无需请求任何存储权限。

如果您使用存储权限维护自己的图库选择器,并且需要完全控制您的实现,请调整您的实现,以使用新的 READ_MEDIA_VISUAL_USER_SELECTED 权限。如果您的应用不使用新权限,系统会在兼容模式下运行应用。

Nutzererfahrung

Sichere Full-Screen-Intent-Benachrichtigungen

在 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 启动设置页面,在该页面中,用户可以授予权限。

Sicherheit

Einschränkungen für implizite und ausstehende Intents

Bei Apps, die auf Android 14 (API-Level 34) oder höher ausgerichtet sind, werden Apps von Android so eingeschränkt, dass sie implizite Intents an interne App-Komponenten senden:

  • Implizite Intents werden nur an exportierte Komponenten gesendet. Anwendungen müssen entweder einen expliziten Intent für die Lieferung an nicht exportierte Komponenten verwenden oder die Komponente als exportiert markieren.
  • Wenn eine App einen änderbaren ausstehenden Intent mit einem Intent erstellt, der keine Komponente oder kein Paket angibt, löst das System eine Ausnahme aus.

Diese Änderungen verhindern, dass schädliche Anwendungen implizite Intents abfangen, die für die internen Komponenten einer App verwendet werden sollen.

Das folgende Beispiel zeigt einen Intent-Filter, der in der Manifestdatei Ihrer App deklariert werden kann:

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

Wenn Ihre App versucht, diese Aktivität mit einem impliziten Intent zu starten, wird eine Ausnahme ausgelöst:

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"));

Um die nicht exportierte Aktivität zu starten, sollte Ihre App stattdessen einen expliziten Intent verwenden:

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

Empfänger von laufzeitregistrierten Broadcasts müssen das Exportverhalten angeben

Apps und Dienste, die auf Android 14 (API-Level 34) oder höher ausgerichtet sind und kontextregistrierte Empfänger verwenden, müssen mit einem Flag angeben, ob der Empfänger in alle anderen Apps auf dem Gerät exportiert werden soll: entweder RECEIVER_EXPORTED bzw. RECEIVER_NOT_EXPORTED. Diese Anforderung trägt durch die Funktionen für diese Empfänger in Android 13 zum Schutz von Apps vor Sicherheitslücken bei.

Ausnahme für Empfänger, die nur System-Broadcasts empfangen

Wenn Ihre App einen Empfänger nur für System-Broadcasts über Context#registerReceiver-Methoden wie Context#registerReceiver() registriert, sollte bei der Registrierung des Empfängers kein Flag angegeben werden.

Sichererer dynamischer Code wird geladen

Wenn Ihre App auf Android 14 (API-Level 34) oder höher ausgerichtet ist und Dynamic Code Loading (DCL) verwendet, müssen alle dynamisch geladenen Dateien als schreibgeschützt markiert werden. Andernfalls gibt das System eine Ausnahme aus. Wir empfehlen, dass Apps Code möglichst nicht dynamisch laden, da sich so das Risiko erheblich erhöht, dass eine App durch Codeinjektion oder Codemanipulation manipuliert werden kann.

Wenn Sie Code dynamisch laden müssen, verwenden Sie den folgenden Ansatz, um die dynamisch geladene Datei (z. B. eine DEX-, JAR- oder APK-Datei) als schreibgeschützt festzulegen, sobald die Datei geöffnet und bevor Inhalte geschrieben werden:

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

Dynamisch geladene Dateien bearbeiten, die bereits vorhanden sind

Damit für vorhandene dynamisch geladene Dateien keine Ausnahmen ausgelöst werden, empfehlen wir, die Dateien zu löschen und neu zu erstellen, bevor Sie versuchen, sie wieder dynamisch in Ihre App zu laden. Folgen Sie beim Neuerstellen der Dateien der Anleitung oben, um die Dateien beim Schreiben als schreibgeschützt zu markieren. Alternativ können Sie die vorhandenen Dateien als schreibgeschützt kennzeichnen. In diesem Fall empfehlen wir jedoch dringend, zuerst die Integrität der Dateien zu prüfen (z. B. indem Sie die Signatur der Datei mit einem vertrauenswürdigen Wert vergleichen), um Ihre Anwendung vor schädlichen Aktionen zu schützen.

Zusätzliche Einschränkungen für das Starten von Aktivitäten im Hintergrund

对于以 Android 14(API 级别 34)或更高版本为目标平台的应用,系统会进一步限制允许应用何时从后台启动 activity:

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

ZIP-Pfaddurchlauf

Bei Apps, die auf Android 14 (API-Level 34) oder höher ausgerichtet sind, verhindert Android die Sicherheitslücke beim ZIP-Pfaddurchlauf auf folgende Weise: ZipFile(String) und ZipInputStream.getNextEntry() gibt ZipException aus, wenn die Namen der ZIP-Dateieinträge „..“ enthalten oder mit „/“ beginnen.

Apps können diese Überprüfung durch Aufrufen von dalvik.system.ZipPathValidator.clearCallback() deaktivieren.

对于以 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

Nicht-SDK-Einschränkungen aktualisiert

Android 14 enthält aktualisierte Listen eingeschränkter Nicht-SDK-Schnittstellen, die auf der Zusammenarbeit mit Android-Entwicklern und den neuesten internen Tests basieren. Wann immer möglich, achten wir darauf, dass öffentliche Alternativen verfügbar sind, bevor wir Nicht-SDK-Schnittstellen einschränken.

Wenn deine App nicht auf Android 14 ausgerichtet ist, betreffen dich einige dieser Änderungen möglicherweise nicht sofort. Sie können derzeit zwar einige Nicht-SDK-Schnittstellen verwenden (abhängig von der Ziel-API-Ebene Ihrer App), aber die Verwendung von Nicht-SDK-Methoden oder -Feldern birgt immer ein hohes Risiko für Probleme mit Ihrer App.

Wenn Sie sich nicht sicher sind, ob Ihre Anwendung Nicht-SDK-Schnittstellen verwendet, können Sie die Anwendung testen. Wenn Ihre App Nicht-SDK-Schnittstellen verwendet, sollten Sie mit der Planung einer Migration zu SDK-Alternativen beginnen. Trotzdem können einige Apps für die Verwendung von Nicht-SDK-Schnittstellen infrage kommen. Wenn Sie für eine Funktion in Ihrer App keine Alternative zur Verwendung einer Nicht-SDK-Schnittstelle finden, sollten Sie eine neue öffentliche API anfordern.

Weitere Informationen zu den Änderungen in diesem Android-Release finden Sie unter Aktualisierungen der Einschränkungen für Schnittstellen, die nicht auf SDK basieren, unter Android 14. Allgemeine Informationen zu Nicht-SDK-Schnittstellen finden Sie unter Einschränkungen für Nicht-SDK-Schnittstellen.