Podobnie jak w poprzednich wersjach, Android 15 wprowadza zmiany w działaniu, które mogą wpłynąć na Twoją aplikację. Poniższe zmiany w działaniu dotyczą tylko aplikacji kierowanych na Androida 15 lub nowszego. Jeśli Twoja aplikacja jest kierowana na Androida 15 lub nowszego, musisz ją zmodyfikować, aby prawidłowo obsługiwała te zachowania (w stosownych przypadkach).
Zapoznaj się też z listą zmian w działaniu, które wpływają na wszystkie aplikacje na Androida 15, niezależnie od targetSdkVersion
aplikacji.
Główna funkcja
Android 15 modyfikuje i rozwija różne podstawowe funkcje systemu Android.
Zmiany dotyczące usług działających na pierwszym planie
Wprowadzamy następujące zmiany w usługach działających na pierwszym planie w Androidzie 15.
- Nowy typ usługi na pierwszym planie przetwarzania multimediów
- Ograniczenia dotyczące
BOOT_COMPLETED
odbiorników uruchamiających usługi na pierwszym planie
Zachowanie limitu czasu usługi synchronizacji danych na pierwszym planie
Android 15 wprowadza nowy limit czasu w dataSync
w przypadku aplikacji kierowanych na Androida 15 lub nowszego. Dotyczy to też nowego typu usługi na pierwszym planie mediaProcessing
.
System zezwala na działanie usług dataSync
aplikacji przez łącznie 6 godzin w ciągu 24 godzin. Po tym czasie system wywołuje metodę Service.onTimeout(int, int)
uruchomionej usługi (wprowadzoną w Androidzie 15). W tej chwili usługa ma kilka sekund na wywołanie Service.stopSelf()
. Po wywołaniu Service.onTimeout()
usługa nie jest już uznawana za usługę na pierwszym planie. Jeśli usługa nie wywoła Service.stopSelf()
, wystąpi błąd i ten komunikat o błędzie: „Usługa na pierwszym planie typu <fgs_type> nie została zatrzymana przed upływem czasu oczekiwania: <component_name>”. W wersji beta 2 komunikat o błędzie jest wyświetlany jako błąd ANR, ale w kolejnej wersji beta ten komunikat o błędzie spowoduje wystąpienie niestandardowego wyjątku.
Aby uniknąć problemów związanych ze zmianą działania, wykonaj co najmniej jedną z tych czynności:
- Zadbaj o wdrożenie w swojej usłudze nowej metody
Service.onTimeout(int, int)
. Gdy aplikacja oddzwoni, skontaktuj się z firmąstopSelf()
w ciągu kilku sekund. Jeśli nie zatrzymasz aplikacji od razu, system wygeneruje błąd. - Upewnij się, że usługi
dataSync
Twojej aplikacji nie działają dłużej niż przez 6 godzin w ciągu doby (chyba że użytkownik wejdzie w interakcję z aplikacją i nie zresetuje minutnika). - Usługi działające na pierwszym planie typu
dataSync
należy uruchamiać tylko w wyniku bezpośredniej interakcji z użytkownikiem, ponieważ aplikacja działa na pierwszym planie po uruchomieniu usługi, dlatego po jej uruchomieniu w tle upłynie pełne 6 godzin. - Zamiast usługi na pierwszym planie
dataSync
użyj alternatywnego interfejsu API.
Jeśli dataSync
usługa na pierwszym planie Twojej aplikacji działała przez 6 godzin w ciągu ostatnich 24 godzin, nie możesz uruchomić innejdataSync
usługi na pierwszym planiechyba że użytkownik przeniósł Twoją aplikację na pierwszy plan (co spowoduje zresetowanie licznika czasu). Jeśli spróbujesz uruchomić inną usługę dataSync
na pierwszym planie, system zgłosi ForegroundServiceStartNotAllowedException
z komunikatem o błędzie takim jak „Limit czasu dla typu usługi na pierwszym planie typu dataSync został już wyczerpany”.
Nowy typ usługi na pierwszym planie przetwarzania multimediów
Android 15 wprowadza 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 do multimediów może pobrać plik audio i przed odtworzeniem go przekonwertować na inny format. Aby mieć pewność, że konwersja będzie kontynuowana, nawet gdy aplikacja działa w tle, możesz użyć usługi na pierwszym planie mediaProcessing
.
System zezwala na działanie usług mediaProcessing
aplikacji przez łącznie 6 godzin w ciągu 24 godzin. Po tym czasie system wywołuje metodę Service.onTimeout(int, int)
uruchomionej usługi (wprowadzoną w Androidzie 15). W tej chwili usługa ma kilka sekund na wywołanie Service.stopSelf()
. Jeśli usługa nie wywoła Service.stopSelf()
, wystąpi błąd z tym komunikatem o błędzie: „Usługa na pierwszym planie <fgs_type> nie została zatrzymana przed upływem czasu oczekiwania: <component_name>”. W wersji beta 2 komunikat o błędzie jest wyświetlany jako błąd ANR, ale w kolejnej wersji beta ten komunikat o błędzie będzie zgłaszać niestandardowy wyjątek.
Aby uniknąć błędu ANR, wykonaj jedną z tych czynności:
- Zadbaj o wdrożenie w swojej usłudze nowej metody
Service.onTimeout(int, int)
. Gdy aplikacja oddzwoni, skontaktuj się z firmąstopSelf()
w ciągu kilku sekund. Jeśli nie zatrzymasz aplikacji od razu, system wygeneruje błąd. - Upewnij się, że usługi
mediaProcessing
Twojej aplikacji nie działają przez ponad 6 godzin w ciągu doby (chyba że użytkownik wejdzie w interakcję z aplikacją i nie zresetuje minutnika). - Usługi działające na pierwszym planie typu
mediaProcessing
należy uruchamiać tylko w wyniku bezpośredniej interakcji z użytkownikiem, ponieważ aplikacja działa na pierwszym planie po uruchomieniu usługi, dlatego po jej uruchomieniu w tle upłynie pełne 6 godzin. - Zamiast usługi na pierwszym planie
mediaProcessing
użyj alternatywnego interfejsu API, takiego jak WorkManager.
Jeśli usługi na pierwszym planie w Twojej aplikacji (mediaProcessing
) działały przez 6 godzin w ciągu ostatnich 24 godzin, nie możesz uruchomić innej usługi mediaProcessing
na pierwszym planie, chyba że użytkownik przeniósł ją na pierwszy plan (co spowoduje zresetowanie licznika). Jeśli spróbujesz uruchomić inną usługę mediaProcessing
na pierwszym planie, system zgłosi ForegroundServiceStartNotAllowedException
z komunikatem o błędzie takim jak „Limit czasu dla usługi na pierwszym planie typu mediaProcessing”.
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.
Ograniczenia dotyczące BOOT_COMPLETED
odbiorników uruchamiających usługi na pierwszym planie
Obowiązują nowe ograniczenia dotyczące odbiorników transmisji (BOOT_COMPLETED
) uruchamiających usługi na pierwszym planie. Odbiorniki BOOT_COMPLETED
nie mogą uruchamiać tych typów usług działających na pierwszym planie:
dataSync
camera
mediaPlayback
phoneCall
mediaProjection
microphone
(to ograniczenie obowiązuje w przypadku aplikacjimicrophone
od wersji Androida 14)
Jeśli odbiornik BOOT_COMPLETED
spróbuje uruchomić którykolwiek z tych typów usług na pierwszym planie, system zgłosi ForegroundServiceStartNotAllowedException
.
Ograniczenia dotyczące uruchamiania usług działających na pierwszym planie, gdy aplikacja ma uprawnienie SYSTEM_ALERT_WINDOW
Wcześniej aplikacja, która miała uprawnienie SYSTEM_ALERT_WINDOW
, mogła uruchamiać usługę na pierwszym planie, nawet jeśli działała w tle (co omówiono w sekcji wyjątki z ograniczeń uruchamiania w tle).
Jeśli aplikacja jest kierowana na Androida 15, to wykluczenie jest teraz węższe. Aplikacja musi teraz mieć uprawnienie SYSTEM_ALERT_WINDOW
oraz również mieć widoczne nakładki. Oznacza to, że aplikacja musi najpierw uruchomić okno TYPE_APPLICATION_OVERLAY
oraz okno musi być widoczne przed uruchomieniem usługi na pierwszym planie.
Jeśli aplikacja próbuje uruchomić usługę na pierwszym planie w tle i nie spełnia tych nowych wymagań (i nie jest objęta innym wyjątkiem), system zgłasza ForegroundServiceStartNotAllowedException
.
Jeśli Twoja aplikacja zadeklaruje uprawnienie SYSTEM_ALERT_WINDOW
i uruchamia usługi działające na pierwszym planie w tle, ta zmiana może mieć na nią wpływ. Jeśli Twoja aplikacja otrzyma właściwość ForegroundServiceStartNotAllowedException
, sprawdź jej kolejność działań i upewnij się, że ma już aktywne okno nakładki, zanim będzie próbowała uruchomić usługę na pierwszym planie z poziomu tła. Aby sprawdzić, czy okno nakładki jest obecnie widoczne, wywołaj View.getWindowVisibility()
. Możesz też zastąpić metodę View.onWindowVisibilityChanged()
, aby otrzymywać powiadomienia o zmianie widoczności.
Zmiany dotyczące tego, kiedy aplikacje mogą modyfikować globalny stan trybu Nie przeszkadzać
Aplikacje kierowane na Androida 15 nie mogą już zmieniać globalnego stanu ani zasad trybu Nie przeszkadzać na urządzeniu (przez zmianę ustawień użytkownika lub wyłączenie trybu Nie przeszkadzać). Zamiast tego aplikacje muszą przekazywać element AutomaticZenRule
, który system łączy w globalną zasadę z dotychczasowym schematem wygrywania zasad o największym ograniczeniu. Wywołania istniejących interfejsów API, które wcześniej wpływały na stan globalny (setInterruptionFilter
, setNotificationPolicy
), skutkują utworzeniem lub zaktualizowaniem niejawnej klasy AutomaticZenRule
, która jest włączana i wyłączana w zależności od cyklu wywołań tych wywołań interfejsu API.
Pamiętaj, że ta zmiana wpływa na obserwowalne zachowanie tylko wtedy, gdy aplikacja wywołuje metodę setInterruptionFilter(INTERRUPTION_FILTER_ALL)
i oczekuje, że wywołanie dezaktywacji AutomaticZenRule
, która została wcześniej aktywowana przez ich właścicieli.
Zmiany w OpenJDK 17
Android 15 kontynuuje prace nad odświeżaniem podstawowych bibliotek Androida w celu zapewnienia zgodności z funkcjami w najnowszych wersjach OpenJDK LTS.
Jedna z tych zmian może wpłynąć na zgodność aplikacji kierowanych na Androida 15:
Zmiany w interfejsach API formatowania ciągów znaków: weryfikacja indeksu argumentów, flag, szerokości i precyzji 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 ten wyjątek jest zgłaszany w przypadku użycia indeksu argumentu 0 (
%0
w ciągu znaków formatu):IllegalFormatArgumentIndexException: Illegal format argument index = 0
W tym przypadku problem można rozwiązać, używając indeksu argumentu 1 (
%1
w ciągu formatu).Zmiany typu komponentu tablicy
Arrays.asList(...).toArray()
: przy zastosowaniuArrays.asList(...).toArray()
typem komponentu tablicy wynikowej jest terazObject
, a nie typ elementów tablicy. Ten kod generuje więcClassCastException
:String[] elements = (String[]) Arrays.asList("one", "two").toArray();
W tym przypadku, aby zachować
String
jako typ komponentu w utworzonej tablicy, możesz zamiast tego użyćCollection.toArray(Object[])
:String[] elements = Arrays.asList("two", "one").toArray(new String[0]);
Zmiany w obsłudze kodu języka: podczas korzystania z interfejsu API
Locale
kody języków hebrajskiego, jidysz i indonezyjskiego nie są już konwertowane na przestarzałe formy (hebrajski:iw
, jidysz:ji
i indonezyjski:in
). Podczas określania kodu języka dla jednego z tych języków należy używać kodów z standardów ISO 639-1 oraz kodów ISO 639-1 i hebrajski:he
,he
.yi
id
Zmiany w losowych sekwencjach int: po zmianach wprowadzonych na stronie https://bugs.openjdk.org/Przeglądaj/JDK-8301574 podane niżej metody
Random.ints()
zwracają teraz inną sekwencję liczb niż metodyRandom.nextInt()
:Zwykle ta zmiana nie powinna powodować łamania aplikacji, ale Twój kod nie powinien się spodziewać, że sekwencja wygenerowana za pomocą metod
Random.ints()
będzie odpowiadać parametrowiRandom.nextInt()
.
Zabezpieczenia
W Androidzie 15 wprowadzono zmiany, które promują bezpieczeństwo systemu w celu ochrony aplikacji i użytkowników przed złośliwymi aplikacjami.
Uruchomienie bezpiecznej aktywności w tle
Android 15 chroni użytkowników przed złośliwymi aplikacjami i daje im większą kontrolę nad urządzeniami, dodając zmiany, które uniemożliwiają złośliwym aplikacjom działającym w tle przenoszenie innych aplikacji na pierwszy plan, podnoszenie ich uprawnień i nadużywanie interakcji z użytkownikiem. Uruchamianie aktywności w tle jest ograniczone od wersji Androida 10 (poziom API 29).
Blokuj uruchamianie aktywności w aplikacjach, które nie pasują do identyfikatora UID najwyższego poziomu w stosie
Złośliwe aplikacje mogą uruchamiać działania innych aplikacji w ramach tego samego zadania, a potem nakładać się na nie, stwarzając wrażenie, że są tą aplikacją. Ten atak „atak z wykorzystaniem przejęcia zadania” omija obecne ograniczenia uruchamiania w tle, ponieważ wszystko odbywa się w ramach tego samego widocznego zadania. Aby ograniczyć to ryzyko, Android 15 dodaje flagę, która blokuje uruchamianie aktywności przez aplikacje, które nie pasują do identyfikatora użytkownika najwyższego poziomu w stosie. Aby zezwolić na wszystkie aktywności w aplikacji, zaktualizuj atrybut allowCrossUidActivitySwitchFromBelow
w pliku AndroidManifest.xml
aplikacji:
<application android:allowCrossUidActivitySwitchFromBelow="false" >
Nowe zabezpieczenia są aktywne, jeśli są spełnione wszystkie te warunki:
- Aplikacja, która ma zostać wprowadzona na rynek, jest kierowana na Androida 15.
- Aplikacja znajdująca się na stosie zadań jest kierowana na Androida 15.
- Każda widoczna aktywność ma włączone nowe zabezpieczenia
Gdy zabezpieczenia są włączone, w przypadku, gdy samodzielnie ukończą zadanie, aplikacje mogą wrócić do ekranu głównego, a nie do ostatniej widocznej aplikacji.
Inne zmiany
Oprócz ograniczenia związanego z dopasowywaniem identyfikatorów UID zmiany obejmą też te inne zmiany:
- Zmień twórców
PendingIntent
, aby domyślnie blokowały uruchamianie aktywności w tle. Pomaga to zapobiegać przypadkowemu tworzeniu przez aplikacje elementówPendingIntent
, które mogłyby zostać wykorzystane przez hakerów. - Nie umieszczaj aplikacji na pierwszym planie, chyba że zezwala na to nadawca
PendingIntent
. Ta zmiana ma zapobiec nadużywaniu możliwości uruchamiania działań w tle przez złośliwe aplikacje. Domyślnie aplikacje nie mogą umieszczać stosu zadań na pierwszym planie, chyba że twórca zezwala na uruchamianie aktywności w tle lub nadawca ma uprawnienia do uruchamiania aktywności w tle. - Określ, w jaki sposób najbardziej wartościowa aktywność na stosie zadań może dokończyć zadanie. Jeśli największe działanie zakończy zadanie, Android powróci do tego, które było ostatnio aktywne. Co więcej, jeśli aktywność spoza najwyższego poziomu dokończy swoje zadanie, Android wróci na ekran główny. Nie zablokuje dokończenia tej aktywności.
- Zapobieganie uruchamianiu dowolnych działań z innych aplikacji w Twoim zadaniu Ta zmiana zapobiega wyłudzeniu informacji przez złośliwe aplikacje przez tworzenie działań, które wyglądają jak pochodzące z innych aplikacji.
- Blokuj niewidoczne okna nie uwzględniania przy uruchamianiu aktywności w tle. Pomaga to zapobiegać nadużywaniu przez złośliwe aplikacje aktywności w tle do wyświetlania użytkownikom niechcianych lub szkodliwych treści.
Bezpieczniejsze intencje
W Androidzie 15 wprowadzamy nowe zabezpieczenia, które zwiększają bezpieczeństwo intencji i są niezawodne. Zmiany te mają na celu zapobieganie potencjalnym lukom w zabezpieczeniach i niewłaściwemu wykorzystywaniu intencji, które mogłyby zostać wykorzystane przez złośliwe aplikacje. Wprowadziliśmy 2 główne ulepszenia w zakresie bezpieczeństwa intencji w Androidzie 15:
- Dopasuj docelowe filtry intencji: intencje kierowane na określone komponenty muszą dokładnie odpowiadać specyfikacjom filtra intencji. Jeśli wysyłasz zamiar uruchomienia działania innej aplikacji, komponent docelowej intencji musi być zgodny z zadeklarowanymi filtrami intencji w działaniu odbierającym.
- Intencje muszą zawierać 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ć jasno określone działanie.
Kotlin
fun onCreate() { StrictMode.setVmPolicy(VmPolicy.Builder() .detectUnsafeIntentLaunch() .build() ) }
Java
public void onCreate() { StrictMode.setVmPolicy(new VmPolicy.Builder() .detectUnsafeIntentLaunch() .build()); }
Wygoda użytkownika i interfejs systemu
W Androidzie 15 wprowadziliśmy kilka zmian, które mają zapewnić bardziej spójną i intuicyjną obsługę użytkowników.
Zmiany wstawiane okien
W Androidzie 15 wprowadzono 2 zmiany związane z wstawianiem okien: ustawienie od krawędzi do krawędzi jest domyślnie wymuszane w obszarze od krawędzi do krawędzi oraz zmiany w konfiguracji, takie jak domyślna konfiguracja pasków systemowych.
Egzekwowanie zasad od krawędzi do krawędzi
Na urządzeniach z Androidem 15 aplikacje są domyślnie zainstalowane od krawędzi do krawędzi, jeśli są przeznaczone na Androida 15.
Jest to niezbędna zmiana, która może negatywnie wpłynąć na interfejs użytkownika aplikacji. Zmiany dotyczą tych obszarów interfejsu:
- Pasek nawigacyjny uchwytu gestów
- Domyślnie przezroczysty.
- Przesunięcie od dołu jest wyłączone, więc treść jest wyświetlana za systemowym paskiem nawigacyjnym, o ile nie zostaną zastosowane odstępy od dołu.
- Funkcje
setNavigationBarColor
iR.attr#navigationBarColor
zostały wycofane i nie mają wpływu na nawigację przy użyciu gestów. - Narzędzia
setNavigationBarContrastEnforced
iR.attr#navigationBarContrastEnforced
nadal nie mają wpływu na nawigację przy użyciu gestów.
- Nawigacja przy użyciu 3 przycisków
- Przezroczystość jest domyślnie ustawiona na 80%, a kolor może pasować do tła okna.
- Przesunięcie dolnego jest wyłączone, więc treść jest wyświetlana za systemowym paskiem nawigacyjnym, jeśli nie zastosowano dopełnienia.
- Domyślne ustawienia
setNavigationBarColor
iR.attr#navigationBarColor
są zgodne z tłem okna. Aby to ustawienie było stosowane, tło okna musi być rysowalnym kolorem. Ten interfejs API został wycofany, ale nadal wpływa na nawigację przy użyciu 3 przycisków. - Wartości
setNavigationBarContrastEnforced
iR.attr#navigationBarContrastEnforced
mają domyślnie wartość prawda, co powoduje dodanie 80% nieprzezroczystego tła podczas nawigacji przy użyciu 3 przycisków.
- Pasek stanu
- Domyślnie przezroczysty.
- Przesunięcie od góry jest wyłączone, więc treść jest wyświetlana za paskiem stanu, chyba że zostaną zastosowane odstępy od góry.
- Funkcje
setStatusBarColor
iR.attr#statusBarColor
zostały wycofane i nie mają wpływu na Androida 15. - Metody
setStatusBarContrastEnforced
iR.attr#statusBarContrastEnforced
zostały wycofane, ale nadal mają wpływ na Androida 15.
- Wycięcie w ekranie
- Minimalna liczba okien niepływających (
layoutInDisplayCutoutMode
) musi wynosićLAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
. ParametrySHORT_EDGES
,NEVER
iDEFAULT
są interpretowane jakoALWAYS
, dzięki czemu użytkownicy nie widzą czarnego paska spowodowanego wycięciem w ekranie i wyglądają od krawędzi do krawędzi.
- Minimalna liczba okien niepływających (
Poniższy przykład pokazuje aplikację przed kierowaniem na Androida 15 i po nim oraz przed i po zastosowaniu wstawki.
Co sprawdzić, czy aplikacja działa już od krawędzi do krawędzi
Jeśli Twoja aplikacja jest już od krawędzi do krawędzi i stosuje wstawione elementy, z wyjątkiem tych scenariuszy nie będzie to miało na nią wpływu. Zalecamy jednak przetestowanie aplikacji, nawet jeśli uważasz, że jej to nie dotyczy.
- Masz okno niepływające, np.
Activity
, które korzysta z elementuSHORT_EDGES
,NEVER
lubDEFAULT
zamiastLAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
. Jeśli przy uruchamianiu aplikacja ulegnie awarii, może to być spowodowane jej ekranem powitalnym. Możesz uaktualnić zależność core splashscreen do 1.2.0-alpha01 lub później albo ustawićwindow.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always
. - Mogą wyświetlać się 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 między innymi:
- Ekrany wprowadzenia lub logowania
- Strony ustawień
Co sprawdzić, czy Twoja aplikacja nie jest już w najnowocześniejszy sposób
Jeśli Twoja aplikacja nie działa jeszcze od krawędzi do krawędzi, prawdopodobnie ten problem Cię dotyczy. Oprócz sytuacji w przypadku aplikacji, które są już od podstaw, weź pod uwagę te kwestie:
- Jeśli podczas tworzenia aplikacji używasz komponentów Material 3 (
androidx.compose.material3
), takich jakTopAppBar
,BottomAppBar
iNavigationBar
, prawdopodobnie nie ma to wpływu na komponenty, ponieważ automatycznie obsługują wstawki. - Jeśli Twoja aplikacja korzysta z komponentów Material 2 (
androidx.compose.material
) w sekcji Utwórz, nie obsługują one automatycznie wstawionych elementów. Możesz jednak uzyskać dostęp do wstawionych i zastosować je ręcznie. W wersji androidx.compose.material 1.6.0 i nowszych możesz użyć parametruwindowInsets
, aby ręcznie zastosować wstawki w przypadkuBottomAppBar
,TopAppBar
,BottomNavigation
iNavigationRail
. Podobnie użyj parametrucontentWindowInsets
dla właściwościScaffold
. - Jeśli Twoja aplikacja korzysta z widoków i komponentów Material (
com.google.android.material
), większość komponentów Material Design, takich jakBottomNavigationView
,BottomAppBar
,NavigationRailView
czyNavigationView
, obsługuje wstawki i nie wymagają dodatkowej pracy. Musisz jednak dodaćandroid:fitsSystemWindows="true"
, jeśli używaszAppBarLayout
. - W przypadku niestandardowych funkcji kompozycyjnych zastosuj elementy wstawiane ręcznie jako dopełnienie. Jeśli treść znajduje się w elemencie
Scaffold
, możesz używać wstawienia za pomocą wartości dopełnieniaScaffold
. W przeciwnym razie zastosuj dopełnienie za pomocą jednego z elementówWindowInsets
. - Jeśli aplikacja korzysta z widoków oraz
BottomSheet
,SideSheet
lub kontenerów niestandardowych, zastosuj dopełnienie za pomocąViewCompat.setOnApplyWindowInsetsListener
. W przypadkuRecyclerView
zastosuj dopełnienie za pomocą tego odbiornika i dodajclipToPadding="false"
.
Co sprawdzić, czy aplikacja musi oferować niestandardową ochronę w tle
Jeśli Twoja aplikacja musi oferować niestandardową ochronę w tle w przypadku nawigacji przy użyciu 3 przycisków lub paska stanu, powinna ona umieścić za paskiem systemu funkcję kompozycyjną lub widok, używając WindowInsets.Type#tappableElement()
, aby ustawić wysokość paska nawigacyjnego z 3 przyciskami lub WindowInsets.Type#statusBars
.
Dodatkowe zasoby od krawędzi do krawędzi
Dodatkowe uwagi na temat stosowania wstawienia znajdziesz w przewodnikach dotyczących widoków od krawędzi do krawędzi i od krawędzi do krawędzi tworzenia wiadomości.
Wycofane interfejsy API
Te interfejsy API zostały wycofane:
R.attr#enforceStatusBarContrast
R.attr#navigationBarColor
R.attr#navigationBarDividerColor
R.attr#statusBarColor
Window#getNavigationBarColor
Window#getNavigationBarDividerColor
Window#getStatusBarColor
Window#isStatusBarContrastEnforced
Window#setDecorFitsSystemWindows
Window#setNavigationBarColor
Window#setNavigationBarDividerColor
Window#setStatusBarColor
Window#setStatusBarContrastEnforced
Stabilna konfiguracja
Jeśli aplikacja jest kierowana na Androida 15 lub nowszego, Configuration
nie wyklucza już pasków systemowych. Jeśli do obliczania układu używasz rozmiaru ekranu z klasy Configuration
, zastąp go lepszymi alternatywami, takimi jak odpowiednia właściwość ViewGroup
, WindowInsets
lub WindowMetricsCalculator
, w zależności od potrzeb.
Działanie Configuration
jest dostępne od wersji API 1. Zwykle jest uzyskiwany z Activity.onConfigurationChanged
. Podaje informacje o gęstości,
orientacji i rozmiarach okien. Jedną z ważnych cech rozmiaru okien zwracanych przez funkcję Configuration
jest to, że wcześniej wykluczały one paski systemowe.
Rozmiar konfiguracji jest zwykle używany do wyboru zasobów, na przykład /res/layout-h500dp
, i jest to nadal prawidłowy przypadek użycia. Jednak zawsze odradzamy używanie go do obliczania układu. Jeśli tak robicie, należy
odejść od tego tematu. Zamiast elementu Configuration
stosuj bardziej odpowiedni w zależności od przypadku użycia.
Jeśli używasz go do obliczenia układu, użyj odpowiedniego elementu ViewGroup
, np. CoordinatorLayout
lub ConstraintLayout
. Jeśli używasz jej do określania wysokości systemowego paska nawigacyjnego, użyj WindowInsets
. Jeśli chcesz poznać bieżący rozmiar okna aplikacji, użyj computeCurrentWindowMetrics
.
Poniższa lista zawiera opis pól, na które wpłynie ta zmiana:
- Rozmiary
Configuration.screenWidthDp
iscreenHeightDp
nie wykluczają już słupków systemowych. - Pośrednio na
Configuration.smallestScreenWidthDp
wpływają zmiany wscreenWidthDp
iscreenHeightDp
. - Na
Configuration.orientation
wpływają pośrednio zmiany w parametrachscreenWidthDp
iscreenHeightDp
na urządzeniach bliskich powierzchni. Display.getSize(Point)
mają pośredni wpływ na zmiany wprowadzone w narzędziuConfiguration
. Ta funkcja została wycofana od poziomu interfejsu API 30.Display.getMetrics()
działa już w ten sposób od poziomu interfejsu API 33.
Atrybut eleganckiTextHeight ma domyślnie wartość „true” (prawda)
W przypadku aplikacji kierowanych na Androida 15 atrybut elegantTextHeight
TextView
ma domyślnie wartość true
, co powoduje zastąpienie domyślnie używanej domyślnie kompaktowej czcionki pewnymi skryptami o dużych danych pionowych inną, która jest znacznie bardziej czytelna. Wprowadzono kompaktową czcionkę, aby zapobiec naruszaniu układów. Android 13 (poziom interfejsu API 33) zapobiega wielu z tych problemów, umożliwiając układowi tekstu rozciąganie wysokości w pionie za pomocą atrybutu fallbackLineSpacing
.
W Androidzie 15 kompaktowa czcionka pozostaje w systemie, więc aplikacja może ustawić elegantTextHeight
na false
, aby uzyskać takie samo działanie jak wcześniej, ale prawdopodobnie nie będzie obsługiwana w kolejnych wersjach. Jeśli Twoja aplikacja obsługuje te skrypty: arabski, laotański, birmański, tamilski, gudżarati, kannada, malajalam, orija, telugu lub tajski, przetestuj ją, ustawiając w polu elegantTextHeight
opcję true
.
Zmiana szerokości TextView w przypadku złożonych kształtów liter
W poprzednich wersjach Androida niektóre czcionki kursywy lub języki ze złożonym kształtem mogły powodować rysowanie liter w obszarze poprzedniego lub następnego znaku.
W niektórych przypadkach takie litery były przycinane na pozycji początkowej lub końcowej.
Począwszy od Androida 15 parametr TextView
przydziela szerokość dostatecznie dużo miejsca na takie litery i pozwala aplikacjom żądać dodatkowego dopełnienia z lewej strony, by zapobiec przycinaniu.
Ta zmiana wpływa na sposób, w jaki TextView
określa szerokość, dlatego TextView
domyślnie przydziela większą szerokość, jeśli aplikacja jest kierowana na Androida 15 lub nowszego. Możesz włączyć lub wyłączyć tę funkcję, wywołując interfejs API setUseBoundsForWidth
w usłudze TextView
.
Dodanie lewego dopełnienia może spowodować niewłaściwe wyrównanie elementów w istniejących układach, dlatego nie jest ono dodawane domyślnie nawet w aplikacjach kierowanych na Androida 15 lub nowszego.
Możesz jednak dodać dodatkowe dopełnienie, wywołując metodę setShiftDrawingOffsetForStartOverhang
, aby zapobiec przycinaniu.
Poniższe przykłady pokazują, jak te zmiany mogą poprawić układ tekstu w przypadku niektórych czcionek i języków.
Domyślna wysokość wiersza elementu EditText zależna od języka
W poprzednich wersjach Androida układ tekstu rozciągnął wysokość tekstu, aby dopasować ją do wysokości czcionki w bieżącym języku. Jeśli na przykład treść była w języku japońskim, ponieważ wysokość wiersza czcionki japońskiej jest nieco większa niż czcionki łacińskiej, wysokość tekstu znacznie się zwiększyła. Pomimo tych różnic w wysokości wierszy, rozmiar elementu EditText
był jednak taki sam niezależnie od używanego regionu, jak na tym przykładzie:
W przypadku aplikacji kierowanych na Androida 15 minimalna wysokość wiersza jest teraz zarezerwowana dla EditText
, aby pasowała do czcionki referencyjnej dla określonego języka, jak widać na tym obrazie:
W razie potrzeby aplikacja może przywrócić poprzednie działanie, określając atrybut useLocalePreferredLineHeightForMinimum
jako false
, a aplikacja może ustawiać niestandardowe minimalne wskaźniki branżowe za pomocą interfejsu API setMinimumFontMetrics
w Kotlin i Javie.
Aparat i multimedia
Android 15 wprowadza te zmiany w działaniu aparatu i multimediów w aplikacjach kierowanych na Androida 15 lub nowszego.
Ograniczenia dotyczące żądania skupienia dźwięku
Aby żądać aktywności audio, aplikacje kierowane na Androida 15 muszą być główną aplikacją lub mieć uruchomioną usługę na pierwszym planie związaną z dźwiękiem. Jeśli aplikacja spróbuje poprosić o zaznaczenie, gdy nie spełnia jednego z tych wymagań, wywołanie zwróci wartość AUDIOFOCUS_REQUEST_FAILED
.
Usługa na pierwszym planie jest uznawana za związaną z dźwiękiem, jeśli jej typ to mediaPlayback
, camera
, microphone
lub phoneCall
.
Więcej informacji o zaznaczeniu dźwięku znajdziesz w artykule Zarządzanie aktywnością audio.
Zaktualizowano ograniczenia dotyczące aplikacji innych niż SDK
Android 15 zawiera zaktualizowane listy podlegających ograniczeniom interfejsów spoza pakietu SDK opracowane na podstawie współpracy z deweloperami aplikacji na Androida i najnowszych testów wewnętrznych. Zanim ograniczymy dostęp do interfejsów spoza SDK, dbamy o to, aby w miarę możliwości dostępne były publiczne alternatywy.
Jeśli Twoja aplikacja nie jest kierowana na Androida 15, niektóre z tych zmian mogą Cię nie odczuć od razu. Mimo że aplikacja może mieć dostęp do niektórych interfejsów spoza SDK w zależności od docelowego poziomu interfejsu API, korzystanie z dowolnych metod lub pól spoza pakietu SDK niesie ze sobą wysokie ryzyko jej awarii.
Jeśli nie masz pewności, czy Twoja aplikacja używa interfejsów spoza SDK, możesz przetestować ją, aby się tego dowiedzieć. Jeśli Twoja aplikacja bazuje na interfejsach innych niż SDK, zacznij planować migrację do alternatywnych pakietów SDK. Zdajemy sobie jednak sprawę, że niektóre aplikacje mają odpowiednie przypadki użycia w zakresie korzystania z interfejsów innych niż SDK. Jeśli nie możesz znaleźć alternatywy dla interfejsu innego niż SDK dla funkcji w aplikacji, poproś o nowy publiczny interfejs API.
Więcej informacji o zmianach w tej wersji Androida znajdziesz w artykule Aktualizacje ograniczeń interfejsu innego niż SDK na Androidzie 15. Więcej informacji o interfejsach innych niż SDK znajdziesz w tym artykule.