Modifiche del comportamento: app destinate ad Android 14 o versioni successive

Come le release precedenti, Android 14 include modifiche del comportamento che potrebbero influire sulla tua app. Le seguenti modifiche del comportamento si applicano esclusivamente alle app che hanno come target Android 14 (livello API 34) o versioni successive. Se la tua app ha come target Android 14 o versioni successive, devi modificare l'app per supportare correttamente questi comportamenti, ove applicabile.

Assicurati di esaminare anche l'elenco delle modifiche del comportamento che interessano tutte le app eseguite su Android 14 a prescindere dalla targetSdkVersion dell'app.

Funzionalità di base

I tipi di servizi in primo piano sono obbligatori

Se la tua app ha come target Android 14 (livello API 34) o versioni successive, deve specificare almeno un tipo di servizio in primo piano per ogni servizio in primo piano all'interno dell'app. Devi scegliere un tipo di servizio in primo piano che rappresenti il caso d'uso della tua app. Il sistema si aspetta che i servizi in primo piano con un certo tipo soddisfino un particolare caso d'uso.

Se un caso d'uso nella tua app non è associato a nessuno di questi tipi, ti consigliamo vivamente di eseguire la migrazione della logica per utilizzare WorkManager o i job di trasferimento di dati avviati dall'utente.

Applicazione dell'autorizzazione BLUETOOTH_CONNECT nell'adattatore Bluetooth

Android 14 applica l'autorizzazione BLUETOOTH_CONNECT quando chiami il metodo BluetoothAdapter getProfileConnectionState() per le app che hanno come target Android 14 (livello API 34) o versioni successive.

Questo metodo richiede già l'autorizzazione BLUETOOTH_CONNECT, ma non è stata applicata. Assicurati che la tua app dichiari BLUETOOTH_CONNECT nel file AndroidManifest.xml dell'app come mostrato nello snippet seguente e verifica che un utente abbia concesso l'autorizzazione prima di chiamare getProfileConnectionState.

<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

Aggiornamenti di OpenJDK 17

Android 14 continua il lavoro di aggiornamento delle librerie di base di Android per allinearsi alle funzionalità delle ultime release OpenJDK LTS, inclusi gli aggiornamenti delle librerie e il supporto del linguaggio Java 17 per gli sviluppatori di app e piattaforme.

Alcune di queste modifiche possono influire sulla compatibilità delle app:

  • Modifiche alle espressioni regolari: i riferimenti a gruppi non validi non possono ora seguire meglio la semantica di OpenJDK. Potresti notare nuovi casi in cui la classe java.util.regex.Matcher genera un valore IllegalArgumentException, quindi assicurati di testare la tua app per individuare aree che utilizzano espressioni regolari. Per attivare o disattivare questa modifica durante il test, attiva/disattiva il flag DISALLOW_INVALID_GROUP_REFERENCE utilizzando gli strumenti del framework di compatibilità.
  • Gestione dell'UUID: il metodo java.util.UUID.fromString() ora esegue controlli più rigorosi durante la convalida dell'argomento di input, quindi potresti vedere una IllegalArgumentException durante la deserializzazione. Per attivare o disattivare questa modifica durante il test, attiva/disattiva il flag ENABLE_STRICT_VALIDATION utilizzando gli strumenti del framework di compatibilità.
  • Problemi di ProGuard: in alcuni casi, l'aggiunta della classe java.lang.ClassValue causa un problema se tenti di ridurre, offuscare e ottimizzare la tua app utilizzando ProGuard. Il problema ha origine da una libreria Kotlin che modifica il comportamento di runtime a seconda che Class.forName("java.lang.ClassValue") restituisca o meno una classe. Se la tua app è stata sviluppata su una versione precedente del runtime senza la classe java.lang.ClassValue disponibile, queste ottimizzazioni potrebbero rimuovere il metodo computeValue dalle classi derivate da java.lang.ClassValue.

JobScheduler rafforza il comportamento di callback e rete

自引入以来,JobScheduler 会预期您的应用在几秒内从 onStartJobonStopJob 返回。在 Android 14 之前,如果作业运行时间太长,则会静默停止并失败。如果您的应用以 Android 14(API 级别 34)或更高版本为目标平台且在主线程上超出了授权的时间,应用会触发 ANR,并显示错误消息“对 onStartJob 没有响应”或“对 onStopJob 没有响应”。请考虑迁移到 WorkManager,该版本可支持异步处理,或将所有繁重工作迁移到后台线程。

JobScheduler 还引入了,如果使用 setRequiredNetworkTypesetRequiredNetwork 约束条件,则需要声明 ACCESS_NETWORK_STATE 权限。如果应用在调度作业时未声明 ACCESS_NETWORK_STATE 权限,并且以 Android 14 或更高版本为目标平台,则会导致 SecurityException

Esperienza utente

Notifiche di intent a schermo intero sicure

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

Sicurezza

Limitazioni agli intent impliciti e in attesa

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

I destinatari delle trasmissioni registrate in runtime devono specificare il comportamento di esportazione

以 Android 14(API 级别 34)或更高版本为目标平台并使用上下文注册的接收器的应用和服务必须指定一个标志,以指明接收器是否应导出到设备上的所有其他应用:分别为 RECEIVER_EXPORTEDRECEIVER_NOT_EXPORTED。此要求有助于利用 Android 13 中引入的这些接收器的功能,保护应用免受安全漏洞的影响。

仅接收系统广播的接收器的例外情况

如果您的应用仅通过 Context#registerReceiver 方法(例如 Context#registerReceiver())为系统广播注册接收器,那么在注册接收器时不应指定标志。

Caricamento del codice dinamico più sicuro

Se la tua app ha come target Android 14 (livello API 34) o versioni successive e utilizza il caricamento dinamico del codice (DCL), tutti i file caricati dinamicamente devono essere contrassegnati come di sola lettura. In caso contrario, il sistema genera un'eccezione. Consigliamo alle app di evitare il caricamento dinamico del codice ogni volta che è possibile, in quanto ciò aumenta notevolmente il rischio che un'app venga compromessa a causa dell'inserimento o della manomissione del codice.

Se devi caricare il codice in modo dinamico, utilizza il seguente approccio per impostare il file caricato dinamicamente (ad esempio un file DEX, JAR o APK) come di sola lettura non appena il file viene aperto e prima che venga scritto un contenuto:

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

Gestire i file caricati dinamicamente già esistenti

Per evitare che vengano generate eccezioni per i file esistenti caricati dinamicamente, ti consigliamo di eliminarli e ricrearli prima di provare a caricarli di nuovo nell'app in modo dinamico. Quando ricrei i file, segui le linee guida precedenti per contrassegnare i file come di sola lettura al momento della scrittura. In alternativa, puoi rietichettare i file esistenti come di sola lettura, ma in questo caso ti consigliamo vivamente di verificare prima l'integrità dei file (ad esempio, controllando la firma del file con un valore attendibile), per proteggere la tua app da azioni dannose.

Ulteriori limitazioni relative all'avvio di attività in background

Per le app che hanno come target Android 14 (livello API 34) o versioni successive, il sistema limita ulteriormente i casi in cui alle app è consentito avviare attività in background:

  • Quando un'app invia un elemento PendingIntent utilizzando PendingIntent#send() o metodi simili, l'app deve eseguire l'attivazione se vuole concedere i propri privilegi di avvio per l'attività in background per avviare l'intent in sospeso. Per l'attivazione, l'app deve trasmettere un bundle ActivityOptions con setPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED).
  • Quando un'app visibile associa un servizio di un'altra app in background con il metodo bindService(), ora l'app visibile deve essere attivata se vuole concedere i propri privilegi di avvio delle attività in background al servizio associato. Per l'attivazione, l'app deve includere il flag BIND_ALLOW_ACTIVITY_STARTS quando chiami il metodo bindService().

Queste modifiche ampliano l'insieme di limitazioni esistenti per proteggere gli utenti impedendo alle app dannose di utilizzare in modo illecito le API di avviare attività di disturbo in background.

Attraversamento percorso zip

对于以 Android 14(API 级别 34)或更高版本为目标平台的应用,Android 会通过以下方式防止 Zip 路径遍历漏洞:如果 zip 文件条目名称包含“..”或以“/”开头,则 ZipInputStream.getNextEntry() 会抛出 ZipExceptionZipFile(String)

应用可以通过调用 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

Limitazioni non SDK aggiornate

Android 14 include elenchi aggiornati di interfacce non SDK limitate in base alla collaborazione con gli sviluppatori Android e agli ultimi test interni. Quando possibile, ci assicuriamo che siano disponibili alternative pubbliche prima di limitare le interfacce non SDK.

Se la tua app non è destinata ad Android 14, alcune di queste modifiche potrebbero non essere applicate immediatamente. Tuttavia, anche se al momento puoi utilizzare alcune interfacce non SDK (a seconda del livello API target della tua app), l'utilizzo di metodi o campi non SDK comporta sempre un rischio elevato di danneggiare la tua app.

Se non hai la certezza che la tua app utilizzi interfacce non SDK, puoi testare l'app per scoprirlo. Se la tua app si basa su interfacce non SDK, devi iniziare a pianificare una migrazione alle alternative SDK. Ciononostante, siamo consapevoli che alcune app hanno casi d'uso validi per l'utilizzo di interfacce non SDK. Se non riesci a trovare un'alternativa all'utilizzo di un'interfaccia non SDK per una funzionalità nella tua app, devi richiedere una nuova API pubblica.

Per scoprire di più sulle modifiche introdotte in questa release di Android, consulta Aggiornamenti alle limitazioni relative alle interfacce non SDK in Android 14. Per saperne di più sulle interfacce non SDK in generale, consulta Limitazioni per le interfacce non SDK.