Zmiany w działaniu: aplikacje kierowane na Androida 15 lub nowszego

Podobnie jak poprzednie wersje, Android 15 wprowadza zmiany w działaniu, które mogą mieć wpływ na Twoją aplikację. Poniższe zmiany dotyczą wyłącznie aplikacji, które są kierowane na Androida 15 lub nowszego. Jeśli Twoja aplikacja jest kierowana na Androida 15 lub nowszego, zmodyfikuj ją tak, aby prawidłowo obsługiwała te zachowania w odpowiednich przypadkach.

Zapoznaj się też z listą zmian w zachowaniu, które mają wpływ 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 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:

  1. Zaimplementuj nową metodę Service.onTimeout(int, int) w swojej usłudze. Gdy aplikacja otrzyma połączenie zwrotne, w ciągu kilku sekund zadzwoń pod numer stopSelf(). Jeśli nie zatrzymasz aplikacji od razu, system wygeneruje błąd.
  2. Upewnij się, że usługi dataSync Twojej 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).
  3. 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.
  4. 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ę 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:

  1. Zaimplementuj nową metodę Service.onTimeout(int, int) w swojej usłudze. Gdy aplikacja otrzyma połączenie zwrotne, w ciągu kilku sekund zadzwoń pod numer stopSelf(). (jeśli nie zatrzymasz aplikacji od razu, system wygeneruje błąd).
  2. 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).
  3. 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.
  4. 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

在启动 BOOT_COMPLETED 广播接收器方面存在新限制 前台服务。BOOT_COMPLETED 接收器能启动 以下类型的前台服务:

如果 BOOT_COMPLETED 接收器尝试启动任何上述类型的前台 服务,系统会抛出 ForegroundServiceStartNotAllowedException

测试

如需测试应用的行为,您可以启用这些新限制,即使您的应用并未以 Android 15 为目标平台(只要应用在 Android 15 设备上运行)也是如此。运行以下 adb 命令:

adb shell am compat enable FGS_BOOT_COMPLETED_RESTRICTIONS your-package-name

如需在不重启设备的情况下发送 BOOT_COMPLETED 广播,请运行以下 adb 命令:

adb shell am broadcast -a android.intent.action.BOOT_COMPLETED your-package-name

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ć

Aplikacje kierowane na Androida 15 (poziom API 35) lub nowszego nie mogą już zmieniać globalnego stanu ani zasad trybu Nie przeszkadzać na urządzeniu (ani przez modyfikowanie ustawień użytkownika, ani przez wyłączanie trybu Nie przeszkadzać). Zamiast tego aplikacje muszą przekazać AutomaticZenRule, które system połączy w globalne zasady z dotychczasowym schematem „najbardziej restrykcyjne zasady wygrywają”. Wywołania istniejących interfejsów API, które wcześniej wpływały na stan globalny (setInterruptionFilter, setNotificationPolicy), powodują utworzenie lub zaktualizowanie niejawnego AutomaticZenRule, który jest włączany i wyłączany w zależności od cyklu wywołań tych interfejsów API.

Pamiętaj, że ta zmiana wpływa tylko na obserwowalne zachowanie, jeśli aplikacja wywołuje funkcję setInterruptionFilter(INTERRUPTION_FILTER_ALL) i oczekuje, że ta funkcja dezaktywuje AutomaticZenRule, który został wcześniej aktywowany przez właścicieli.

Zmiany w interfejsie OpenJDK API

Android 15 kontynuuje odświeżanie podstawowych bibliotek Androida, aby dostosować je do funkcji najnowszych wersji OpenJDK LTS.

Niektóre z tych zmian mogą mieć wpływ na kompatybilność aplikacji kierowanych na Androida 15 (poziom interfejsu API 35):

  • Zmiany w interfejsach API formatowania ciągów znaków: weryfikacja indeksu argumentu, flag, szerokości i precyzji jest teraz bardziej rygorystyczna w przypadku korzystania z tych interfejsów API:String.format()Formatter.format():

    Na przykład ten wyjątek jest zgłaszany, gdy używany jest indeks argumentu 0 (%0 w ciągu formatującym):

    IllegalFormatArgumentIndexException: Illegal format argument index = 0
    

    W takim przypadku problem można rozwiązać, używając indeksu argumentu 1 (%1w ciągu formatującym).

  • Zmiany typu komponentu Arrays.asList(...).toArray(): w przypadku użycia funkcji Arrays.asList(...).toArray() typ komponentu wynikowej tablicy to teraz Object, a nie typ elementów tablicy bazowej. Dlatego ten kod zgłasza wyjątek ClassCastException:

    String[] elements = (String[]) Arrays.asList("one", "two").toArray();
    

    W tym przypadku, aby zachować String jako typ komponentu w wynikowej tablicy, możesz użyć Collection.toArray(Object[]):

    String[] elements = Arrays.asList("two", "one").toArray(new String[0]);
    
  • Zmiany w obsłudze kodów języka: podczas korzystania z interfejsu Locale API kody języka hebrajskiego, jidysz i indonezyjskiego nie są już konwertowane na ich przestarzałe formy (hebrajski: iw, jidysz: ji i indonezyjski: in). Podczas określania kodu języka dla jednego z tych języków używaj kodów z ISO 639-1 (hebrajski: he, jidysz: yi i indonezyjski: id).

  • Zmiany w sekwencjach liczb losowych: w wyniku zmian wprowadzonych w https://bugs.openjdk.org/browse/JDK-8301574 te metody Random.ints() zwracają teraz inną sekwencję liczb niż metody Random.nextInt():

    Zwykle ta zmiana nie powinna powodować nieprawidłowego działania aplikacji, ale kod nie powinien oczekiwać, że sekwencja wygenerowana przez metody Random.ints() będzie zgodna z sekwencją Random.nextInt().

Nowy interfejs API SequencedCollection może wpłynąć na zgodność aplikacji po zaktualizowaniu compileSdk w konfiguracji kompilacji aplikacji w celu używania Androida 15 (poziom interfejsu API 35):

  • Kolizja z funkcjami rozszerzeń MutableList.removeFirst()MutableList.removeLast()kotlin-stdlib

    Typ List w Javie jest mapowany na typ MutableList w Kotlinie. Interfejsy API List.removeFirst()List.removeLast() zostały wprowadzone w Androidzie 15 (poziom interfejsu API 35), więc kompilator Kotlina rozwiązuje wywołania funkcji, np. list.removeFirst(), statycznie do nowych interfejsów API List zamiast do funkcji rozszerzeń w kotlin-stdlib.

    Jeśli aplikacja zostanie ponownie skompilowana z ustawieniem compileSdk na 35minSdk na 34 lub niższą wersję, a następnie zostanie uruchomiona na Androidzie 14 lub starszym, wystąpi błąd środowiska wykonawczego:

    java.lang.NoSuchMethodError: No virtual method
    removeFirst()Ljava/lang/Object; in class Ljava/util/ArrayList;
    

    Istniejąca opcja NewApi lint we wtyczce Androida do obsługi Gradle może wykrywać te nowe zastosowania 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ątek środowiska wykonawczego i błędy lint, wywołania funkcji removeFirst()removeLast() można zastąpić odpowiednio wywołaniami removeAt(0)removeAt(list.lastIndex) w Kotlinie. Jeśli używasz Android Studio Ladybug | 2024.1.3 lub nowszej, możesz też skorzystać z opcji szybkiej naprawy tych błędów.

    Jeśli opcja lint została wyłączona, rozważ usunięcie @SuppressLint("NewApi")lintOptions { disable 'NewApi' }.

  • Kolizja z innymi metodami w Javie

    Do istniejących typów dodaliśmy nowe metody, np. ListDeque. 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ą kompilator javac zgłasza błąd w czasie kompilacji. Przykład:

    Przykładowy błąd 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 List
    

    Przykł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 error
    

    Przykł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 error
    

    Aby 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 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 chroni użytkowników przed złośliwymi aplikacjami i zapewnia im większą kontrolę nad urządzeniami. Wprowadziliśmy 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. Od Androida 10 (poziom interfejsu API 29) uruchamianie aktywności w tle jest ograniczone.

Inne zmiany

  • Zmień domyślne ustawienie PendingIntent twórców na blokowanie uruchamiania aktywności w tle. Pomaga to zapobiegać przypadkowemu tworzeniu przez aplikacjePendingIntent, które mogłyby być wykorzystywane przez nieuczciwe podmioty.
  • Nie przenoś aplikacji na pierwszy plan, chyba że PendingIntentnadawca na to zezwoli. Ta zmiana ma zapobiegać nadużywaniu przez złośliwe aplikacje możliwości rozpoczynania aktywności w tle. Domyślnie aplikacje nie mogą przenosić stosu zadań na pierwszy plan, chyba że twórca zezwoli na uprawnienia do uruchamiania działań w tle lub nadawca ma uprawnienia do uruchamiania działań w tle.
  • Określa, jak najwyższa aktywność w stosie zadań może zakończyć zadanie. Jeśli aktywność na górze stosu zakończy zadanie, Android wróci do ostatniego aktywnego zadania. Jeśli aktywność niebędąca na pierwszym planie zakończy swoje zadanie, Android wró do ekranu głównego. Nie zablokuje zakończenia tej aktywności.
  • Zapobiegaj uruchamianiu dowolnych działań z innych aplikacji w swoim zadaniu. Ta zmiana uniemożliwia złośliwym aplikacjom wyłudzanie informacji od użytkowników przez tworzenie działań, które wyglądają jak działania innych aplikacji.
  • Blokowanie okien niewidocznych, aby nie były brane pod uwagę podczas uruchamiania aktywności w tle. Pomaga to zapobiegać wykorzystywaniu przez złośliwe aplikacje uruchamiania aktywności w tle do wyświetlania użytkownikom niechcianych lub szkodliwych treści.

Bezpieczniejsze zamiary

Android 15 针对 intent 引入了 StrictMode

如需查看有关 Intent 使用违规行为的详细日志,请使用以下方法:

Kotlin

fun onCreate() {
    StrictMode.setVmPolicy(VmPolicy.Builder()
        .detectUnsafeIntentLaunch()
        .build()
    )
}

Java

public void onCreate() {
    StrictMode.setVmPolicy(new VmPolicy.Builder()
            .detectUnsafeIntentLaunch()
            .build());
}

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.

Egzekwowanie treści od krawędzi do krawędzi

如果应用以 Android 15(API 级别 35)为目标平台,则在搭载 Android 15 的设备上默认以无边框显示。

以 Android 14 为目标平台且在 Android 15 设备上不是全屏显示的应用。


以 Android 15(API 级别 35)为目标平台且在 Android 15 设备上实现全屏显示的应用。
此应用主要使用会自动应用边衬区的 Material 3 Compose 组件。此屏幕不受 Android 15 强制执行的无边框措施的负面影响。

这是一项重大变更,可能会对应用的界面产生负面影响。这些更改会影响以下界面区域:

  • 手势柄导航栏
    • 默认透明。
    • 底部偏移量处于停用状态,因此内容会绘制在系统导航栏后面,除非应用了边衬区。
    • setNavigationBarColorR.attr#navigationBarColor 已弃用,不会影响手势导航。
    • setNavigationBarContrastEnforcedR.attr#navigationBarContrastEnforced 继续对使用手势进行导航没有任何影响。
  • “三按钮”导航
    • 默认情况下,不透明度设置为 80%,颜色可能与窗口背景颜色一致。
    • 底部偏移量已停用,因此内容会绘制在系统导航栏后面,除非应用了边衬区。
    • setNavigationBarColorR.attr#navigationBarColor 默认设置为与窗口背景保持一致。窗口背景必须是颜色可绘制对象,才能应用此默认值。此 API 已弃用,但仍会影响三按钮导航。
    • setNavigationBarContrastEnforcedR.attr#navigationBarContrastEnforced 默认值为 true,这会在三按钮导航栏中添加 80% 不透明度的背景。
  • 状态栏
    • 默认透明。
    • 顶部偏移量处于停用状态,因此内容会绘制在状态栏后面,除非应用了边衬区。
    • setStatusBarColorR.attr#statusBarColor 已弃用,对 Android 15 没有影响。
    • setStatusBarContrastEnforcedR.attr#statusBarContrastEnforced 已废弃,但仍会对 Android 15 产生影响。
  • 刘海屏
    • 非浮动窗口的 layoutInDisplayCutoutMode 必须为 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYSSHORT_EDGESNEVERDEFAULT 会被解读为 ALWAYS,这样用户就不会看到因刘海屏而产生的黑条,并且应用会显示在屏幕的整个边缘。

以下示例展示了应用在以 Android 15(API 级别 35)为目标平台之前和之后,以及在应用边衬区之前和之后的效果。此示例并不全面,在 Android Auto 上可能会显示不同的内容。

以 Android 14 为目标平台且在 Android 15 设备上不是全屏显示的应用。
以 Android 15(API 级别 35)为目标平台且在 Android 15 设备上实现全屏显示的应用。不过,由于 Android 15 的边缘到边缘强制执行,许多元素现在会被状态栏、三按钮导航栏或刘海屏遮挡。隐藏界面包括 Material 2 顶部应用栏、悬浮操作按钮和列表项。
以 Android 15(API 级别 35)为目标平台的应用在 Android 15 设备上是全屏显示,并应用了边衬区,因此界面不会被隐藏。
如果应用已实现全屏显示,需要检查哪些方面

如果您的应用已实现全屏显示并应用边衬区,则基本上不会受到影响,但以下情形除外。不过,即使您认为自己不受影响,我们仍建议您测试应用。

  • 您有一个非浮动窗口,例如使用 SHORT_EDGESNEVERDEFAULT 而不是 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYSActivity。如果您的应用在启动时崩溃,这可能是由启动画面引起的。您可以将核心启动画面依赖项升级到 1.2.0-alpha01 或更高版本,也可以设置 window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always
  • 可能存在流量较低且界面被遮挡的屏幕。验证这些访问频率较低的界面是否没有被遮挡的界面。低流量屏幕包括:
    • 初始配置或登录界面
    • “设置”页面
如果您的应用尚未实现全屏显示,需要检查哪些方面

如果您的应用尚未实现全屏显示,则很可能会受到影响。除了已实现全屏显示的边缘到边缘应用的相关场景之外,您还应考虑以下事项:

  • 如果您的应用在 Compose 中使用 Material 3 组件 (androidx.compose.material3),例如 TopAppBarBottomAppBarNavigationBar,这些组件很可能不会受到影响,因为它们会自动处理边衬区。
  • 如果您的应用使用的是 Compose 中的 Material 2 组件 (androidx.compose.material),这些组件不会自动处理边衬区。不过,您可以获得边衬区的访问权限,然后手动应用边衬区。在 androidx.compose.material 1.6.0 及更高版本中,使用 windowInsets 参数可为 BottomAppBarTopAppBarBottomNavigationNavigationRail 手动应用边衬区。 同样,请为 Scaffold 使用 contentWindowInsets 参数。
  • 如果应用使用了视图和 Material 组件 (com.google.android.material),则大多数基于视图的 Material 组件(例如 BottomNavigationViewBottomAppBarNavigationRailViewNavigationView)都会处理边衬区,因此不需要执行额外的操作。不过,如果使用的是 AppBarLayout,则需要添加 android:fitsSystemWindows="true"
  • 对于自定义可组合项,请手动应用边衬区作为内边距。如果您的内容位于 Scaffold 中,则可以使用 Scaffold 内边距值来使用边衬区。否则,请使用 WindowInsets 之一应用内边距。
  • 如果应用使用的是视图和 BottomSheetSideSheet 或自定义容器,请使用 ViewCompat.setOnApplyWindowInsetsListener 应用内边距。对于 RecyclerView,请使用此监听器应用内边距,同时添加 clipToPadding="false"
如果应用必须提供自定义后台保护,您需要检查哪些方面

如果您的应用必须为三按钮导航或状态栏提供自定义背景保护,则应使用 WindowInsets.Type#tappableElement() 获取三按钮导航栏高度或 WindowInsets.Type#statusBars,在系统栏后面放置一个可组合项或视图。

其他全屏显示资源

如需了解有关应用边衬区的其他注意事项,请参阅全屏视图全屏 Compose 指南。

已弃用的 API

以下 API 已弃用,但未停用:

以下 API 已弃用并停用:

Stabilna konfiguracja

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 rozmiaru ekranu w klasie Configuration, zastąp go lepszymi alternatywami, takimi jak odpowiedni 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, ich 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 wyboru 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 przypadku użycia.

Jeśli używasz go do obliczania układu, użyj odpowiedniego 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:

Atrybut elegantTextHeight ma domyślnie wartość true.

W przypadku aplikacji przeznaczonych na Androida 15 (poziom interfejsu API 35) atrybut elegantTextHeight TextView domyślnie staje się true, co zastępuje czcionkę kompaktową używaną domyślnie w niektórych skryptach, które mają duże wymiary pionowe, czcionką o znacznie lepszej czytelności. Czcionka kompaktowa została wprowadzona, aby zapobiec rozmieszczaniu elementów układu. Android 13 (poziom interfejsu API 33) zapobiega wielu takim problemom, ponieważ pozwala na rozciąganie wysokości układu tekstu za pomocą atrybutu fallbackLineSpacing.

W Androidzie 15 czcionka kompaktowa nadal pozostaje w systemie, więc aplikacja może ustawić wartość elegantTextHeight na false, aby uzyskać takie samo działanie jak wcześniej, ale jest mało prawdopodobne, aby była obsługiwana w przyszłych wersjach. Jeśli Twoja aplikacja obsługuje te pismo: arabski, kannada, oriya, tamilski, telugu, gudżarati, malajalam, birmański, gudźarati, kannada, malajalam, oriya, telugu lub tajski, przetestuj ją, ustawiając wartość elegantTextHeight na true.

elegantTextHeightdla aplikacji kierowanych na Androida 14 (poziom API 34) i starszego.
elegantTextHeightzachowanie w przypadku aplikacji kierowanych na Androida 15.

Szerokość widoku TextView zmienia się w przypadku złożonych kształtów liter

在以前的 Android 版本中,某些具有复杂形状的手写字体或语言可能会在上一个或下一个字符的区域绘制字母。在某些情况下,此类字母会在开头或结尾处被剪裁。从 Android 15 开始,TextView 会分配宽度,以便为此类字母绘制足够的空间,并允许应用请求向左额外添加内边距以防止剪裁。

由于此更改会影响 TextView 确定宽度的方式,因此如果应用以 Android 15(API 级别 35)或更高版本为目标平台,TextView 会默认分配更多宽度。您可以通过对 TextView 调用 setUseBoundsForWidth API 来启用或停用此行为。

由于添加左内边距可能会导致现有布局未对齐,因此默认情况下不会添加内边距,即使以 Android 15 或更高版本为目标平台的应用也是如此。不过,您可以通过调用 setShiftDrawingOffsetForStartOverhang 添加额外的内边距以防止剪裁。

以下示例展示了这些更改如何改进某些字体和语言的文本布局。

采用手写体字体的英语文本的标准布局。部分字母被截断。对应的 XML 如下:

<TextView
    android:fontFamily="cursive"
    android:text="java" />
相同英语文本的布局,增加了宽度和内边距。以下是相应的 XML:

<TextView
    android:fontFamily="cursive"
    android:text="java"
    android:useBoundsForWidth="true"
    android:shiftDrawingOffsetForStartOverhang="true" />
泰语文本的标准布局。部分字母被截断。 以下是相应的 XML:

<TextView
    android:text="คอมพิวเตอร์" />
相同泰语文本的布局,增加了宽度和内边距。以下是相应的 XML:

<TextView
    android:text="คอมพิวเตอร์"
    android:useBoundsForWidth="true"
    android:shiftDrawingOffsetForStartOverhang="true" />

Domyślna wysokość wiersza w widoku EditText uwzględniająca ustawienia regionalne

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:

Trzy pola reprezentujące elementy 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:

Trzy pola reprezentujące elementy 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

Android 15 wprowadza te zmiany w działaniu aplikacji w zakresie kamery i multimediów, które są kierowane na Androida 15 lub nowszego.

Ograniczenia dotyczące żądania fokusu audio

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 dotyczące interfejsów API innych niż SDK

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. Zanim ograniczymy interfejsy inne niż SDK, w miarę możliwości udostępniamy publiczne alternatywy.

Jeśli Twoja aplikacja nie jest kierowana na Androida 15, niektóre z tych zmian mogą nie mieć na Ciebie natychmiastowego wpływu. Jednak chociaż aplikacja może mieć dostęp do niektórych interfejsów spoza SDK w zależności od docelowego poziomu interfejsu API, 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 używa interfejsów innych niż SDK, możesz to sprawdzić, testując aplikację. Jeśli Twoja aplikacja korzysta z interfejsów spoza SDK, zacznij planować migrację do alternatywnych pakietów SDK. Zdajemy sobie jednak sprawę, że w przypadku niektórych aplikacji używanie interfejsów innych niż SDK jest uzasadnione. Jeśli nie możesz znaleźć alternatywy dla używania interfejsu spoza pakietu SDK w przypadku funkcji w aplikacji, poproś o nowy publiczny interfejs API.

Więcej informacji o zmianach w tej wersji Androida znajdziesz w artykule Zmiany ograniczeń interfejsu niebędącego interfejsem SDK w Androidzie 15. Więcej informacji o interfejsach innych niż SDK znajdziesz w artykule Ograniczenia interfejsów innych niż SDK.