Come le release precedenti, Android 15 include modifiche al comportamento che potrebbero influire sulla tua app. Le seguenti modifiche al comportamento si applicano esclusivamente alle app che hanno come target Android 15 o versioni successive. Se la tua app ha come target Android 15 o versioni successive, devi modificarla per supportare correttamente questi comportamenti, ove applicabile.
Assicurati di esaminare anche l'elenco delle modifiche al comportamento che interessano tutte le app
in esecuzione su Android 15, indipendentemente dal targetSdkVersion della tua app.
Funzionalità di base
Android 15 modifica o espande varie funzionalità di base del sistema Android.
Modifiche ai servizi in primo piano
Con Android 15 stiamo apportando le seguenti modifiche ai servizi in primo piano.
- Comportamento del timeout del servizio in primo piano di sincronizzazione dei dati
- Nuovo tipo di servizio in primo piano per l'elaborazione di contenuti multimediali
- Limitazioni relative ai broadcast receiver
BOOT_COMPLETEDche avviano servizi in primo piano - Restrizioni relative all'avvio dei servizi in primo piano quando un'app detiene l'autorizzazione
SYSTEM_ALERT_WINDOW
Comportamento del timeout del servizio in primo piano di sincronizzazione dei dati
对于以 Android 15(API 级别 35)或更高版本为目标平台的应用,Android 15 为 dataSync 引入了新的超时行为。此行为也适用于新的 mediaProcessing 前台服务类型。
系统允许应用的 dataSync 服务在 24 小时内总共运行 6 小时,之后系统会调用正在运行的服务的 Service.onTimeout(int, int) 方法(在 Android 15 中引入)。此时,该服务有几秒钟时间来调用 Service.stopSelf()。调用 Service.onTimeout() 后,该服务将不再被视为前台服务。如果服务未调用 Service.stopSelf(),系统会抛出内部异常。系统会在 Logcat 中记录此异常,并显示以下消息:
Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type dataSync did not stop within its timeout: [component name]"
为避免因行为变更而导致问题,您可以执行以下一项或多项操作:
- 让您的服务实现新的
Service.onTimeout(int, int)方法。当您的应用收到回调时,请务必在几秒钟内调用stopSelf()。(如果您不立即停止应用,系统会生成故障。) - 确保应用的
dataSync服务在任何 24 小时内总运行时间不超过 6 小时(除非用户与应用互动,重置计时器)。 - 仅通过直接的用户互动来启动
dataSync前台服务;由于您的应用在服务启动时位于前台,因此服务会在应用进入后台后的 6 小时内完整运行。 - 请改用替代 API,而不是使用
dataSync前台服务。
如果您的应用的 dataSync 前台服务在过去 24 小时内运行了 6 小时,则您无法启动其他 dataSync 前台服务,除非用户已将您的应用切换到前台(这会重置计时器)。如果您尝试启动其他 dataSync 前台服务,系统会抛出 ForegroundServiceStartNotAllowedException,并显示类似“前台服务类型 dataSync 的时间限制已用尽”的错误消息。
测试
如需测试应用的行为,您可以启用数据同步超时功能,即使应用未以 Android 15 为目标平台也是如此(前提是应用在 Android 15 设备上运行)。如需启用超时,请运行以下 adb 命令:
adb shell am compat enable FGS_INTRODUCE_TIME_LIMITS your-package-name
您还可以调整超时期限,更轻松地测试应用在达到此限制时的行为。如需设置新的超时期限,请运行以下 adb 命令:
adb shell device_config put activity_manager data_sync_fgs_timeout_duration duration-in-milliseconds
Nuovo tipo di servizio in primo piano per l'elaborazione multimediale
Android 15 引入了一种新的前台服务类型 mediaProcessing。此服务类型适用于转码媒体文件等操作。例如,媒体应用可能会下载音频文件,并需要先将其转换为其他格式,然后才能播放。您可以使用 mediaProcessing 前台服务,确保即使应用在后台运行时转换也会继续。
系统允许应用的 mediaProcessing 服务在 24 小时内总共运行 6 小时,之后系统会调用正在运行的服务的 Service.onTimeout(int, int) 方法(在 Android 15 中引入)。此时,服务有几秒钟的时间来调用 Service.stopSelf()。如果服务未调用 Service.stopSelf(),系统会抛出内部异常。系统会在 Logcat 中记录此异常,并显示以下消息:
Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type mediaProcessing did not stop within its timeout: [component name]"
为避免出现此异常,您可以执行以下任一操作:
- 让您的服务实现新的
Service.onTimeout(int, int)方法。当您的应用收到回调时,请务必在几秒钟内调用stopSelf()。(如果您未立即停止应用,系统会生成失败情况。) - 确保应用的
mediaProcessing服务在任何 24 小时内总运行时间不超过 6 小时(除非用户与应用互动,重置计时器)。 - 仅在有直接用户互动时启动
mediaProcessing前台服务;由于服务启动时应用位于前台,因此您的服务在应用进入后台后有完整的 6 小时时间。 - 请改用 替代 API(例如 WorkManager),而不是使用
mediaProcessing前台服务。
如果您的应用的 mediaProcessing 前台服务在过去 24 小时内运行了 6 小时,则您无法启动其他 mediaProcessing 前台服务,除非用户将您的应用切换到前台(这会重置计时器)。如果您尝试启动另一个 mediaProcessing 前台服务,系统会抛出 ForegroundServiceStartNotAllowedException,并显示类似于“前台服务类型 mediaProcessing 的时间限制已用尽”的错误消息。
如需详细了解 mediaProcessing 服务类型,请参阅 Android 15 前台服务类型变更:媒体处理。
测试
如需测试应用的行为,您可以启用媒体处理超时,即使您的应用并非以 Android 15 为目标平台也是如此(前提是应用在 Android 15 设备上运行)。如需启用超时,请运行以下 adb 命令:
adb shell am compat enable FGS_INTRODUCE_TIME_LIMITS your-package-name
您还可以调整超时期限,以便更轻松地测试应用在达到上限时的行为方式。如需设置新的超时期限,请运行以下 adb 命令:
adb shell device_config put activity_manager media_processing_fgs_timeout_duration duration-in-milliseconds
Limitazioni relative ai BOOT_COMPLETED broadcast receiver che avviano servizi in primo piano
在启动 BOOT_COMPLETED 广播接收器方面存在新限制
前台服务。BOOT_COMPLETED 接收器不能启动
以下类型的前台服务:
dataSynccameramediaPlaybackphoneCallmediaProjectionmicrophone(自 Android 14 起,microphone就受到此限制)
如果 BOOT_COMPLETED 接收器尝试启动任何上述类型的前台
服务,系统会抛出 ForegroundServiceStartNotAllowedException。
测试
如需测试应用的行为,您可以启用这些新限制,即使您的应用并未以 Android 15 为目标平台(只要应用在 Android 15 设备上运行)也是如此。运行以下 adb 命令:
adb shell am compat enable FGS_BOOT_COMPLETED_RESTRICTIONS your-package-name
如需在不重启设备的情况下发送 BOOT_COMPLETED 广播,请运行以下 adb 命令:
adb shell am broadcast -a android.intent.action.BOOT_COMPLETED your-package-name
Restrizioni relative all'avvio dei servizi in primo piano quando un'app dispone dell'autorizzazione SYSTEM_ALERT_WINDOW
In precedenza, se un'app disponeva dell'autorizzazione SYSTEM_ALERT_WINDOW, poteva avviare un servizio in primo piano anche se l'app era attualmente in background (come discusso nella sezione Esclusioni dalle limitazioni di avvio in background).
Se un'app ha come target Android 15, l'esenzione è ora più limitata. Ora l'app deve avere l'autorizzazione SYSTEM_ALERT_WINDOW e anche una finestra overlay visibile. In altre parole, l'app deve prima avviare una finestra TYPE_APPLICATION_OVERLAY e la finestra deve essere visibile prima di avviare un servizio in primo piano.
Se la tua app tenta di avviare un servizio in primo piano in background senza
soddisfare questi nuovi requisiti (e non ha altre esenzioni), il
sistema restituisce ForegroundServiceStartNotAllowedException.
Se la tua app dichiara l'autorizzazione SYSTEM_ALERT_WINDOW
e avvia servizi in primo piano in background, potrebbe essere interessata da questa
modifica. Se la tua app riceve un ForegroundServiceStartNotAllowedException, controlla l'ordine di operazioni dell'app e assicurati che abbia già una finestra in overlay attiva prima di tentare di avviare un servizio in primo piano da un servizio in background. Puoi controllare se la finestra dell'overlay è attualmente visibile
chiamando View.getWindowVisibility() oppure
puoi eseguire l'override di View.onWindowVisibilityChanged()
per ricevere una notifica ogni volta che la visibilità cambia.
Test
Per testare il comportamento della tua app, puoi attivare queste nuove limitazioni anche se la tua app non ha come target Android 15 (a condizione che l'app sia in esecuzione su un dispositivo Android 15). Per attivare queste nuove limitazioni per l'avvio dei servizi in primo piano
dall'background, esegui il seguente comando adb:
adb shell am compat enable FGS_SAW_RESTRICTIONS your-package-name
Modifiche all'orario in cui le app possono modificare lo stato globale della modalità Non disturbare
Le app che hanno come target Android 15 (livello API 35) e versioni successive non possono più modificare lo stato o i criteri globali della modalità Non disturbare (ND) su un dispositivo (modificando le impostazioni utente o disattivando la modalità ND). Le app devono invece fornire un AutomaticZenRule, che il sistema combina in una norma globale con lo schema vigente che prevede l'applicazione della norma più restrittiva. Le chiamate alle API esistenti che precedentemente influivano sullo stato globale (setInterruptionFilter,
setNotificationPolicy) comportano la creazione o l'aggiornamento di un valore AutomaticZenRule implicito, che viene attivato e disattivato in base al ciclo di chiamata di queste chiamate API.
Tieni presente che questa modifica influisce sul comportamento osservabile solo se l'app chiama setInterruptionFilter(INTERRUPTION_FILTER_ALL) e si aspetta che la chiamata disattivi un AutomaticZenRule precedentemente attivato dai relativi proprietari.
Modifiche all'API OpenJDK
Android 15 将继续更新 Android 的核心库,以与最新 OpenJDK LTS 版本中的功能保持一致。
以下变更可能会影响以 Android 15(API 级别 35)为目标平台的应用的兼容性:
对字符串格式化 API 进行了更改:现在,当使用以下
String.format()和Formatter.format()API 时,对参数索引、标志、 宽度和精度的验证要求变得更加严格:String.format(String, Object[])String.format(Locale, String, Object[])Formatter.format(String, Object[])Formatter.format(Locale, String, Object[])
例如,当使用实参索引 0(格式字符串中的
%0)时,系统会抛出以下异常:IllegalFormatArgumentIndexException: Illegal format argument index = 0在这种情况下,可以使用实参索引 1(格式字符串中的
%1)来解决此问题。对
Arrays.asList(...).toArray()的组件类型进行了更改:使用Arrays.asList(...).toArray()时,生成的数组的组件类型现在是Object,而不是底层数组元素的类型。因此,以下代码会抛出ClassCastException:String[] elements = (String[]) Arrays.asList("one", "two").toArray();在这种情况下,如需在生成的 数组中保留
String作为组件类型,您可以改用Collection.toArray(Object[]):String[] elements = Arrays.asList("two", "one").toArray(new String[0]);对语言代码处理进行了更改:使用
LocaleAPI 时, 希伯来语、意第绪语和印度尼西亚语的语言代码不再转换为 其过时形式(希伯来语:iw,意第绪语:ji,印度尼西亚语:in)。 指定其中一种语言区域的语言代码时,请改用 ISO 639-1 中的代码 (希伯来语:he,意第绪语:yi,印度尼西亚语:id)。对随机 int 序列进行了更改:根据 https://bugs.openjdk.org/browse/JDK-8301574 中所做的更改,以下
Random.ints()方法现在返回的数字序列与 theRandom.nextInt()方法返回的数字序列不同:一般来说,此更改不应导致应用出现破坏性行为,但您的代码不应期望从
Random.ints()方法生成的序列与Random.nextInt()匹配。
新的 SequencedCollection API 可能会影响应用的兼容性
在应用的 build 配置中
更新 以使用
Android 15(API 级别 35)后:compileSdk
与
MutableList.removeFirst()和MutableList.removeLast()扩展函数在kotlin-stdlib中发生冲突Java 中的
List类型映射到 Kotlin 中的MutableList类型。 由于List.removeFirst()和List.removeLast()API 是在 Android 15(API 级别 35)中引入的,因此 Kotlin 编译器 会将函数调用(例如list.removeFirst())静态解析为 新的ListAPI,而不是kotlin-stdlib中的扩展函数。如果使用
compileSdk设置为35且minSdk设置为34或更低版本重新编译应用,然后在 Android 14 及更低版本上运行该应用,则会抛出运行时错误:java.lang.NoSuchMethodError: No virtual method removeFirst()Ljava/lang/Object; in class Ljava/util/ArrayList;Android Gradle 插件中现有的
NewApilint 选项可以捕获这些新的 API 用法。./gradlew lintMainActivity.kt:41: Error: Call requires API level 35 (current min is 34): java.util.List#removeFirst [NewApi] list.removeFirst()如需修复运行时异常和 lint 错误,可以将
removeFirst()和removeLast()函数调用分别替换为 Kotlin 中的removeAt(0)和removeAt(list.lastIndex)。如果您使用的是 Android Studio Ladybug | 2024.1.3 或更高版本,它还为这些错误提供了快速修复选项。如果 lint 选项已停用,请考虑移除
@SuppressLint("NewApi")和lintOptions { disable 'NewApi' }。与 Java 中的其他方法发生冲突
新的方法已添加到现有类型中,例如,
List和Deque。这些新方法可能与其他接口和类中具有相同名称和实参类型的方法不兼容。如果方法签名冲突且不兼容,javac编译器会输出 build 时错误。例如:错误示例 1:
javac MyList.javaMyList.java:135: error: removeLast() in MyList cannot implement removeLast() in List public void removeLast() { ^ return type void is not compatible with Object where E is a type-variable: E extends Object declared in interface List错误示例 2:
javac MyList.javaMyList.java:7: error: types Deque<Object> and List<Object> are incompatible; public class MyList implements List<Object>, Deque<Object> { both define reversed(), but with unrelated return types 1 error错误示例 3:
javac MyList.javaMyList.java:43: error: types List<E#1> and MyInterface<E#2> are incompatible; public static class MyList implements List<Object>, MyInterface<Object> { class MyList inherits unrelated defaults for getFirst() from types List and MyInterface where E#1,E#2 are type-variables: E#1 extends Object declared in interface List E#2 extends Object declared in interface MyInterface 1 error如需修复这些 build 错误,实现这些接口的类应使用兼容的返回值类型替换该方法。例如:
@Override public Object getFirst() { return List.super.getFirst(); }
Sicurezza
Android 15 include modifiche che promuovono la sicurezza del sistema per proteggere app e utenti da app dannose.
Versioni TLS con restrizioni
Android 15 限制了对 TLS 版本 1.0 和 1.1 的使用。这些版本之前已在 Android 中被弃用,但现在不允许面向 Android 15 的应用使用。
Avvio di attività in background protette
Android 15 protegge gli utenti da app dannose e offre loro un maggiore controllo sui propri dispositivi aggiungendo modifiche che impediscono alle app dannose in background di portare altre app in primo piano, elevare i propri privilegi e abusare dell'interazione con l'utente. Gli avvii di attività in background sono limitati a partire da Android 10 (livello API 29).
Altre modifiche
- Modifica i creator di
PendingIntentin modo che blocchino l'avvio delle attività in background per impostazione predefinita. In questo modo, si impedisce alle app di creare accidentalmente unPendingIntentche potrebbe essere sfruttato da malintenzionati. - Non portare un'app in primo piano a meno che il mittente
PendingIntentnon lo consenta. Questa modifica ha lo scopo di impedire alle app dannose di abusare della possibilità di avviare attività in background. Per impostazione predefinita, le app non sono autorizzate a portare in primo piano lo stack di attività, a meno che il creatore non consenta i privilegi di avvio dell'attività in background o il mittente non disponga di questi privilegi. - Controlla come l'attività principale di una pila di attività può terminare l'attività. Se l'attività in primo piano termina un'attività, Android torna all'ultima attività attiva. Inoltre, se un'attività non in primo piano termina la sua attività, Android tornerà alla schermata Home e non bloccherà il completamento di questa attività non in primo piano.
- Impedisci l'avvio di attività arbitrarie da altre app nella tua attività. Questa modifica impedisce alle app dannose di effettuare phishing sugli utenti creando attività che sembrano provenire da altre app.
- Bloccare l'avvio di attività in background per le finestre non visibili. In questo modo, si impedisce alle app dannose di utilizzare in modo improprio l'avvio di attività in background per mostrare agli utenti contenuti indesiderati o dannosi.
Intenzioni più sicure
Android 15 针对 intent 引入了 StrictMode。
如需查看有关 Intent 使用违规行为的详细日志,请使用以下方法:
Kotlin
fun onCreate() { StrictMode.setVmPolicy(VmPolicy.Builder() .detectUnsafeIntentLaunch() .build() ) }
Java
public void onCreate() { StrictMode.setVmPolicy(new VmPolicy.Builder() .detectUnsafeIntentLaunch() .build()); }
Esperienza utente e UI di sistema
Android 15 include alcune modifiche volte a creare un'esperienza utente più coerente e intuitiva.
Modifiche all'inserto della finestra
Android 15 中与窗口内边距相关的两项变更:默认强制执行边到边,此外还有配置变更,例如系统栏的默认配置。
Applicazione edge-to-edge
Le app sono edge-to-edge per impostazione predefinita sui dispositivi su cui è in esecuzione Android 15 se hanno come target Android 15 (livello API 35).
Si tratta di una modifica che comporta un'interruzione e che potrebbe influire negativamente sulla UI della tua app. Le modifiche riguardano le seguenti aree della UI:
- Barra di navigazione con handle per i gesti
- Trasparente per impostazione predefinita.
- L'offset inferiore è disattivato, quindi i contenuti vengono disegnati dietro la barra di navigazione di sistema, a meno che non vengano applicati gli inset.
setNavigationBarColoreR.attr#navigationBarColorsono deprecati e non influiscono sulla navigazione tramite gesti.setNavigationBarContrastEnforcedeR.attr#navigationBarContrastEnforcedcontinuano a non avere alcun effetto sulla navigazione tramite gesti.
- Navigazione con tre pulsanti
- Opacità impostata su 80% per impostazione predefinita, con il colore che potrebbe corrispondere allo sfondo della finestra.
- L'offset inferiore è disattivato, quindi i contenuti vengono disegnati dietro la barra di navigazione di sistema, a meno che non vengano applicati gli inset.
setNavigationBarColoreR.attr#navigationBarColorsono impostati in modo da corrispondere allo sfondo della finestra per impostazione predefinita. Lo sfondo della finestra deve essere un elemento disegnabile a colori per l'applicazione di questa impostazione predefinita. Questa API è deprecata, ma continua a influire sulla navigazione con tre pulsanti.setNavigationBarContrastEnforcedeR.attr#navigationBarContrastEnforcedsono impostati su true per impostazione predefinita, il che aggiunge uno sfondo opaco all'80% alla navigazione con tre pulsanti.
- Barra di stato
- Trasparente per impostazione predefinita.
- L'offset superiore è disattivato, quindi i contenuti vengono disegnati dietro la barra di stato, a meno che non vengano applicati gli inset.
setStatusBarColoreR.attr#statusBarColorsono deprecati e non hanno alcun effetto su Android 15.setStatusBarContrastEnforcedeR.attr#statusBarContrastEnforcedsono deprecati, ma hanno ancora un effetto su Android 15.
- Ritaglio display
layoutInDisplayCutoutModedelle finestre non mobili deve essereLAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS.SHORT_EDGES,NEVEReDEFAULTvengono interpretati comeALWAYSin modo che gli utenti non vedano una barra nera causata dal ritaglio display e che l'app appaia edge-to-edge.
L'esempio seguente mostra un'app prima e dopo aver scelto come target Android 15 (livello API 35) e prima e dopo aver applicato gli inset. Questo esempio non è esaustivo e potrebbe apparire in modo diverso su Android Auto.
Cosa controllare se la tua app è già edge-to-edge
Se la tua app è già edge-to-edge e applica gli inset, non dovresti riscontrare problemi, tranne nei seguenti scenari. Tuttavia, anche se ritieni di non essere interessato, ti consigliamo di testare la tua app.
- Hai una finestra non mobile, ad esempio un'
Activityche utilizzaSHORT_EDGES,NEVERoDEFAULTanzichéLAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS. Se l'app si arresta in modo anomalo all'avvio, il problema potrebbe essere dovuto alla schermata iniziale. Puoi eseguire l'upgrade della dipendenza core splashscreen alla versione 1.2.0-alpha01 o successive oppure impostarewindow.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always. - Potrebbero esserci schermate con meno traffico con UI occlusa. Verifica che queste schermate meno visitate non abbiano UI occlusa. Le schermate con meno traffico includono:
- Schermate di onboarding o di accesso
- Pagine Impostazioni
Cosa controllare se la tua app non è ancora edge-to-edge
Se la tua app non è ancora edge-to-edge, è molto probabile che tu sia interessato. Oltre agli scenari per le app già edge-to-edge, devi considerare quanto segue:
- Se la tua app utilizza i componenti di Material 3 (
androidx.compose.material3) in Compose, comeTopAppBar,BottomAppBar, eNavigationBar, è probabile che questi componenti non siano interessati perché gestiscono automaticamente gli inset. - Se la tua app utilizza i componenti di Material 2 (
androidx.compose.material) in Compose, questi componenti non gestiscono automaticamente gli inset. Tuttavia, puoi accedere agli inset e applicarli manualmente. In androidx.compose.material 1.6.0 e versioni successive, utilizza il parametrowindowInsetsper applicare manualmente gli inset perBottomAppBar,TopAppBar,BottomNavigationeNavigationRail. Allo stesso modo, utilizza ilcontentWindowInsetsparametro perScaffold. - Se la tua app utilizza le visualizzazioni e i componenti Material
(
com.google.android.material), la maggior parte dei componenti Material basati sulle visualizzazioni, comeBottomNavigationView,BottomAppBar,NavigationRailViewoNavigationView, gestisce gli inset e non richiede ulteriori interventi. Tuttavia, devi aggiungereandroid:fitsSystemWindows="true"se utilizziAppBarLayout. - Per i composable personalizzati, applica gli inset manualmente come spaziatura interna. Se i tuoi
contenuti si trovano all'interno di un
Scaffold, puoi utilizzare gli inset utilizzando iScaffoldvalori di spaziatura interna. In caso contrario, applica la spaziatura interna utilizzando uno deiWindowInsets. - Se la tua app utilizza le visualizzazioni e
BottomSheet,SideSheeto container personalizzati, applica la spaziatura interna utilizzandoViewCompat.setOnApplyWindowInsetsListener. PerRecyclerView, applica la spaziatura interna utilizzando questo listener e aggiungi ancheclipToPadding="false".
Cosa controllare se la tua app deve offrire una protezione dello sfondo personalizzata
Se la tua app deve offrire una protezione dello sfondo personalizzata alla navigazione con tre pulsanti o
alla barra di stato, deve posizionare un composable o una visualizzazione dietro la barra di sistema
utilizzando WindowInsets.Type#tappableElement() per ottenere l'altezza della barra di navigazione con tre pulsanti
o WindowInsets.Type#statusBars.
Risorse aggiuntive per la modalità edge-to-edge
Per ulteriori considerazioni sull'applicazione degli inset, consulta le guide Visualizzazioni edge-to-edge e Compose edge-to-edge.
API deprecate
Le seguenti API sono deprecate, ma non disattivate:
R.attr#enforceStatusBarContrastR.attr#navigationBarColor(per la navigazione con tre pulsanti, con alfa 80%)Window#isStatusBarContrastEnforcedWindow#setNavigationBarColor(per la navigazione con tre pulsanti, con alfa 80%)Window#setStatusBarContrastEnforced
Le seguenti API sono deprecate e disattivate:
R.attr#navigationBarColor(per la navigazione tramite gesti)R.attr#navigationBarDividerColorR.attr#statusBarColorWindow#setDecorFitsSystemWindowsWindow#getNavigationBarColorWindow#getNavigationBarDividerColorWindow#getStatusBarColorWindow#setNavigationBarColor(per la navigazione tramite gesti)Window#setNavigationBarDividerColorWindow#setStatusBarColor
Configurazione stabile
如果您的应用以 Android 15(API 级别 35)或更高版本为目标平台,Configuration 不再排除系统栏。如果您在 Configuration 类中使用屏幕尺寸进行布局计算,则应根据需要将其替换为更好的替代方案,例如适当的 ViewGroup、WindowInsets 或 WindowMetricsCalculator。
Configuration 自 API 1 起可用。它通常从 Activity.onConfigurationChanged 获取。它提供窗口密度、屏幕方向和尺寸等信息。从 Configuration 返回的窗口尺寸的一个重要特征是,它之前排除了系统栏。
配置尺寸通常用于资源选择,例如 /res/layout-h500dp,这仍然是一个有效的用例。但是,我们一直不建议将其用于布局计算。如果您这样做,现在应该停止。您应该根据自己的用例,将 Configuration 的使用替换为更合适的内容。
如果您使用它来计算布局,请使用适当的 ViewGroup,例如 CoordinatorLayout 或 ConstraintLayout。如果您使用它来确定系统导航栏的高度,请使用 WindowInsets。如果您想知道应用窗口的当前尺寸,请使用 computeCurrentWindowMetrics。
以下列表介绍了受此更改影响的字段:
Configuration.screenWidthDp和screenHeightDp尺寸不再 排除系统栏。Configuration.smallestScreenWidthDp间接受到screenWidthDp和screenHeightDp更改的影响。Configuration.orientation间接受到接近正方形的设备上screenWidthDp和screenHeightDp更改的影响。Display.getSize(Point)间接受到Configuration更改的影响。此方法已从 API 级别 30 开始被弃用。- 自 API 级别 33 起,
Display.getMetrics()的运作方式已是如此。
L'attributo elegantTextHeight è impostato su true per impostazione predefinita.
对于以 Android 15(API 级别 35)为目标平台的应用,elegantTextHeight TextView 属性默认会变为 true,将默认使用的紧凑字体替换为一些具有较大垂直测量的脚本,使其更易于阅读。紧凑字体旨在防止布局中断;Android 13(API 级别 33)允许文本布局利用 fallbackLineSpacing 属性拉伸垂直高度,从而防止许多此类中断。
在 Android 15 中,系统中仍保留了紧凑字体,因此您的应用可以将 elegantTextHeight 设置为 false 以获得与之前相同的行为,但即将发布的版本不太可能支持此字体。因此,如果您的应用支持以下脚本:阿拉伯语、老挝语、缅甸语、泰米尔语、古吉拉特语、卡纳达语、马拉雅拉姆语、奥里亚语、泰卢固语或泰语,请将 elegantTextHeight 设置为 true 以测试您的应用。
elegantTextHeight 行为。
elegantTextHeight 行为。Modifiche alla larghezza di TextView per forme di lettere complesse
在以前的 Android 版本中,某些具有复杂形状的手写字体或语言可能会在上一个或下一个字符的区域绘制字母。在某些情况下,此类字母会在开头或结尾处被剪裁。从 Android 15 开始,TextView 会分配宽度,以便为此类字母绘制足够的空间,并允许应用请求向左额外添加内边距以防止剪裁。
由于此更改会影响 TextView 确定宽度的方式,因此如果应用以 Android 15(API 级别 35)或更高版本为目标平台,TextView 会默认分配更多宽度。您可以通过对 TextView 调用 setUseBoundsForWidth API 来启用或停用此行为。
由于添加左内边距可能会导致现有布局未对齐,因此默认情况下不会添加内边距,即使以 Android 15 或更高版本为目标平台的应用也是如此。不过,您可以通过调用 setShiftDrawingOffsetForStartOverhang 添加额外的内边距以防止剪裁。
以下示例展示了这些更改如何改进某些字体和语言的文本布局。
<TextView android:fontFamily="cursive" android:text="java" />
<TextView android:fontFamily="cursive" android:text="java" android:useBoundsForWidth="true" android:shiftDrawingOffsetForStartOverhang="true" />
<TextView android:text="คอมพิวเตอร์" />
<TextView android:text="คอมพิวเตอร์" android:useBoundsForWidth="true" android:shiftDrawingOffsetForStartOverhang="true" />
Altezza della riga predefinita in base alle impostazioni internazionali per EditText
Nelle versioni precedenti di Android, il layout del testo allungava l'altezza del testo per raggiungere l'altezza della riga del carattere corrispondente alle impostazioni internazionali correnti. Ad esempio, se i contenuti erano in giapponese, l'altezza del testo è aumentata leggermente perché l'altezza della riga del carattere giapponese è leggermente superiore a quella di un carattere latino. Tuttavia, nonostante queste differenze nelle altezze delle righe, le dimensioni dell'elemento EditText erano uniformi, indipendentemente dall'impostazione internazionale utilizzata, come illustrato nell'immagine seguente:
EditText che possono contenere testo in inglese (en), giapponese (ja) e birmano (my). L'EditText è della stessa altezza, anche se queste lingue hanno altezze diverse.Per le app che hanno come target Android 15 (livello API 35), ora è stata riservata un'altezza minima della riga per EditText in modo che corrisponda al carattere di riferimento per le impostazioni internazionali specificate, come mostrato nell'immagine seguente:
EditText che possono contenere testo in inglese (en), giapponese (ja) e birmano (my). L'altezza del carattere EditText ora include lo spazio per l'altezza della riga predefinita per i caratteri di queste lingue.Se necessario, l'app può ripristinare il comportamento precedente specificando l'attributo useLocalePreferredLineHeightForMinimum su false e può impostare metriche verticali minime personalizzate utilizzando l'API setMinimumFontMetrics in Kotlin e Java.
Fotocamera e contenuti multimediali
Android 15 apporta le seguenti modifiche al comportamento della fotocamera e dei contenuti multimediali per le app che hanno come target Android 15 o versioni successive.
Limitazioni relative alla richiesta di messa a fuoco dell'audio
Per richiedere l'attenzione audio, le app che hanno come target Android 15 (livello API 35) devono essere l'app principale o eseguire un servizio in primo piano. Se un'app tenta di richiedere lo stato attivo quando non soddisfa uno di questi requisiti, la chiamata restituisce AUDIOFOCUS_REQUEST_FAILED.
Per scoprire di più sul controllo audio, consulta l'articolo Gestire il controllo audio.
Limitazioni non SDK aggiornate
Android 15 include elenchi aggiornati di interfacce non SDK con limitazioni basati sulla collaborazione con gli sviluppatori Android e sui test interni più recenti. Ove possibile, ci assicuriamo che siano disponibili alternative pubbliche prima di limitare le interfacce non SDK.
Se la tua app non ha come target Android 15, alcune di queste modifiche potrebbero non interessarti immediatamente. Tuttavia, anche se è possibile che la tua app acceda ad alcune interfacce non SDK a seconda del livello API target dell'app, l'utilizzo di qualsiasi metodo o campo non SDK comporta sempre un rischio elevato di interruzione dell'app.
Se non sai con certezza se la tua app utilizza interfacce non SDK, puoi testarla per scoprirlo. Se la tua app si basa su interfacce non SDK, devi iniziare a pianificare una migrazione ad alternative SDK. Tuttavia, comprendiamo 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à della tua app, devi richiedere una nuova API pubblica.
Per scoprire di più sulle modifiche in questa release di Android, consulta Aggiornamenti alle limitazioni relative alle interfacce non SDK in Android 15. Per saperne di più sulle interfacce non SDK in generale, consulta Limitazioni relative alle interfacce non SDK.