Podobnie jak w przypadku poprzednich wersji, Android 15 zawiera zmiany działania, które mogą mieć wpływ na Twoją aplikację. Poniższe zmiany działania dotyczą wyłącznie aplikacji kierowanych na Androida 15 lub nowszego. Jeśli Twoja aplikacja jest kierowana na Androida 15 lub nowszego, musisz ją odpowiednio zmodyfikować, aby obsługiwała te funkcje (w stosownych przypadkach).
Zapoznaj się też z listą zmian zachowania, które wpływają na wszystkie aplikacje działające na Androidzie 15, niezależnie od targetSdkVersion
Twojej 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_COMPLETED
uruchamiają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 mediaProcessing
typu 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 system wywołuje metodę Service.onTimeout(int, int)
(wprowadzoną w Androidzie 15). Obecnie usługa ma kilka sekund na wywołanie funkcji 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
dataSync
w aplikacji nie działają dłużej niż 6 godzin w ciągu 24 godzin (chyba że użytkownik wchodzi w interakcję z aplikacją, resetując timer). - Uruchamiaj
dataSync
usł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
dataSync
uż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ę dataSync
na pierwszym planie, system wyświetli komunikat o błędzie, np. „Czas limitu został już wyczerpany dla usługi na pierwszym planie typu dataSync”.ForegroundServiceStartNotAllowedException
Testowanie
Aby przetestować działanie aplikacji, możesz włączyć limity czasu synchronizacji danych, 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ć 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
mediaProcessing
w 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
mediaProcessing
tylko 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
mediaProcessing
uż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:
dataSync
camera
mediaPlayback
phoneCall
mediaProjection
microphone
(to ograniczenie obowiązuje w przypadkumicrophone
od 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 kontynuuje odświeżanie podstawowych bibliotek Androida, aby dostosować je do funkcji w najnowszych wersjach OpenJDK LTS.
Niektóre z tych zmian mogą mieć wpływ na zgodność aplikacji kierowanych na Androida 15 (poziom interfejsu API 35):
Zmiany w interfejsach API do formatowania ciągów znaków: weryfikacja indeksu argumentu, flag, szerokości i dokładności jest teraz bardziej rygorystyczna podczas korzystania z tych interfejsów API:
String.format()
iFormatter.format()
:String.format(String, Object[])
String.format(Locale, String, Object[])
Formatter.format(String, Object[])
Formatter.format(Locale, String, Object[])
Na przykład gdy użyjesz indeksu argumentu 0 (
%0
w formatowaniu ciągu znaków), zostanie rzucone to wyjątku:IllegalFormatArgumentIndexException: Illegal format argument index = 0
W takim przypadku problem można rozwiązać, używając indeksu argumentu 1 (
%1
) w wierszu formatu.Zmiany typu komponentu
Arrays.asList(...).toArray()
: gdy używasz funkcjiArrays.asList(...).toArray()
, typ komponentu powstałego tablicy jest terazObject
, a nie typ elementów podrzędnej tablicy. Ten kod powoduje wyjątekClassCastException
:String[] elements = (String[]) Arrays.asList("one", "two").toArray();
W tym przypadku, aby zachować wartość
String
jako typ komponentu w wynikającym z niego tablicy, możesz użyć elementuCollection.toArray(Object[])
:String[] elements = Arrays.asList("two", "one").toArray(new String[0]);
Zmiany w obsługiwaniu kodu języka: gdy używasz interfejsu API
Locale
, kody języka hebrajskiego, jidysz i indonezyjskiego nie są już konwertowane na ich przestarzałe formy (hebr.:iw
, jidysz:ji
, indonezyjski:in
). Podczas określania kodu języka dla jednego z tych języków użyj kodów z ISO 639-1 (hebr.:he
, jidysz:yi
, indonezyjski:id
).Zmiany w losowych sekwencjach liczb całkowitych: po zmianach wprowadzonych w https://bugs.openjdk.org/browse/JDK-8301574 metody
Random.ints()
zwracają teraz inną sekwencję liczb niż metodyRandom.nextInt()
:Zwykle ta zmiana nie powinna powodować nieprawidłowego działania aplikacji, ale kod nie powinien zakładać, że sekwencja wygenerowana z metod
Random.ints()
będzie pasować doRandom.nextInt()
.
Nowy interfejs API SequencedCollection
może wpłynąć na zgodność aplikacji po zaktualnieniu compileSdk
w konfiguracji kompilacji aplikacji, aby używać Androida 15 (poziom API 35):
Konflikt z funkcjami rozszerzenia
MutableList.removeFirst()
iMutableList.removeLast()
w plikukotlin-stdlib
Typ
List
w języku Java jest mapowany na typMutableList
w Kotlinie. InterfejsyList.removeFirst()
iList.removeLast()
zostały wprowadzone w Androidzie 15 (poziom interfejsu API 35), dlatego kompilator Kotlina rozwiązuje wywołania funkcji, np.list.removeFirst()
, statycznie do nowych interfejsówList
, a nie do funkcji rozszerzeń wkotlin-stdlib
.Jeśli aplikacja zostanie ponownie skompilowana z wartością
compileSdk
równą35
, a wartościąminSdk
równą34
lub niższą, a następnie zostanie uruchomiona na Androidzie 14 lub starszym, wystąpi błąd czasu wykonywania:java.lang.NoSuchMethodError: No virtual method removeFirst()Ljava/lang/Object; in class Ljava/util/ArrayList;
Istniejąca opcja
NewApi
wtyczki Androida do obsługi Gradle może wykrywać te nowe użycia interfejsu API../gradlew lint
MainActivity.kt:41: Error: Call requires API level 35 (current min is 34): java.util.List#removeFirst [NewApi] list.removeFirst()Aby naprawić wyjątki czasu wykonywania i błędy lint, możesz zastąpić wywołania funkcji
removeFirst()
iremoveLast()
odpowiednio wywołaniamiremoveAt(0)
iremoveAt(list.lastIndex)
w Kotlinie. Jeśli używasz Android Studio Ladybug | 2024.1.3 lub nowszej wersji, możesz też szybko naprawić te błędy.Jeśli opcja sprawdzania kodu została wyłączona, rozważ usunięcie
@SuppressLint("NewApi")
ilintOptions { disable 'NewApi' }
.Konflikt z innymi metodami w języku Java
Do dotychczasowych typów dodano nowe metody, np.
List
iDeque
. Te nowe metody mogą być niezgodne z metodami o tej samej nazwie i typach argumentów w innych interfejsach i klasach. W przypadku kolizji sygnatury metody z niezgodnością kompilatorjavac
generuje błąd w czasie kompilacji. Przykład:Przykład błędu 1:
javac MyList.java
MyList.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 ListPrzykładowy błąd 2:
javac MyList.java
MyList.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 errorPrzykładowy błąd 3:
javac MyList.java
MyList.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 errorAby naprawić te błędy kompilacji, klasa implementująca te interfejsy powinna zastąpić metodę zgodnym typem zwracanym. Na przykład:
@Override public Object getFirst() { return List.super.getFirst(); }
Bezpieczeństwo
Android 15 zawiera zmiany, które poprawiają bezpieczeństwo systemu i chronią aplikacje oraz użytkowników przed złośliwymi aplikacjami.
Wersje TLS z ograniczeniami
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.
Uruchamianie zabezpieczonej aktywności w tle
Android 15 chroni użytkowników przed złośliwymi aplikacjami i daje im większą kontrolę nad ich urządzeniach, dodając zmiany, które uniemożliwiają złośliwym aplikacjom działającym w tle ujawnianie innych aplikacji, podnoszenie ich przywilejów i nadużywanie interakcji użytkownika. Od wersji Android 10 (poziom interfejsu API 29) ograniczono uruchamianie działań w tle.
Blokowanie uruchamiania aktywności przez aplikacje, których identyfikator nie pasuje do najwyższego identyfikatora na stosie
Złośliwe aplikacje mogą uruchomić inną aplikację w ramach tego samego zadania, a następnie
nakładają się na siebie i tworzą wrażenie, że jest to ta aplikacja. To „zadanie
porwanie” omija obecne ograniczenia uruchamiania w tle,
występuje w ramach tego samego widocznego zadania. Aby zmniejszyć to ryzyko, Android 15 dodaje flagę, która blokuje uruchamianie aktywności przez aplikacje, których identyfikator UID nie pasuje do najwyższego identyfikatora UID w steku. Aby wyrazić zgodę na wszystkie aktywności w aplikacji, zaktualizuj
allowCrossUidActivitySwitchFromBelow
w pliku AndroidManifest.xml
aplikacji:
<application android:allowCrossUidActivitySwitchFromBelow="false" >
Nowe zabezpieczenia są aktywne, jeśli są spełnione wszystkie te warunki:
- Aplikacja, w której wprowadzana jest na rynek, jest kierowana na Androida 15.
- Aplikacja u góry stosu zadań jest kierowana na Androida 15.
- Każda widoczna aktywność została objęta nowymi zabezpieczeniami
Jeśli środki bezpieczeństwa są włączone, aplikacje mogą po zakończeniu działania wracać na ekran główny, a nie do ostatniej widocznej aplikacji.
Inne zmiany
Oprócz ograniczenia dopasowania identyfikatorów UID te inne zmiany również uwzględniono:
- Zmień
PendingIntent
twórców na blokowanie uruchamiania aktywności w tle przez domyślne. Zapobiega to przypadkowemu utworzeniu przez aplikacjePendingIntent
, które mogą być wykorzystywane przez hakerów. - Nie przenoś aplikacji na pierwszy plan, chyba że nadawca
PendingIntent
na to zezwala. Ta zmiana ma na celu zapobieganie wykorzystywaniu uruchamianie działań w tle. Domyślnie aplikacje nie są może przenieść stos zadań na pierwszy plan, chyba że twórca wyrazi zgodę uprawnienia do uruchamiania aktywności w tle lub nadawca ma aktywność w tle uprawnienia do uruchamiania. - Określ, w jaki sposób główna aktywność stosu zadań może wykonać zadanie. Jeśli które kończy zadanie, Android wróci do tego, które było jako ostatnia aktywność. Ponadto jeśli aktywność niebędąca na pierwszym planie zakończy swoje działanie, Android wróci do ekranu głównego. Nie zablokuje to zakończenia tej aktywności.
- Zapobiegaj uruchamianiu dowolnych działań z innych aplikacji we własnym zakresie zadanie. Ta zmiana zapobiega wyłudzaniu informacji przez złośliwe aplikacje, tworząc aktywności, które wyglądają jak z innych aplikacji.
- Nie zezwalaj na uwzględnianie niewidocznych okien w aktywności w tle . Pomaga to zapobiegać wykorzystywaniu działania w tle przez złośliwe aplikacje aby wyświetlać użytkownikom niechciane lub szkodliwe treści.
Bezpieczniejsze zamiary
Android 15 wprowadza nowe opcjonalne środki bezpieczeństwa, które zwiększają bezpieczeństwo i stabilność intencji. Te zmiany mają na celu zapobieganie potencjalnym luk w zabezpieczeniach i niewłaściwemu wykorzystywaniu intencji, które mogą być wykorzystywane przez złośliwe aplikacje. W Androidzie 15 wprowadziliśmy 2 główne ulepszenia dotyczące bezpieczeństwa intencji:
- Pasowanie do docelowych filtrów intencji: intencje kierowane na konkretne komponenty muszą dokładnie odpowiadać specyfikacji filtrów intencji docelowych. Jeśli wysyłasz intencję, aby uruchomić działanie innej aplikacji, docelowy komponent intencji musi być zgodny z deklarowanymi filtrami intencji działania odbierającego.
- Intencje muszą mieć działania: intencje bez działania nie będą już pasować do żadnych filtrów intencji. Oznacza to, że intencje używane do uruchamiania działań lub usług muszą mieć wyraźnie zdefiniowane działanie.
Aby sprawdzić, jak Twoja aplikacja reaguje na te zmiany, użyj w niej metody StrictMode
. Aby wyświetlić szczegółowe dzienniki dotyczące naruszeń zasad Intent
, dodaj tę metodę:
Kotlin
fun onCreate() { StrictMode.setVmPolicy(VmPolicy.Builder() .detectUnsafeIntentLaunch() .build() ) }
Java
public void onCreate() { StrictMode.setVmPolicy(new VmPolicy.Builder() .detectUnsafeIntentLaunch() .build()); }
Wrażenia użytkownika i interfejs systemu
Android 15 zawiera kilka zmian, które mają na celu zapewnienie bardziej spójnego i intuicyjnego interfejsu.
Zmiany w oknach wstawnych
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.
Egzekwowanie treści od krawędzi do krawędzi
Aplikacje są domyślnie wyświetlane bez ramki na urządzeniach z Androidem 15, jeśli są kierowane na Androida 15 (poziom API 35).

Jest to zmiana powodująca przerwanie działania, która może negatywnie wpłynąć na interfejs aplikacji. Zmiany dotyczą tych obszarów interfejsu:
- Pasek nawigacyjny z uchwytem gestów
- Domyślnie przezroczysty.
- Odsunięcie od dołu jest wyłączone, więc treści są wyświetlane za paskiem nawigacji systemu, chyba że zastosowano wstawki.
setNavigationBarColor
iR.attr#navigationBarColor
są przestarzałe i nie wpływają na nawigację przy użyciu gestów.setNavigationBarContrastEnforced
iR.attr#navigationBarContrastEnforced
nadal nie mają wpływu na nawigację za pomocą gestów.
- Nawigacja przy użyciu 3 przycisków
- Domyślnie ustawiona jest przezroczystość na poziomie 80%, a kolor może być dopasowany do tła okna.
- Odsunięcie od dołu jest wyłączone, więc treści są wyświetlane za paskiem nawigacji systemu, chyba że zastosowano wstawki.
- Domyślnie kolory
setNavigationBarColor
iR.attr#navigationBarColor
są dopasowywane do tła okna. Aby można było zastosować tę wartość domyślną, tło okna musi być obiektem rysowalnym koloru. Ten interfejs API został wycofany, ale nadal wpływa na nawigację z 3 przyciskami. setNavigationBarContrastEnforced
iR.attr#navigationBarContrastEnforced
są domyślnie ustawione na wartość true, co oznacza, że w nawigacji z 3 przyciskami będzie widoczne 80% przezroczystego tła.
- Pasek stanu
- Domyślnie przezroczysty.
- Odsunięcie w górę jest wyłączone, więc treści są wyświetlane za paskiem stanu, chyba że zastosowano wgłębienia.
setStatusBarColor
iR.attr#statusBarColor
są wycofane i nie mają wpływu na Androida 15.setStatusBarContrastEnforced
iR.attr#statusBarContrastEnforced
są wycofane, ale nadal mają wpływ na Androida 15.
- Wycięcie na wyświetlaczu
layoutInDisplayCutoutMode
nieruchomych okien musi byćLAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
.SHORT_EDGES
,NEVER
iDEFAULT
są interpretowane jakoALWAYS
, aby użytkownicy nie widzieli czarnego paska spowodowanego wycięciem w ekranie.
Ten przykład pokazuje aplikację przed i po kierowaniu na Androida 15 (poziom API 35) oraz przed i po zastosowaniu odcięć.



Co sprawdzić, jeśli aplikacja jest już w trybie edge-to-edge
Jeśli Twoja aplikacja jest już wyświetlana od krawędzi do krawędzi i zawiera wstawione elementy, zmiany nie będą miały większego wpływu na Twoją aplikację, z wyjątkiem tych scenariuszy. Jednak nawet jeśli uważasz, że problem Cię nie dotyczy, zalecamy przetestowanie aplikacji.
- Masz okno nieprzesuwające się, np.
Activity
, które używaSHORT_EDGES
,NEVER
lubDEFAULT
zamiastLAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
. Jeśli aplikacja ulega awarii przy uruchamianiu, może to być spowodowane przez ekran powitalny. Możesz uaktualnić zależność core splashscreen do wersji 1.2.0-alpha01 lub nowszej albo ustawićwindow.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always
. - Mogą się pojawić ekrany o mniejszym natężeniu ruchu z zasłoniętym interfejsem. Sprawdź, czy te ekrany, które są rzadziej odwiedzane, 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 jest jeszcze wyświetlana od krawędzi do krawędzi
Jeśli Twoja aplikacja nie jest jeszcze wyświetlana od krawędzi do krawędzi, prawdopodobnie dotyczy Cię ta zmiana. Oprócz scenariuszy dotyczących aplikacji, które są już wyświetlane w trybie edge-to-edge, należy wziąć pod uwagę te kwestie:
- Jeśli Twoja aplikacja korzysta z komponentów Material 3 (
androidx.compose.material3
) w komponencie kompozytorskim, takich jakTopAppBar
,BottomAppBar
iNavigationBar
, te komponenty prawdopodobnie nie są dotknięte, ponieważ automatycznie obsługują wstawione elementy. - Jeśli Twoja aplikacja korzysta w Compose z komponentów Material 2 (
androidx.compose.material
), te komponenty nie będą automatycznie obsługiwać wstawień. Możesz jednak uzyskać dostęp do wstawionych elementów i zastosować je ręcznie. W androidx.compose.material 1.6.0 i nowszych użyj parametruwindowInsets
, aby ręcznie zastosować wcięcia dlaBottomAppBar
,TopAppBar
,BottomNavigation
iNavigationRail
. Podobnie użyj parametrucontentWindowInsets
w przypadku atrybutuScaffold
. - Jeśli Twoja aplikacja korzysta z widoków i komponentów Material Design (
com.google.android.material
), większość komponentów Material Design opartych na widokach, takich jakBottomNavigationView
,BottomAppBar
,NavigationRailView
lubNavigationView
, obsługuje wbudowane elementy i nie wymaga dodatkowych działań. Jeśli używaszAppBarLayout
, musisz jednak dodaćandroid:fitsSystemWindows="true"
. - W przypadku niestandardowych komponentów zastosuj wstawione elementy ręcznie jako wypełnienie. Jeśli Twój
content znajduje się w
Scaffold
, możesz używać wstawionych elementów, korzystając z wartości wypełnieniaScaffold
. W przeciwnym razie zastosuj wypełnienie za pomocą jednej z opcjiWindowInsets
. - Jeśli Twoja aplikacja używa widoków i kontenerów
BottomSheet
,SideSheet
lub niestandardowych, zastosuj wypełnienie za pomocą elementuViewCompat.setOnApplyWindowInsetsListener
. W przypadkuRecyclerView
zastosuj wypełnienie za pomocą tego listenera i dodajclipToPadding="false"
.
Co sprawdzić, jeśli aplikacja musi zapewniać niestandardową ochronę w tle
Jeśli Twoja aplikacja musi zapewniać niestandardową ochronę w tle w przypadku nawigacji z 3 przyciskami lub paska stanu, powinna umieszczać komponenty lub widoki za pomocą WindowInsets.Type#tappableElement()
, aby uzyskać wysokość paska nawigacji z 3 przyciskami lub WindowInsets.Type#statusBars
.
Dodatkowe materiały dotyczące edge-to-edge
Więcej informacji o ramkach w trybie pełnoekranowym znajdziesz w przewodnikach Wyświetlanie w ramce pełnoekranowej i Tworzenie treści w ramce pełnoekranowej.
Wycofane interfejsy API
Te interfejsy API są przestarzałe, ale nie zostały wyłączone:
R.attr#enforceStatusBarContrast
R.attr#navigationBarColor
(nawigacja przy użyciu 3 przycisków z 80% alfa)Window#isStatusBarContrastEnforced
Window#setNavigationBarColor
(nawigacja przy użyciu 3 przycisków, przezroczystość 80%)Window#setStatusBarContrastEnforced
Te interfejsy API są wycofane i wyłączone:
R.attr#navigationBarColor
(do nawigacji przy użyciu gestów)R.attr#navigationBarDividerColor
R.attr#statusBarColor
Window#setDecorFitsSystemWindows
Window#getNavigationBarColor
Window#getNavigationBarDividerColor
Window#getStatusBarColor
Window#setNavigationBarColor
(do nawigacji przy użyciu gestów)Window#setNavigationBarDividerColor
Window#setStatusBarColor
Stabilna konfiguracja
Jeśli Twoja aplikacja jest kierowana na Androida 15 (poziom API 35) lub nowszego, Configuration
nie wyklucza już pasków systemowych. Jeśli do obliczenia układu używasz rozmiaru ekranu w klasie Configuration
, zastąp go lepszymi alternatywami, takimi jak ViewGroup
, WindowInsets
lub WindowMetricsCalculator
, w zależności od potrzeb.
Interfejs Configuration
jest dostępny od wersji API 1. Zwykle jest ona uzyskiwana z Activity.onConfigurationChanged
. Zawiera on informacje o gęstości okna, orientacji i rozmiarach. Jedną z ważnych cech rozmiarów okien zwracanych przez funkcję Configuration
jest to, że wcześniej wykluczano paski systemu.
Rozmiar konfiguracji jest zwykle używany do wyboru zasobów, np. /res/layout-h500dp
, i nadal jest to ważny przypadek użycia. Nie zalecamy jednak używania go do obliczania układu. Jeśli tak, odejdź od niego. W zależności od przypadku użycia Configuration
należy zastąpić czymś bardziej odpowiednim.
Jeśli używasz go do obliczania układu, użyj odpowiedniej wartości ViewGroup
, np. CoordinatorLayout
lub ConstraintLayout
. Jeśli używasz go do określenia wysokości paska nawigacyjnego systemu, użyj WindowInsets
. Jeśli chcesz sprawdzić bieżący rozmiar okna aplikacji, użyj computeCurrentWindowMetrics
.
Poniżej znajdziesz listę pól, których dotyczy ta zmiana:
- Rozmiary
Configuration.screenWidthDp
iscreenHeightDp
nie wykluczają już pasków systemu. - Zmiany w usługach
screenWidthDp
iscreenHeightDp
mają pośredni wpływ na usługęConfiguration.smallestScreenWidthDp
. Configuration.orientation
jest pośrednio dotknięty zmianami w funkcjachscreenWidthDp
iscreenHeightDp
na urządzeniach z ekranem zbliżonym do kwadratu.Display.getSize(Point)
jest pośrednio dotknięty zmianami wConfiguration
. Został on wycofany od poziomu interfejsu API 30.Display.getMetrics()
działa w ten sposób od poziomu API 33.
Wartość domyślna atrybutu elegantTextHeight to Prawda.
对于以 Android 15(API 级别 35)为目标平台的应用,elegantTextHeight
TextView
属性默认会变为 true
,将默认使用的紧凑字体替换为一些具有较大垂直测量的脚本,使其更易于阅读。紧凑字体旨在防止布局中断;Android 13(API 级别 33)允许文本布局利用 fallbackLineSpacing
属性拉伸垂直高度,从而防止许多此类中断。
在 Android 15 中,系统中仍保留了紧凑字体,因此您的应用可以将 elegantTextHeight
设置为 false
以获得与之前相同的行为,但即将发布的版本不太可能支持此字体。因此,如果您的应用支持以下脚本:阿拉伯语、老挝语、缅甸语、泰米尔语、古吉拉特语、卡纳达语、马拉雅拉姆语、奥里亚语、泰卢固语或泰语,请将 elegantTextHeight
设置为 true
以测试您的应用。

elegantTextHeight
行为。
elegantTextHeight
行为。Zmiany szerokości TextView 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 EditText uwzględniająca lokalizację
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 wprowadzono następujące zmiany zachowania aparatu i multimediów w aplikacjach kierowanych na Androida 15 lub nowszego.
Ograniczenia dotyczące prośby o skupienie się na dźwięku
Aplikacje kierowane na Androida 15 (poziom API 35) muszą być aplikacjami na pierwszym planie lub usługami na pierwszym planie, aby poprosić o uzyskanie kontroli nad dźwiękiem. Jeśli aplikacja próbuje poprosić o skupienie uwagi, gdy nie spełnia jednego z tych wymagań, wywołanie zwraca AUDIOFOCUS_REQUEST_FAILED
.
Więcej informacji o fokusowaniu dźwięku znajdziesz w artykule Zarządzanie fokusem dźwięku.
Zaktualizowane ograniczenia inne niż związane z pakietem SDK
Android 15 包含更新后的受限非 SDK 接口列表(基于与 Android 开发者之间的协作以及最新的内部测试)。在限制使用非 SDK 接口之前,我们会尽可能确保有可用的公开替代方案。
如果您的应用并非以 Android 15 为目标平台,其中一些变更可能不会立即对您产生影响。不过,虽然您的应用可以访问一些非 SDK 接口(具体取决于应用的目标 API 级别),但如果您使用任何非 SDK 方法或字段,应用无法运行的风险始终会很高。
如果您不确定自己的应用是否使用了非 SDK 接口,则可以测试该应用,进行确认。如果您的应用依赖于非 SDK 接口,您应该开始计划迁移到 SDK 替代方案。不过,我们知道某些应用具有使用非 SDK 接口的有效用例。如果您无法为应用中的某项功能找到使用非 SDK 接口的替代方案,则应请求新的公共 API。
如需详细了解此 Android 版本中的变更,请参阅 Android 15 中有关限制非 SDK 接口的更新。如需全面了解有关非 SDK 接口的详细信息,请参阅对非 SDK 接口的限制。