Podobnie jak w przypadku poprzednich wersji Androida, w Androidzie 15 wprowadziliśmy zmiany w działaniu, które mogą mieć wpływ na Twoją aplikację. Poniższe zmiany w działaniu dotyczą wyłącznie aplikacji kierowanych na Androida 15 lub nowszego. Jeśli Twoja aplikacja jest kierowana na Androida 15 lub nowszego, zmodyfikuj ją, aby w odpowiednich przypadkach obsługiwała te działania.
Zapoznaj się też z listą zmian w działaniu, które wpływają na wszystkie aplikacje działające na Androidzie 15 niezależnie od targetSdkVersion aplikacji.
Główna funkcja
Android 15 modyfikuje lub rozszerza różne podstawowe funkcje systemu Android.
Zmiany w usługach działających na pierwszym planie
W Androidzie 15 wprowadzamy następujące zmiany w usługach działających na pierwszym planie.
- Zachowanie usługi synchronizacji danych na pierwszym planie w przypadku przekroczenia limitu czasu
- Nowy typ usługi na pierwszym planie do przetwarzania multimediów
- Ograniczenia dotyczące odbiorników
BOOT_COMPLETEDuruchamiających usługi na pierwszym planie - Ograniczenia dotyczące uruchamiania usług na pierwszym planie, gdy aplikacja ma uprawnienie
SYSTEM_ALERT_WINDOW
Zachowanie limitu czasu usługi na pierwszym planie synchronizującej dane
Android 15 wprowadza nowe zachowanie dotyczące limitu czasu w przypadku dataSync w aplikacjach kierowanych na Androida 15 (poziom interfejsu API 35) lub nowszego. Takie zachowanie dotyczy też nowego mediaProcessingtypu usługi działającej na pierwszym planie.
System zezwala na działanie usług dataSync aplikacji przez łącznie 6 godzin w ciągu 24 godzin, po czym wywołuje metodę Service.onTimeout(int, int) działającej usługi (wprowadzoną w Androidzie 15). W tej chwili usługa ma kilka sekund na wywołanie metody Service.stopSelf(). Gdy wywołana zostanie usługa Service.onTimeout(), nie będzie ona już usługą na pierwszym planie. Jeśli usługa nie wywołuje funkcji Service.stopSelf(), system zgłasza wewnętrzny wyjątek. Wyjątek jest rejestrowany w Logcat z tym komunikatem:
Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type dataSync did not stop within its timeout: [component name]"
Aby uniknąć problemów związanych z tą zmianą zachowania, możesz wykonać co najmniej jedną z tych czynności:
- Zaimplementuj nową metodę
Service.onTimeout(int, int)w swojej usłudze. Gdy aplikacja otrzyma połączenie zwrotne, w ciągu kilku sekund zadzwoń pod numerstopSelf(). Jeśli nie zatrzymasz aplikacji od razu, system wygeneruje błąd. - Upewnij się, że usługi
dataSyncTwojej aplikacji nie działają przez łącznie 6 godzin w dowolnym okresie 24 godzin (chyba że użytkownik wejdzie w interakcję z aplikacją, resetując minutnik). - Uruchamiaj
dataSyncusługi na pierwszym planie wyłącznie w wyniku bezpośredniej interakcji z użytkownikiem. Ponieważ aplikacja znajduje się na pierwszym planie w momencie uruchomienia usługi, usługa ma pełne 6 godzin od uruchomienia w tle. - Zamiast usługi na pierwszym planie
dataSyncużyj alternatywnego interfejsu API.
Jeśli w ciągu ostatnich 24 godzin usługi dataSync na pierwszym planie Twojej aplikacji działały przez 6 godzin, nie możesz uruchomić innej usługi dataSync na pierwszym planie chyba że użytkownik przełączył aplikację na pierwszy plan (co spowoduje zresetowanie minutnika). Jeśli spróbujesz uruchomić inną usługę na pierwszym planie dataSync, system wygeneruje ForegroundServiceStartNotAllowedException z komunikatem o błędzie, np. „Limit czasu dla usługi działającej na pierwszym planie typu dataSync został już wyczerpany”.
Testowanie
Aby przetestować działanie aplikacji, możesz włączyć czas oczekiwania na synchronizację danych, nawet jeśli aplikacja nie jest kierowana na Androida 15 (o ile działa na urządzeniu z Androidem 15). Aby włączyć limity czasu, uruchom to polecenie adb:
adb shell am compat enable FGS_INTRODUCE_TIME_LIMITS your-package-name
Możesz też dostosować limit czasu oczekiwania, aby łatwiej testować działanie aplikacji po osiągnięciu limitu. Aby ustawić nowy okres oczekiwania, uruchom to polecenie adb:
adb shell device_config put activity_manager data_sync_fgs_timeout_duration duration-in-milliseconds
Nowy typ usługi działającej na pierwszym planie do przetwarzania multimediów
W Androidzie 15 wprowadziliśmy nowy typ usługi na pierwszym planie: mediaProcessing. Ten typ usługi jest odpowiedni do operacji takich jak transkodowanie plików multimedialnych. Na przykład aplikacja multimedialna może pobrać plik audio i przed odtworzeniem musi przekonwertować go na inny format. Możesz użyć usługi mediaProcessing na pierwszym planie, aby mieć pewność, że konwersja będzie kontynuowana nawet wtedy, gdy aplikacja będzie działać w tle.
System zezwala na działanie usług mediaProcessing aplikacji przez łącznie 6 godzin w okresie 24 godzin. Po tym czasie system wywołuje metodę Service.onTimeout(int, int) (wprowadzoną w Androidzie 15). Obecnie usługa ma kilka sekund na wywołanie funkcji Service.stopSelf(). Jeśli usługa nie wywołuje funkcji Service.stopSelf(), system zgłasza wewnętrzny wyjątek. Wyjątek jest logowany w Logcat z tym komunikatem:
Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type mediaProcessing did not stop within its timeout: [component name]"
Aby uniknąć wyjątku, wykonaj jedną z tych czynności:
- Zaimplementuj nową metodę
Service.onTimeout(int, int)w swojej usłudze. Gdy aplikacja otrzyma połączenie zwrotne, w ciągu kilku sekund zadzwoń pod numerstopSelf(). (jeśli nie zatrzymasz aplikacji od razu, system wygeneruje błąd). - Upewnij się, że usługi
mediaProcessingw aplikacji nie działają dłużej niż 6 godzin w ciągu 24 godzin (chyba że użytkownik wchodzi w interakcję z aplikacją, zresetowując w ten sposób timer). - Uruchamiaj usługi na pierwszym planie
mediaProcessingtylko w wyniku bezpośredniej interakcji z użytkownikiem. Ponieważ aplikacja jest na pierwszym planie, gdy usługa się uruchamia, ma ona 6 godzin na działanie po przejściu aplikacji w tło. - Zamiast usługi na pierwszym planie
mediaProcessingużyj alternatywnego interfejsu API, takiego jak WorkManager.
Jeśli w ciągu ostatnich 24 godzin usługi mediaProcessing na pierwszym planie aplikacji działały przez 6 godzin, nie możesz uruchomić innej usługi mediaProcessing na pierwszym planie chyba że użytkownik przełączył aplikację na pierwszy plan (co spowoduje zresetowanie minutnika). Jeśli spróbujesz uruchomić inną usługę działającą na pierwszym planie mediaProcessing, system wyświetli komunikat o błędzie podobny do „Czas limitu usługi działającej na pierwszym planie typu mediaProcessing został już wykorzystany”.ForegroundServiceStartNotAllowedException
Więcej informacji o typie usługi mediaProcessing znajdziesz w artykule Zmiany w typach usług na pierwszym planie w Androidzie 15: przetwarzanie multimediów.
Testowanie
Aby przetestować działanie aplikacji, możesz włączyć limity czasu przetwarzania multimediów, nawet jeśli aplikacja nie jest kierowana na Androida 15 (o ile jest uruchomiona na urządzeniu z Androidem 15). Aby włączyć limity czasu, uruchom to polecenie adb:
adb shell am compat enable FGS_INTRODUCE_TIME_LIMITS your-package-name
Możesz też dostosować czas oczekiwania, aby łatwiej testować działanie aplikacji po osiągnięciu limitu. Aby ustawić nowy okres oczekiwania, uruchom to polecenie adb:
adb shell device_config put activity_manager media_processing_fgs_timeout_duration duration-in-milliseconds
Ograniczenia dotyczące odbiorników BOOT_COMPLETED uruchamiających usługi na pierwszym planie
Wprowadziliśmy nowe ograniczenia dotyczące odbiorników BOOT_COMPLETED
usług działających na pierwszym planie. Odbiorcy BOOT_COMPLETED nie mogą uruchamiać modułu
te typy usług na pierwszym planie:
dataSynccameramediaPlaybackphoneCallmediaProjectionmicrophone(to ograniczenie obowiązuje w przypadkumicrophoneod Androida 14)
Jeśli odbiornik BOOT_COMPLETED próbuje uruchomić którykolwiek z tych typów działania na pierwszym planie
usług, system wywołuje ForegroundServiceStartNotAllowedException.
Testowanie
Aby przetestować działanie aplikacji, możesz włączyć te nowe ograniczenia, nawet jeśli aplikacja nie jest kierowana na Androida 15 (o ile jest ona uruchomiona na urządzeniu z Androidem 15). Uruchom to polecenie adb:
adb shell am compat enable FGS_BOOT_COMPLETED_RESTRICTIONS your-package-name
Aby wysłać komunikat typu BOOT_COMPLETED bez ponownego uruchamiania urządzenia:
uruchom to polecenie adb:
adb shell am broadcast -a android.intent.action.BOOT_COMPLETED your-package-name
Ograniczenia dotyczące uruchamiania usług na pierwszym planie, gdy aplikacja ma uprawnienia SYSTEM_ALERT_WINDOW
Wcześniej, jeśli aplikacja miała uprawnienia SYSTEM_ALERT_WINDOW, mogła uruchomić usługę na pierwszym planie, nawet jeśli była w tej chwili uruchomiona w tle (jak opisano w wyjątkach od ograniczeń dotyczących uruchamiania w tle).
Jeśli aplikacja jest kierowana na Androida 15, wykluczenie jest teraz bardziej precyzyjne. Aplikacja musi mieć teraz uprawnienia SYSTEM_ALERT_WINDOW, a także mieć widoczne okno nakładki. Oznacza to, że aplikacja musi najpierw uruchomić okno TYPE_APPLICATION_OVERLAY i to okno musi być widoczne, zanim uruchomisz usługę na pierwszym planie.
Jeśli aplikacja próbuje uruchomić usługę działającą na pierwszym planie w tle bez spełnienia tych nowych wymagań (i nie ma żadnych innych wyjątków), system zgłasza ForegroundServiceStartNotAllowedException.
Jeśli Twoja aplikacja deklaruje uprawnienie SYSTEM_ALERT_WINDOW i uruchamia usługi na pierwszym planie z poziomu usług działających w tle, może być dotknięta tą zmianą. Jeśli Twoja aplikacja otrzymuje ForegroundServiceStartNotAllowedException, sprawdź kolejność jej działań i upewnij się, że aplikacja ma już aktywne okno nakładki, zanim spróbuje uruchomić usługę na pierwszym planie z tle. Aby sprawdzić, czy okno nakładki jest obecnie widoczne, wywołaj View.getWindowVisibility() lub zastąp View.onWindowVisibilityChanged(), aby otrzymywać powiadomienia o zmianie widoczności.
Testowanie
Aby przetestować działanie aplikacji, możesz włączyć te nowe ograniczenia, nawet jeśli aplikacja nie jest kierowana na Androida 15 (o ile jest ona uruchomiona na urządzeniu z Androidem 15). Aby włączyć nowe ograniczenia dotyczące uruchamiania usług na pierwszym planie w tle, uruchom to polecenie adb:
adb shell am compat enable FGS_SAW_RESTRICTIONS your-package-name
Zmiany dotyczące tego, kiedy aplikacje mogą modyfikować globalny stan trybu Nie przeszkadzać
以 Android 15(API 级别 35)及更高版本为目标平台的应用无法再更改设备上的勿扰 (DND) 功能的全局状态或政策(无论是通过修改用户设置还是关闭勿扰模式)。相反,应用必须提供 AutomaticZenRule,系统会将其与现有的“最严格的政策优先”方案合并为一个全局政策。对之前会影响全局状态的现有 API 的调用(setInterruptionFilter、setNotificationPolicy)会导致创建或更新隐式 AutomaticZenRule,该 AutomaticZenRule 会根据这些 API 调用的调用周期开启和关闭。
请注意,只有当应用调用 setInterruptionFilter(INTERRUPTION_FILTER_ALL) 并希望该调用停用之前由其所有者激活的 AutomaticZenRule 时,此更改才会影响可观察到的行为。
Zmiany w interfejsie OpenJDK API
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(); }
Bezpieczeństwo
Android 15 zawiera zmiany, które zwiększają bezpieczeństwo systemu, aby chronić aplikacje i użytkowników przed złośliwymi aplikacjami.
Ograniczone wersje protokołu TLS
Android 15 ogranicza użycie TLS w wersjach 1.0 i 1.1. Te wersje zostały wcześniej wycofane w Androidzie, ale teraz są niedozwolone w przypadku aplikacji kierowanych na Androida 15.
Zabezpieczone uruchamianie aktywności w tle
Android 15 做出了一些变更,可防止恶意后台应用将其他应用置于前台、提升自身权限并滥用用户互动,从而保护用户免受恶意应用的侵害,并让用户更好地控制自己的设备。自 Android 10(API 级别 29)起,后台 activity 启动受到限制。
其他更改
- 将
PendingIntent创建者更改为默认阻止后台活动启动。这有助于防止应用意外创建可能被恶意行为者滥用的PendingIntent。 - 除非
PendingIntent发送方允许,否则请勿将应用转至前台。此变更旨在防止恶意应用滥用在后台启动 activity 的功能。默认情况下,除非创建者允许后台 activity 启动权限或发送者具有后台 activity 启动权限,否则不允许应用将任务堆栈带到前台。 - 控制任务堆栈的顶层 activity 如何完成其任务。如果顶部 activity 完成了一项任务,Android 将返回到上次处于活跃状态的任务。此外,如果非顶部 activity 完成其任务,Android 会返回到主屏幕;它不会阻止此非顶部 activity 完成。
- 防止从其他应用启动任意 activity 进入您自己的任务。此变更可防止恶意应用通过创建看似来自其他应用的 activity 来对用户进行钓鱼式攻击。
- 阻止将非可见窗口纳入后台 activity 启动的考虑范围。这有助于防止恶意应用滥用后台活动启动来向用户显示不必要或恶意的内容。
Bezpieczniejsze zamiary
W Androidzie 15 wprowadzono StrictMode w przypadku intencji.
Aby wyświetlić szczegółowe dzienniki naruszeń zasad korzystania z Intent, wykonaj te czynności:
Kotlin
fun onCreate() { StrictMode.setVmPolicy(VmPolicy.Builder() .detectUnsafeIntentLaunch() .build() ) }
Java
public void onCreate() { StrictMode.setVmPolicy(new VmPolicy.Builder() .detectUnsafeIntentLaunch() .build()); }
Wrażenia użytkowników i interfejs systemu
Android 15 zawiera kilka zmian, które mają na celu zapewnienie bardziej spójnej i intuicyjnej obsługi.
Zmiany w oknie
W Androidzie 15 wprowadzono 2 zmiany związane z współrzędnymi okna: domyślnie wymuszono tryb pełnoekranowy, a także wprowadzono zmiany konfiguracji, takie jak domyślna konfiguracja pasków systemowych.
Edge-to-edge enforcement
Jeśli aplikacja jest kierowana na Androida 15 (poziom API 35), domyślnie wyświetla się bez ramki na urządzeniach z tą wersją systemu.
Jest to zmiana powodująca niezgodność wsteczną, która może mieć negatywny wpływ na interfejs aplikacji. Zmiany dotyczą tych obszarów interfejsu:
- Pasek nawigacji z obsługą gestów
- Domyślnie przezroczysty.
- Odsunięcie od dołu jest wyłączone, więc treść jest rysowana za paskiem nawigacji systemu, chyba że zastosowano wcięcia.
setNavigationBarColoriR.attr#navigationBarColorsą wycofane i nie mają wpływu na nawigację przy użyciu gestów.setNavigationBarContrastEnforcediR.attr#navigationBarContrastEnforcednadal nie mają wpływu na nawigację przy użyciu gestów.
- Nawigacja przy użyciu 3 przycisków
- Domyślnie ustawiona jest przezroczystość 80%, a kolor może być zgodny z tłem okna.
- Odsunięcie od dołu jest wyłączone, więc treść jest rysowana za paskiem nawigacji systemu, chyba że zastosowano wcięcia.
setNavigationBarColoriR.attr#navigationBarColorsą domyślnie ustawione tak, aby pasowały do tła okna. Aby zastosować to ustawienie domyślne, tło okna musi być obiektem rysowalnym w kolorze. Ten interfejs API jest wycofany, ale nadal wpływa na nawigację przy użyciu 3 przycisków.setNavigationBarContrastEnforcediR.attr#navigationBarContrastEnforcedsą domyślnie ustawione na wartość „prawda”, co powoduje dodanie tła o przezroczystości 80% w nawigacji przy użyciu 3 przycisków.
- Pasek stanu
- Domyślnie przezroczysty.
- Odsunięcie od góry jest wyłączone, więc treść jest rysowana za paskiem stanu, chyba że zastosowano wcięcia.
setStatusBarColoriR.attr#statusBarColorsą wycofane i nie mają wpływu na Androida 15.setStatusBarContrastEnforcediR.attr#statusBarContrastEnforcedsą wycofane, ale nadal mają wpływ na Androida 15.
- Wycięcie w ekranie
- W przypadku okien niepływających wartość
layoutInDisplayCutoutModemusi być równaLAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS. WartościSHORT_EDGES,NEVERiDEFAULTsą interpretowane jakoALWAYS, dzięki czemu użytkownicy nie widzą czarnego paska spowodowanego wycięciem w ekranie, a aplikacja wyświetla się bez ramki.
- W przypadku okien niepływających wartość
Poniższy przykład pokazuje aplikację przed i po kierowaniu na Androida 15 (poziom API 35) oraz przed i po zastosowaniu wcięć. Ten przykład nie jest wyczerpujący i może wyglądać inaczej w Androidzie Auto.
Co sprawdzić, jeśli aplikacja już wyświetla się bez ramki
Jeśli Twoja aplikacja już wyświetla się bez ramki i stosuje wcięcia, w większości przypadków nie musisz nic robić, z wyjątkiem tych sytuacji: Nawet jeśli uważasz, że nie musisz nic robić, zalecamy przetestowanie aplikacji.
- Masz okno niepływające, np.
Activity, które używa wartościSHORT_EDGES,NEVERlubDEFAULTzamiastLAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS. Jeśli aplikacja ulega awarii podczas uruchamiania, przyczyną może być ekran powitalny. Możesz zaktualizować zależność core splashscreen do wersji 1.2.0-alpha01 lub nowszej albo ustawićwindow.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always. - Mogą występować ekrany o mniejszym natężeniu ruchu z zasłoniętym interfejsem. Sprawdź, czy te rzadziej odwiedzane ekrany nie mają zasłoniętego interfejsu. Ekrany o mniejszym natężeniu ruchu to m.in.:
- ekrany wprowadzające lub logowania,
- strony ustawień.
Co sprawdzić, jeśli aplikacja nie wyświetla się jeszcze bez ramki
Jeśli Twoja aplikacja nie wyświetla się jeszcze bez ramki, najprawdopodobniej musisz coś zmienić. Oprócz scenariuszy dotyczących aplikacji, które już wyświetlają się bez ramki, musisz wziąć pod uwagę te kwestie:
- Jeśli Twoja aplikacja używa komponentów Material 3 (
androidx.compose.material3) w Compose, takich jakTopAppBar,BottomAppBar, iNavigationBar, te komponenty nie powinny mieć wpływu, ponieważ automatycznie obsługują wcięcia. - Jeśli Twoja aplikacja używa komponentów Material 2 (
androidx.compose.material) w Compose, te komponenty nie obsługują automatycznie wcięć. Możesz jednak uzyskać dostęp do wcięć i zastosować je ręcznie. W androidx.compose.material 1.6.0 i nowszych wersjach użyj parametruwindowInsets, aby ręcznie zastosować wcięcia w przypadku komponentówBottomAppBar,TopAppBar,BottomNavigationiNavigationRail. Podobnie użyj parametrucontentWindowInsetsdlaScaffold. - Jeśli Twoja aplikacja używa widoków i komponentów Material
(
com.google.android.material), większość komponentów Material opartych na widokach, takich jakBottomNavigationView,BottomAppBar,NavigationRailViewczyNavigationView, obsługuje wcięcia i nie wymaga dodatkowej pracy. Jeśli jednak używasz komponentuAppBarLayout, musisz dodaćandroid:fitsSystemWindows="true". - W przypadku niestandardowych komponentów kompozycyjnych zastosuj wcięcia ręcznie jako dopełnienie. Jeśli treść znajduje się w komponencie
Scaffold, możesz użyć wcięć za pomocą wartości dopełnieniaScaffoldpadding values. W przeciwnym razie zastosuj dopełnienie za pomocą jednego z komponentówWindowInsets. - Jeśli Twoja aplikacja używa widoków i
BottomSheet,SideSheetlub niestandardowych kontenerów, zastosuj dopełnienie za pomocąViewCompat.setOnApplyWindowInsetsListener. W przypadkuRecyclerViewzastosuj dopełnienie za pomocą tego odbiornika i dodaj teżclipToPadding="false".
Co sprawdzić, jeśli aplikacja musi oferować niestandardową ochronę tła
Jeśli Twoja aplikacja musi oferować niestandardową ochronę tła w przypadku nawigacji przy użyciu 3 przycisków lub paska stanu, powinna umieścić komponent kompozycyjny lub widok za paskiem systemowym za pomocą WindowInsets.Type#tappableElement(), aby uzyskać wysokość paska nawigacji przy użyciu 3 przycisków, lub WindowInsets.Type#statusBars.
Dodatkowe materiały dotyczące wyświetlania bez ramki
Dodatkowe informacje o stosowaniu wcięć znajdziesz w przewodnikach Wyświetlanie bez ramki w widokach i Wyświetlanie bez ramki w Compose.
Wycofane interfejsy API
Te interfejsy API są wycofane, ale nie wyłączone:
R.attr#enforceStatusBarContrastR.attr#navigationBarColor(w przypadku nawigacji przy użyciu 3 przycisków z przezroczystością 80%)Window#isStatusBarContrastEnforcedWindow#setNavigationBarColor(w przypadku nawigacji przy użyciu 3 przycisków z przezroczystością 80%)Window#setStatusBarContrastEnforced
Te interfejsy API są wycofane i wyłączone:
R.attr#navigationBarColor(w przypadku nawigacji przy użyciu gestów)R.attr#navigationBarDividerColorR.attr#statusBarColorWindow#setDecorFitsSystemWindowsWindow#getNavigationBarColorWindow#getNavigationBarDividerColorWindow#getStatusBarColorWindow#setNavigationBarColor(w przypadku nawigacji przy użyciu gestów)Window#setNavigationBarDividerColorWindow#setStatusBarColor
Stable configuration
Jeśli Twoja aplikacja jest kierowana na Androida 15 (API na poziomie 35) lub nowszego, Configuration nie wyklucza już pasków systemowych. Jeśli do obliczania układu używasz klasy Configuration, zastąp ją lepszymi alternatywami, takimi jak odpowiednia klasa ViewGroup, WindowInsets lub WindowMetricsCalculator, w zależności od potrzeb.
Configuration jest dostępny od interfejsu API 1. Zwykle jest ona uzyskiwana z Activity.onConfigurationChanged. Zawiera informacje takie jak gęstość okien, orientacja i rozmiary. Ważną cechą rozmiarów okien zwracanych przez Configuration jest to, że wcześniej wykluczały one paski systemowe.
Rozmiar konfiguracji jest zwykle używany do wybierania zasobów, np. /res/layout-h500dp, i nadal jest to prawidłowy przypadek użycia. Jednak używanie go do obliczania układu zawsze było odradzane. Jeśli tak jest, odsuń się od niego. Zamiast Configuration użyj czegoś bardziej odpowiedniego w zależności od konkretnego przypadku użycia.
Jeśli używasz go do obliczania układu, użyj odpowiedniego elementu ViewGroup, np. CoordinatorLayout lub ConstraintLayout. Jeśli używasz go do określania wysokości paska nawigacyjnego systemu, użyj WindowInsets. Jeśli chcesz poznać bieżący rozmiar okna aplikacji, użyj computeCurrentWindowMetrics.
Poniżej znajdziesz listę pól, których dotyczy ta zmiana:
- Rozmiary
Configuration.screenWidthDpiscreenHeightDpnie wykluczają już pasków systemu. - Usługa
Configuration.smallestScreenWidthDpjest pośrednio objęta zmianami w usługachscreenWidthDpiscreenHeightDp. - Na
Configuration.orientationpośrednio wpływają zmiany wscreenWidthDpiscreenHeightDpna urządzeniach o ekranach zbliżonych do kwadratu. Display.getSize(Point)jest pośrednio objęty zmianami wConfiguration. Zostało to wycofane od poziomu API 30.Display.getMetrics()działa w ten sposób od poziomu API 33.
Atrybut elegantTextHeight ma domyślnie wartość true.
For apps targeting Android 15 (API level 35), the
elegantTextHeight TextView attribute
becomes true by default, replacing the compact font used by default with some
scripts that have large vertical metrics with one that is much more readable.
The compact font was introduced to prevent breaking layouts; Android 13 (API
level 33) prevents many of these breakages by allowing the text layout to
stretch the vertical height utilizing the fallbackLineSpacing
attribute.
In Android 15, the compact font still remains in the system, so your app can set
elegantTextHeight to false to get the same behavior as before, but it is
unlikely to be supported in upcoming releases. So, if your app supports the
following scripts: Arabic, Lao, Myanmar, Tamil, Gujarati, Kannada, Malayalam,
Odia, Telugu or Thai, test your app by setting elegantTextHeight to true.
elegantTextHeight behavior for apps targeting Android 14 (API level 34) and lower.
elegantTextHeight behavior for apps targeting Android 15.Szerokość widoku TextView zmienia się w przypadku złożonych kształtów liter
W poprzednich wersjach Androida niektóre czcionki kursywe lub języki ze złożonym kształtem mogą rysować litery w obszarze poprzedniego lub następnego znaku.
Zdarzało się, że takie litery były obcinane na początku lub na końcu.
Od Androida 15 TextView przydziela wystarczającą ilość miejsca na wyświetlenie takich liter, a aplikacje mogą prosić o dodatkowe wypełnienie po lewej stronie, aby zapobiec przycięciu.
Ta zmiana wpływa na sposób określania szerokości przez TextView, więc TextView domyślnie przydziela więcej szerokości, jeśli aplikacja jest kierowana na Androida 15 (poziom API 35) lub nowszego. Możesz włączyć lub wyłączyć tę funkcję, wywołując interfejs API setUseBoundsForWidth w komponencie TextView.
Dodanie dopełnienia z lewej strony może spowodować niewłaściwe ułożenie istniejących układów, dlatego dopełnienie nie jest dodawane domyślnie nawet w przypadku aplikacji kierowanych na Androida 15 lub nowszego.
Możesz jednak dodać dodatkowy margines, aby zapobiec przycięciu, wywołując funkcję setShiftDrawingOffsetForStartOverhang.
W poniższych przykładach pokazujemy, jak te zmiany mogą poprawić układ tekstu w przypadku niektórych czcionek i języków.
<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" />
Domyślna wysokość wiersza w widoku EditText z uwzględnieniem ustawień regionalnych
W poprzednich wersjach Androida układ tekstu rozciągał wysokość tekstu, aby dopasować ją do wysokości wiersza czcionki odpowiadającej bieżącemu ustawieniu języka. Jeśli na przykład treści były w języku japońskim, to ze względu na to, że wysokość linii czcionki japońskiej jest nieco większa niż czcionki łacińskiej, wysokość tekstu była nieco większa. Jednak pomimo tych różnic w wysokościach wierszy element EditText miał jednakowy rozmiar niezależnie od używanej lokalizacji, jak pokazano na poniższym obrazku:
EditText, które mogą zawierać tekst w języku angielskim (en), japońskim (ja) i birmańskim (my). Wysokość EditText jest taka sama, mimo że te języki mają różne wysokości linii.W przypadku aplikacji kierowanych na Androida 15 (poziom interfejsu API 35) minimalna wysokość linii jest teraz zarezerwowana dla EditText, aby pasowała do czcionki referencyjnej dla określonego języka, jak pokazano na poniższym obrazie:
EditText, które mogą zawierać tekst w języku angielskim (en), japońskim (ja) i birmańskim (my). Wysokość EditText uwzględnia teraz miejsce na domyślną wysokość wiersza dla czcionek w tych językach.W razie potrzeby aplikacja może przywrócić poprzednie działanie, ustawiając atrybut useLocalePreferredLineHeightForMinimum na false. Może też ustawić niestandardowe minimalne dane pionowe za pomocą interfejsu API setMinimumFontMetrics w językach Kotlin i Java.
Aparat i multimedia
W Androidzie 15 wprowadziliśmy te zmiany w działaniu aparatu i multimediów w przypadku aplikacji kierowanych na Androida 15 lub nowszego.
Ograniczenia dotyczące żądania aktywności audio
Apps that target Android 15 (API level 35) must be the top app or running a
foreground service in order to request audio focus. If an app
attempts to request focus when it does not meet one of these requirements, the
call returns AUDIOFOCUS_REQUEST_FAILED.
You can learn more about audio focus at Manage audio focus.
Zaktualizowane ograniczenia dotyczące pakietów SDK innych firm
Android 15 zawiera zaktualizowane listy ograniczonych interfejsów innych niż SDK, które powstały na podstawie współpracy z deweloperami Androida i najnowszych testów wewnętrznych. Zawsze, gdy jest to możliwe, udostępniamy publiczne alternatywy, zanim ograniczymy interfejsy inne niż SDK.
Jeśli Twoja aplikacja nie jest kierowana na Androida 15, niektóre z tych zmian mogą nie mieć na nią natychmiastowego wpływu. Jednak chociaż w zależności od docelowego poziomu interfejsu API aplikacji może ona mieć dostęp do niektórych interfejsów innych niż SDK, używanie dowolnej metody lub pola spoza SDK zawsze wiąże się z wysokim ryzykiem awarii aplikacji.
Jeśli nie masz pewności, czy Twoja aplikacja korzysta z interfejsów innych niż SDK, możesz sprawdzić to, testując aplikację. Jeśli Twoja aplikacja korzysta z interfejsów innych niż SDK, zacznij planować migrację do alternatywnych pakietów SDK. Rozumiemy jednak, że niektóre aplikacje mają uzasadnione przypadki użycia interfejsów innych niż SDK. Jeśli nie możesz znaleźć alternatywy dla używania interfejsu innego niż SDK w przypadku funkcji w aplikacji, powinieneś poprosić o nowy publiczny interfejs API.
如需详细了解此 Android 版本中的变更,请参阅 Android 15 中有关限制非 SDK 接口的更新。如需全面了解有关非 SDK 接口的详细信息,请参阅对非 SDK 接口的限制。