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

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.

Zachowanie limitu czasu usługi synchronizacji danych na pierwszym planie

Android 15 introduces a new timeout behavior to dataSync for apps targeting Android 15 or higher. This behavior also applies to the new mediaProcessing foreground service type.

The system permits an app's dataSync services to run for a total of 6 hours in a 24-hour period, after which the system calls the running service's Service.onTimeout(int, int) method (introduced in Android 15). At this time, the service has a few seconds to call Service.stopSelf(). When Service.onTimeout() is called, the service is no longer considered a foreground service. If the service does not call Service.stopSelf(), a failure will occur with this error message: "A foreground service of <fgs_type> did not stop within its timeout: <component_name>". In Beta 2, the failure message is shown as an ANR, but in a future Beta release, this failure message will throw a custom exception.

To avoid problems with this behavior change, you can do one or more of the following:

  1. Have your service implement the new Service.onTimeout(int, int) method. When your app receives the callback, make sure to call stopSelf() within a few seconds. (If you don't stop the app right away, the system generates a failure.)
  2. Make sure your app's dataSync services don't run for more than a total of 6 hours in any 24-hour period (unless the user interacts with the app, resetting the timer).
  3. Only start dataSync foreground services as a result of direct user interaction; since your app is in the foreground when the service starts, your service has the full six hours after the app goes to the background.
  4. Instead of using a dataSync foreground service, use an alternative API.

If your app's dataSync foreground services have run for 6 hours in the last 24, you cannot start another dataSync foreground service unless the user has brought your app to the foreground (which resets the timer). If you try to start another dataSync foreground service, the system throws ForegroundServiceStartNotAllowedException with an error message like "Time limit already exhausted for foreground service type dataSync".

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:

  1. 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.
  2. 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).
  3. 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.
  4. 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:

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ć

以 Android 15 为目标平台的应用无法再更改设备上的全局状态或勿扰 (DND) 政策(通过修改用户设置或关闭 DND 模式)。相反,应用必须提供一个 AutomaticZenRule,系统会将后者合并到一个具有现有最严格的政策胜出方案的全局政策中。调用之前影响全局状态的现有 API(setInterruptionFiltersetNotificationPolicy)会导致创建或更新隐式 AutomaticZenRule,该 AutomaticZenRule 根据这些 API 调用的调用周期而开启或关闭。

请注意,只有在应用调用 setInterruptionFilter(INTERRUPTION_FILTER_ALL) 且预期调用会停用之前由其所有者激活的 AutomaticZenRule 时,此变更才会影响可观察的行为。

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() i Formatter.format():

    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 zastosowaniu Arrays.asList(...).toArray() typem komponentu tablicy wynikowej jest teraz Object, a nie typ elementów tablicy. Ten kod generuje więc ClassCastException:

    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.yiid

  • 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ż metody Random.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ć parametrowi Random.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ów PendingIntent, 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.

全面强制执行

Apps are edge-to-edge by default on devices running Android 15 if the app is targeting Android 15.

An app that targets Android 14 and is not edge-to-edge on an Android 15 device.


An app that targets Android 15 and is edge-to-edge on an Android 15 device. This app mostly uses Material 3 Compose Components that automatically apply insets. This screen is not negatively impacted by the Android 15 edge-to-edge enforcement.

This is a breaking change that might negatively impact your app's UI. The changes affect the following UI areas:

  • Gesture handle navigation bar
    • Transparent by default.
    • Bottom offset is disabled so content draws behind the system navigation bar unless insets are applied.
    • setNavigationBarColor and R.attr#navigationBarColor are deprecated and don't affect gesture navigation.
    • setNavigationBarContrastEnforced and R.attr#navigationBarContrastEnforced continue to have no effect on gesture navigation.
  • 3-button navigation
    • Opacity set to 80% by default, with color possibly matching the window background.
    • Bottom offset disabled so content draws behind the system navigation bar unless insets are applied.
    • setNavigationBarColor and R.attr#navigationBarColor are set to match the window background by default. The window background must be a color drawable for this default to apply. This API is deprecated but continues to affect 3-button navigation.
    • setNavigationBarContrastEnforced and R.attr#navigationBarContrastEnforced is true by default, which adds an 80% opaque background across 3-button navigation.
  • Status bar
    • Transparent by default.
    • The top offset is disabled so content draws behind the status bar unless insets are applied.
    • setStatusBarColor and R.attr#statusBarColor are deprecated and have no effect on Android 15.
    • setStatusBarContrastEnforced and R.attr#statusBarContrastEnforced are deprecated but still have an effect on Android 15.
  • Display cutout
    • layoutInDisplayCutoutMode of non-floating windows must be LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS. SHORT_EDGES, NEVER and DEFAULT are interpreted as ALWAYS so that users don't see a Black bar caused by the display cutout and appear edge-to-edge.

The following example shows an app before and after targeting Android 15, and before and after applying insets.

An app that targets Android 14 and is not edge-to-edge on an Android 15 device.
An app that targets Android 15 and is edge-to-edge on an Android 15 device. However, many elements are now occluded by the status bar, 3-button navigation bar, or display cutout due to the Android 15 edge-to-edge enforcements. Occluded UI includes the Material 2 top app bar, floating action buttons, and list items.
An app that targets Android 15, is edge to edge on an Android 15 device and applies insets so that UI is not occluded.
What to check if your app is already edge-to-edge

If your app is already edge-to-edge and applies insets, you are mostly unimpacted, except in the following scenarios. However, even if you think you aren't impacted, we recommend you test your app.

  • You have a non-floating window, such as an Activity that uses SHORT_EDGES, NEVER or DEFAULT instead of LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS. If your app crashes on launch, this might be due to your splashscreen. You can either upgrade the core splashscreen dependency to 1.2.0-alpha01 or later or set window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always.
  • There might be lower-traffic screens with occluded UI. Verify these less-visited screens don't have occluded UI. Lower-traffic screens include:
    • Onboarding or sign-in screens
    • Settings pages
What to check if your app is not already edge-to-edge

If your app is not already edge-to-edge, you are most likely impacted. In addition to the scenarios for apps that are already edge-to-edge, you should consider the following:

  • If your app uses Material 3 Components ( androidx.compose.material3) in compose, such as TopAppBar, BottomAppBar, and NavigationBar, these components are likely not impacted because they automatically handle insets.
  • If your app is using Material 2 Components ( androidx.compose.material) in Compose, these components don't automatically handle insets. However, you can get access to the insets and apply them manually. In androidx.compose.material 1.6.0 and later, use the windowInsets parameter to apply the insets manually for BottomAppBar, TopAppBar, BottomNavigation, and NavigationRail. Likewise, use the contentWindowInsets parameter for Scaffold.
  • If your app uses views and Material Components (com.google.android.material), most views-based Material Components such as BottomNavigationView, BottomAppBar, NavigationRailView, or NavigationView, handle insets and require no additional work. However, you need to add android:fitsSystemWindows="true" if using AppBarLayout.
  • For custom composables, apply the insets manually as padding. If your content is within a Scaffold, you can consume insets using the Scaffold padding values. Otherwise, apply padding using one of the WindowInsets.
  • If your app is using views and BottomSheet, SideSheet or custom containers, apply padding using ViewCompat.setOnApplyWindowInsetsListener. For RecyclerView, apply padding using this listener and also add clipToPadding="false".
What to check if your app must offer custom background protection

If your app must offer custom background protection to 3-button navigation or the status bar, you app should place a composable or view behind the system bar using WindowInsets.Type#tappableElement() to get the 3-button navigation bar height or WindowInsets.Type#statusBars.

Additional edge-to-edge resources

See the Edge to Edge Views and Edge to Edge Compose guides for additional considerations on applying insets.

Deprecated APIs

The following APIs are now deprecated:

稳定配置

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:

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.

Zachowanie elegantTextHeight w przypadku aplikacji kierowanych na Androida 14 (poziom API 34) i starsze.
elegantTextHeight w przypadku aplikacji kierowanych na Androida 15.

Zmiana szerokości TextView w przypadku złożonych kształtów liter

In previous versions of Android, some cursive fonts or languages that have complex shaping might draw the letters in the previous or next character's area. In some cases, such letters were clipped at the beginning or ending position. Starting in Android 15, a TextView allocates width for drawing enough space for such letters and allows apps to request extra paddings to the left to prevent clipping.

Because this change affects how a TextView decides the width, TextView allocates more width by default if the app targets Android 15 or higher. You can enable or disable this behavior by calling the setUseBoundsForWidth API on TextView.

Because adding left padding might cause a misalignment for existing layouts, the padding is not added by default even for apps that target Android 15 or higher. However, you can add extra padding to preventing clipping by calling setShiftDrawingOffsetForStartOverhang.

The following examples show how these changes can improve text layout for some fonts and languages.

Standard layout for English text in a cursive font. Some of the letters are clipped. Here is the corresponding XML:

<TextView
    android:fontFamily="cursive"
    android:text="java" />
Layout for the same English text with additional width and padding. Here is the corresponding XML:

<TextView
    android:fontFamily="cursive"
    android:text="java"
    android:useBoundsForWidth="true"
    android:shiftDrawingOffsetForStartOverhang="true" />
Standard layout for Thai text. Some of the letters are clipped. Here is the corresponding XML:

<TextView
    android:text="คอมพิวเตอร์" />
Layout for the same Thai text with additional width and padding. Here is the corresponding XML:

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

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:

3 pola reprezentujące elementy EditText, które mogą zawierać tekst w języku angielskim (en), japońskim (ja) i birmańskim (my). Wysokość wiersza EditText jest taka sama, mimo że te języki różnią się wysokością wierszy.

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:

3 pola reprezentujące elementy EditText, które mogą zawierać tekst w języku angielskim (en), japońskim (ja) i birmańskim (my). Wysokość elementu EditText obejmuje teraz miejsce na domyślną wysokość wiersza dla czcionek w tych językach.

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.