Zmiany w działaniu Androida 8.0

Oprócz nowych funkcji i możliwości Android 8.0 (poziom interfejsu API 26) wprowadza wiele zmian w zachowaniu systemu i interfejsu API. W tym dokumencie omawiamy najważniejsze zmiany, które należy wziąć pod uwagę w swoich aplikacjach.

Większość tych zmian dotyczy wszystkich aplikacji, niezależnie od tego, na którą wersję Androida są one kierowane. Jednak niektóre zmiany dotyczą tylko aplikacji kierowanych na Androida 8.0. Aby zwiększyć przejrzystość, podzieliliśmy tę stronę na 2 sekcje: Zmiany dla wszystkich aplikacjiZmiany dla aplikacji kierowanych na Androida 8.0.

Zmiany we wszystkich aplikacjach

Te zmiany zachowania dotyczą wszystkich aplikacji, które działają na platformie Android 8.0 (poziom interfejsu API 26), niezależnie od poziomu interfejsu API, na który są kierowane. Wszyscy deweloperzy powinni zapoznać się z tymi zmianami i w razie potrzeby odpowiednio zmodyfikować swoje aplikacje, aby były z nimi zgodne.

Limity wykonywania w tle

Jednym z modyfikacji wprowadzonych w Androidzie 8.0 (poziom interfejsu API 26) w celu wydłużenia czasu pracy na baterii jest to, że gdy aplikacja przechodzi w stan cached (zapisany w pamięci podręcznej) bez aktywnych komponentów, system zwalnia wszystkie blokady budzenia, które aplikacja posiada.

Aby zwiększyć wydajność urządzenia, system ogranicza też niektóre działania aplikacji, które nie działają na pierwszym planie. Więcej szczegółów:

  • Aplikacje działające w tle mają teraz ograniczony dostęp do usług działających w tle.
  • Aplikacje nie mogą używać swoich plików manifestu do rejestrowania większości komunikatów niejawnych (czyli transmisji, które nie są na nie kierowane).

Domyślnie te ograniczenia dotyczą tylko aplikacji kierowanych na O. Użytkownicy mogą jednak włączyć te ograniczenia w dowolnej aplikacji na ekranie Ustawienia, nawet jeśli aplikacja nie jest kierowana na O.

Android 8.0 (poziom interfejsu API 26) zapewnia też te zmiany w konkretnych metodach:

  • Metoda startService() powoduje teraz błąd IllegalStateException, jeśli aplikacja kierowana na Androida 8.0 próbuje użyć tej metody w sytuacji, gdy nie może utworzyć usług działających w tle.
  • Nowa metoda Context.startForegroundService() uruchamia usługę na pierwszym planie. System zezwala aplikacjom na wywoływanie Context.startForegroundService() nawet wtedy, gdy aplikacja działa w tle. Aplikacja musi jednak wywołać metodę startForeground() tej usługi w ciągu 5 sekund od jej utworzenia.

Więcej informacji znajdziesz w artykule Limity wykonywania w tle.

Limity lokalizacji w tle na Androidzie

Aby oszczędzać baterię, dbać o wygodę użytkowników i stan systemu, aplikacje działające w tle otrzymują aktualizacje lokalizacji rzadziej, gdy są używane na urządzeniu z Androidem 8.0. Ta zmiana działania ma wpływ na wszystkie aplikacje, które otrzymują aktualizacje lokalizacji, w tym na Usługi Google Play.

Te zmiany dotyczą tych interfejsów API:

  • Dostawca uśrednionej lokalizacji (FLP)
  • Geofencing
  • Pomiary GNSS
  • Menedżer lokalizacji
  • Menedżer Wi-Fi

Aby mieć pewność, że aplikacja działa zgodnie z oczekiwaniami, wykonaj te czynności:

  • Sprawdź logikę swojej aplikacji i upewnij się, że używasz najnowszych interfejsów API lokalizacji.
  • Sprawdź, czy aplikacja zachowuje się zgodnie z oczekiwaniami w każdym przypadku użycia.
  • Rozważ użycie połączonego dostawcy lokalizacji (FLP) lub geofencingu, aby obsłużyć przypadki użycia, które zależą od bieżącej lokalizacji użytkownika.

Więcej informacji o tych zmianach znajdziesz w artykule Ograniczenia dostępu do lokalizacji w tle.

Skróty do aplikacji

Android 8.0 (poziom interfejsu API 26) zawiera te zmiany dotyczące skrótów aplikacji:

  • Transmisja com.android.launcher.action.INSTALL_SHORTCUT nie ma już wpływu na Twoją aplikację, ponieważ jest teraz prywatną, domyślną transmisją. Zamiast tego utwórz skrót do aplikacji, korzystając z metody requestPinShortcut() z klasy ShortcutManager.
  • Intencją ACTION_CREATE_SHORTCUT można teraz tworzyć skróty aplikacji, którymi zarządzasz za pomocą klasy ShortcutManager. Ta intencja może też tworzyć skróty w starszych wersjach programu uruchamiającego, które nie współpracują z ShortcutManager. Wcześniej ta intencja mogła tworzyć tylko skróty w starszych wersjach programu uruchamiającego.
  • Skróty utworzone za pomocą funkcji requestPinShortcut() oraz skróty utworzone w aktywności, która obsługuje intencję ACTION_CREATE_SHORTCUT są teraz pełnoprawnymi skrótami aplikacji. W związku z tym aplikacje mogą teraz aktualizować je za pomocą metod z ShortcutManager.
  • Stare skróty zachowują funkcjonalność z poprzednich wersji Androida, ale musisz je ręcznie przekonwertować na skróty do aplikacji.

Więcej informacji o zmianach w skrótach do aplikacji znajdziesz w przewodniku po funkcji Przypinanie skrótów i widżetów.

Języki i internacjonalizacja

W Androidzie 7.0 (poziom interfejsu API 24) wprowadzono możliwość określenia domyślnego języka kategorii, ale niektóre interfejsy API nadal korzystały z ogólnej metody Locale.getDefault() bez argumentów, podczas gdy w ich przypadku należałoby użyć domyślnego języka kategorii DISPLAY. W Androidzie 8.0 (poziom interfejsu API 26) w tych metodach zamiast Locale.getDefault() jest używana wartość Locale.getDefault(Category.DISPLAY):

Funkcja Locale.getDisplayScript(Locale) przechodzi też do wartości Locale.getDefault(), gdy wartość displayScript podana dla argumentu Locale jest niedostępna.

Dodatkowe zmiany związane z lokalizacją i międzynarodowością:

  • Wywołanie Currency.getDisplayName(null) powoduje błąd NullPointerException, co odpowiada udokumentowanemu działaniu.
  • Zmieniono analizowanie nazwy strefy czasowej. Wcześniej urządzenia z Androidem używały wartości zegara systemowego pobranej podczas uruchamiania, aby przechowywać w pamięci podręcznej nazwy stref czasowych używanych do analizowania dat i czasów. W efekcie może to negatywnie wpłynąć na parsowanie, jeśli zegar systemowy był nieprawidłowy podczas uruchamiania lub w innych rzadszych przypadkach.

    Obecnie w typowych przypadkach logika analizowania używa ICU i obecnej wartości zegara systemowego podczas analizowania nazw stref czasowych. Ta zmiana zapewnia bardziej prawidłowe wyniki, które mogą się różnić od wyników z wcześniejszych wersji Androida, gdy aplikacja używa klas takich jak SimpleDateFormat.

  • Android 8.0 (poziom interfejsu API 26) aktualizuje wersję ICU do wersji 58.

Okna alertów

Jeśli aplikacja korzysta z uprawnienia SYSTEM_ALERT_WINDOWi używa jednego z tych typów okien, aby wyświetlać okna alertów nad innymi aplikacjami i oknami systemowymi:

...to te okna zawsze będą się pojawiać pod oknami, które używają typu okna TYPE_APPLICATION_OVERLAY. Jeśli aplikacja jest kierowana na Androida 8.0 (poziom interfejsu API 26), aplikacja używa typu okna TYPE_APPLICATION_OVERLAY do wyświetlania okien alertów.

Więcej informacji znajdziesz w sekcji Typowe typy okien alertów w artykule o zmianach działania aplikacji kierowanych na Androida 8.0.

Wpisywanie i poruszanie się po ekranie

Wraz z postępem aplikacji na Androida w ChromeOS i na innych dużych urządzeniach, takich jak tablety, obserwujemy ponowny wzrost korzystania z nawigacji za pomocą klawiatury w aplikacjach na Androida. W Androidzie 8.0 (poziom interfejsu API 26) ponownie zajęliśmy się kwestią używania klawiatury jako urządzenia do wprowadzania danych nawigacyjnych. W efekcie udało nam się stworzyć bardziej niezawodny i przewidywalny model nawigacji za pomocą strzałek i kart.

Wprowadziliśmy te zmiany w zachowaniu dotyczącego fokusowania elementów:

  • Jeśli nie zdefiniujesz żadnych kolorów stanu skupienia dla obiektu View (czy to pierwszego planu, czy tła), framework ustawi domyślny kolor wyróżnienia skupienia dla View. To podświetlenie jest elementem rysowanym falą, który zmienia się w zależności od motywu aktywności.

    Jeśli nie chcesz, aby obiekt View używał domyślnego podświetlenia po uzyskaniu fokusa, ustaw atrybut android:defaultFocusHighlightEnabled na false w pliku XML układu zawierającym element View lub przekaż wartość false do elementu setDefaultFocusHighlightEnabled() w logice interfejsu użytkownika aplikacji.

  • Aby sprawdzić, jak dane wprowadzane za pomocą klawiatury wpływają na skupienie na elemencie interfejsu, możesz włączyć opcję dla programistów Rysowanie > Pokaż granice układu. W Androidzie 8.0 ta opcja wyświetla ikonę „X” nad aktualnie zaznaczonym elementem.

Wszystkie elementy paska narzędzi w Androidzie 8.0 są automatycznie grupowane na klawiaturze, co ułatwia użytkownikom nawigację po poszczególnych paskach narzędzi.

Aby dowiedzieć się więcej o ulepszaniu obsługi nawigacji za pomocą klawiatury w aplikacji, przeczytaj przewodnik Wsparcie nawigacji za pomocą klawiatury.

Autouzupełnianie formularzy internetowych

Teraz, gdy Framework autouzupełniania na Androida zapewnia wbudowane wsparcie dla funkcji autouzupełniania, w przypadku aplikacji zainstalowanych na urządzeniach z Androidem 8.0 (poziom interfejsu API 26) zmieniły się następujące metody związane z obiektmi WebView:

WebSettings
WebViewDatabase
  • Wywołanie clearFormData() nie działa już.
  • Metoda hasFormData() zwraca teraz wartość false. Wcześniej ta metoda zwracałatrue, gdy formularz zawierał dane.

Ułatwienia dostępu

Android 8.0 (poziom interfejsu API 26) zawiera te zmiany dotyczące ułatwień dostępu:

  • Platforma dostępności konwertuje teraz wszystkie gesty podwójnego dotknięcia w akcje ACTION_CLICK. Ta zmiana sprawi, że TalkBack będzie działać bardziej jak inne usługi ułatwień dostępu.

    Jeśli obiekty View w aplikacji korzystają z niestandardowego obsługiwania dotyku, sprawdź, czy nadal działają z TalkBack. Wystarczy, że zarejestrujesz moduł obsługi kliknięcia, którego używają obiekty View. Jeśli TalkBack nadal nie rozpoznaje gestów wykonywanych na tych obiektachView, zastąpij jeperformAccessibilityAction().

  • Usługi ułatwień dostępu są teraz świadome wszystkich wystąpień ClickableSpan w obiektach TextView w aplikacji.

Więcej informacji o zwiększaniu dostępności aplikacji znajdziesz w artykule Ułatwienia dostępu.

Sieć i połączenia HTTP(S)

Android 8.0 (poziom interfejsu API 26) zawiera te zmiany zachowania dotyczące sieci i połączeń HTTP(S):

  • Żądania OPTIONS bez treści mają nagłówek Content-Length: 0. Wcześniej nie miały nagłówka Content-Length.
  • HttpURLConnection normalizuje adresy URL zawierające puste ścieżki, dodając ukośnik po nazwie hosta lub autorytetu. Na przykład: http://example.com jest przekształcane w http://example.com/.
  • Niestandardowy selektor serwera proxy ustawiony za pomocą funkcji ProxySelector.setDefault() jest kierowany tylko na adres (schemat, host i port) żądanego adresu URL. W rezultacie wybór serwera proxy może być oparty tylko na tych wartościach. Adres URL przekazany niestandardowemu selektorowi serwera proxy nie zawiera ścieżki, parametrów zapytania ani fragmentów żądanego adresu URL.
  • Identyfikatory URI nie mogą zawierać pustych etykiet.

    Wcześniej platforma obsługiwała obejście polegające na akceptowanie pustych etykiet w nazwach hostów, co jest niedozwolone w przypadku identyfikatorów URI. To obejście miało na celu zapewnienie zgodności ze starszymi wersjami libcore. Deweloperzy korzystający z interfejsu API w nieprawidłowy sposób zobaczą komunikat ADB: „Identyfikator URI example..com zawiera puste etykiety w nazwie hosta. Jest on źle sformatowany i nie będzie akceptowany w przyszłych wersjach Androida." W Androidzie 8.0 nie można już stosować tego obejścia. W przypadku nieprawidłowego identyfikatora URI system zwraca wartość null.

  • Implementacja klasy HttpsURLConnection w Androidzie 8.0 nie korzysta z niebezpiecznej wersji protokołu TLS/SSL.
  • Obsługa tunelowania połączeń HTTP(S) zmieniła się w ten sposób:
    • Podczas tunelowania połączenia HTTPS przez połączenie system prawidłowo umieszcza numer portu (:443) w wierszu Host, wysyłając te informacje do serwera pośredniego. Wcześniej numer portu występował tylko w wierszu CONNECT.
    • System nie wysyła już nagłówków user-agent i proxy-authorization z tunelowanego żądania do serwera proxy.

      Podczas konfigurowania tunelu system nie wysyła już do serwera proxy nagłówka autoryzacji serwera proxy w tunelu Http(s)URLConnection do serwera proxy. Zamiast tego system generuje nagłówek proxy-authorization i wysyła go do serwera proxy, gdy ten wysyła odpowiedź HTTP 407 w odpowiedzi na początkowe żądanie.

      System nie będzie już kopiować nagłówka klienta użytkownika z żądania tunelowanego do żądania serwera proxy, które konfiguruje tunel. Zamiast tego biblioteka generuje nagłówek klienta użytkownika dla tego żądania.

  • Jeśli wcześniej wykonana metoda connect() zakończyła się niepowodzeniem, metoda send(java.net.DatagramPacket) zgłasza SocketException.
    • Jeśli wystąpi błąd wewnętrzny, DatagramSocket.connect() ustawia pendingSocketException. W wersjach Androida starszych niż 8.0 wywołanie funkcji recv() wywoływało SocketException, mimo że wywołanie funkcji send() zakończyło się powodzeniem. W trosce o spójność oba wywołania rzucają teraz SocketException.
  • InetAddress.isReachable() próbuje użyć protokołu ICMP, a potem, jeśli to nie zadziała, używa protokołu TCP Echo.
    • Niektóre hosty, które blokują port 7 (TCP Echo), takie jak google.com, mogą stać się dostępne, jeśli akceptują protokół ICMP Echo.
    • W przypadku hostów, których nie można dosięgnąć, ta zmiana oznacza, że przed powrotem wywołania mija podwójna ilość czasu.

Bluetooth

W Androidzie 8.0 (poziom interfejsu API 26) wprowadzono następujące zmiany długości danych zwracanych przez metodę ScanRecord.getBytes():

  • Metoda getBytes() nie zakłada żadnej liczby bajtów. Dlatego aplikacje nie powinny polegać na minimalnej ani maksymalnej liczbie zwracanych bajtów. Zamiast tego należy sprawdzić długość tablicy wynikowej.
  • Urządzenia zgodne z Bluetooth 5 mogą zwracać dane o długości przekraczającej poprzedni maksymalny limit około 60 bajtów.
  • Jeśli urządzenie zdalne nie odpowie na skanowanie, może zwrócić mniej niż 60 bajtów.

Bezproblemowa łączność

Android 8.0 (poziom interfejsu API 26) wprowadza szereg ulepszeń ustawień Wi-Fi, aby ułatwić wybór sieci Wi-Fi, która zapewnia najlepsze wrażenia użytkownika. Dotychczasowe zmiany:

  • Ulepszenia stabilności i niezawodności.
  • bardziej czytelny interfejs;
  • jedno, skonsolidowane menu Ustawienia Wi-Fi.
  • Na zgodnych urządzeniach automatyczne włączanie Wi-Fi, gdy w pobliżu znajduje się zapisana sieć wysokiej jakości.

Bezpieczeństwo

W Androidzie 8.0 wprowadziliśmy te zmiany dotyczące bezpieczeństwa:

  • Platforma nie obsługuje już protokołu SSLv3.
  • Podczas nawiązywania połączenia HTTPS z serwerem, który nieprawidłowo implementuje negocjację wersji protokołu TLS, HttpsURLConnection nie próbuje już obejścia problemu przez przejście na wcześniejsze wersje protokołu TLS i ponowne próby.
  • Android 8.0 (poziom API 26) stosuje filtr SECCOMP do wszystkich aplikacji. Lista dozwolonych wywołań systemowych jest ograniczona do tych, które są dostępne za pomocą bionic. Chociaż istnieje kilka innych wywołań systemowych udostępnionych ze względu na zgodność z wcześniejszymi wersjami, zalecamy, aby ich nie używać.
  • Obiekty WebView w aplikacji są teraz uruchamiane w trybie wieloprocesowym. Treści internetowe są obsługiwane w ramach osobnego, odizolowanego procesu od procesu aplikacji, aby zwiększyć bezpieczeństwo.
  • Nie możesz już zakładać, że pliki APK znajdują się w katalogach, których nazwy kończą się na -1 lub -2. Aplikacje powinny używać sourceDir do uzyskiwania danych z katalogu, a nie bezpośrednio formatu katalogu.
  • Informacje o ulepszeniach zabezpieczeń związanych z korzystaniem z bibliotek natywnych znajdziesz w artykule Biblioteki natywne.

Dodatkowo Android 8.0 (interfejs API na poziomie 26) wprowadza te zmiany dotyczące instalowania nieznanych aplikacji z nieznanych źródeł:

Więcej informacji o instalowaniu nieznanych aplikacji znajdziesz w poradnikach dotyczących uprawnień do instalowania nieznanych aplikacji.

Dodatkowe wskazówki na temat zwiększania bezpieczeństwa aplikacji znajdziesz w artykule Bezpieczeństwo dla deweloperów aplikacji na Androida.

Prywatność

Android 8.0 (poziom 26 interfejsu API) wprowadza na platformie te zmiany związane z prywatnością:

  • Platforma obsługuje teraz identyfikatory inaczej.
    • W przypadku aplikacji zainstalowanych przed aktualizacją OTA do wersji Androida 8.0 (poziom interfejsu API 26) (poziom interfejsu API 26) wartość ANDROID_ID pozostaje bez zmian, chyba że zostanie odinstalowana, a potem ponownie zainstalowana po aktualizacji OTA. Aby zachować wartości po odinstalowaniu OTA, deweloperzy mogą powiązać stare i nowe wartości, używając kopii zapasowej kluczy i wartości.
    • W przypadku aplikacji zainstalowanych na urządzeniu z Androidem 8.0 wartość parametru ANDROID_ID jest teraz ograniczona do klucza podpisywania aplikacji i użytkownika. WartośćANDROID_ID jest unikalna dla każdej kombinacji klucza podpisywania aplikacji, użytkownika i urządzenia. W efekcie aplikacje z różnymi kluczami podpisywania działające na tym samym urządzeniu nie będą już widzieć tego samego identyfikatora Android ID (nawet w przypadku tego samego użytkownika).
    • Wartość ANDROID_IDnie zmienia się po odinstalowaniu lub ponownym zainstalowaniu pakietu, o ile klucz podpisywania pozostaje ten sam (i aplikacja nie została zainstalowana przed aktualizacją OTA do wersji Androida 8.0).
    • Wartość ANDROID_IDnie zmienia się nawet wtedy, gdy aktualizacja systemu powoduje zmianę klucza podpisywania pakietu.
    • Na urządzeniach z usługami Google Play i identyfikatorem wyświetlania reklam musisz używać identyfikatora wyświetlania reklam. Prosty, standardowy system zarabiania na aplikacjach. Identyfikator wyświetlania reklam to unikalny, możliwy do zresetowania przez użytkownika identyfikator wyświetlania reklam. Jest ona udostępniana przez Usługi Google Play.

      Inni producenci urządzeń powinni nadal udostępniać ANDROID_ID.

  • Zapytanie do właściwości systemowej net.hostname zwraca wartość null.

Logowanie niewykrytych wyjątków

Jeśli aplikacja zainstaluje Thread.UncaughtExceptionHandler, która nie wywołuje domyślnej Thread.UncaughtExceptionHandler, system nie zabija aplikacji, gdy wystąpi nieprzechwycony wyjątek. Począwszy od Androida 8.0 (poziom interfejsu API 26) system w tej sytuacji rejestruje wyjątek stosu wyjątków. We wcześniejszych wersjach platformy system nie zarejestrował tego zrzutu stosu wyjątków.

Zalecamy, aby niestandardowe implementacje Thread.UncaughtExceptionHandler zawsze wywoływały domyślny moduł obsługi. Zmiana w Androidzie 8.0 nie ma wpływu na aplikacje, które korzystają z tego zalecenia.

Zmiana podpisu findViewById()

Wszystkie instancje metody findViewById() zwracają teraz <T extends View> T zamiast View. Ta zmiana będzie miała te konsekwencje:

  • Może to spowodować, że istniejący kod będzie miał niejednoznaczny typ zwracanych danych, na przykład jeśli istnieją funkcje someMethod(View)someMethod(TextView), które przyjmują wynik wywołania funkcji findViewById().
  • W przypadku języka źródłowego Java 8 wymagane jest jawne zastąpienie wartości View, gdy typ zwracany nie jest ograniczony (np. assertNotNull(findViewById(...)).someViewMethod())).
  • Zastąpienia metod findViewById(), które nie są metodami końcowymi (na przykład Activity.findViewById()), będą wymagać zaktualizowania typu zwracanej wartości.

Zmiana statystyk użytkowania dostawcy kontaktów

W poprzednich wersjach Androida komponent Dostawca kontaktów umożliwia programistom uzyskanie danych o korzystaniu z każdego kontaktu. Te dane o korzystaniu zawierają informacje o każdym adresie e-mail i numerze telefonu powiązanym z kontaktem, w tym liczbę i czas ostatniego kontaktu z kontaktem. Aplikacje, które wymagają uprawnienia READ_CONTACTS mogą odczytywać te dane.

Aplikacje mogą nadal odczytywać te dane, jeśli poproszą o uprawnienia READ_CONTACTS. W Androidzie 8.0 (poziom interfejsu API 26) i nowszych wersjach zapytania dotyczące danych o użytkowaniu zwracają wartości przybliżone, a nie dokładne. System Androida przechowuje dokładne wartości wewnętrznie, więc ta zmiana nie ma wpływu na interfejs Autocomplete API.

Ta zmiana działania wpływa na te parametry zapytania:

Obsługa odbioru

AbstractCollection.removeAll()AbstractCollection.retainAll() teraz zawsze rzucają błąd NullPointerException; wcześniej błąd NullPointerException nie był rzucany, gdy kolekcja była pusta. Ta zmiana sprawia, że działanie jest zgodne z dokumentacją.

Android Enterprise

Android 8.0 (poziom interfejsu API 26) zmienia zachowanie niektórych interfejsów API i funkcji w aplikacjach dla firm, w tym kontrolerów zasad urządzeń (DPC). Zmiany obejmują:

  • Nowe zachowania, które pomagają aplikacjom obsługiwać profile służbowe na urządzeniach w pełni zarządzanych.
  • Zmiany w obsługiwaniu aktualizacji systemu, weryfikacji aplikacji i uwierzytelnianiu w celu zwiększenia integralności urządzenia i systemu.
  • Ulepszenia wrażeń użytkowników dotyczącego obsługi, powiadomień, ekranu Ostatnie i VPN-u zawsze włączonego.

Aby zobaczyć wszystkie zmiany w Androidzie 8.0 (interfejs API na poziomie 26) dotyczące przedsiębiorstw i dowiedz się, jak mogą one wpłynąć na Twoją aplikację, przeczytaj artykuł Android w przedsiębiorstwie.

Aplikacje kierowane na Androida 8.0

Te zmiany w działaniu dotyczą tylko aplikacji kierowanych na Androida 8.0 (poziom interfejsu API 26) lub nowszego. Aplikacje skompilowane pod kątem Androida 8.0 lub z ustawionymi parametrami targetSdkVersion Androida 8.0 lub nowszego muszą zostać zmodyfikowane, aby prawidłowo obsługiwać te zachowania (w odpowiednich przypadkach).

Okna alertów

Aplikacje, które używają uprawnienia SYSTEM_ALERT_WINDOW, nie mogą już używać tych typów okien do wyświetlania okien alertów nad innymi aplikacjami i oknami systemowymi:

Zamiast tego aplikacje muszą używać nowego typu okna o nazwie TYPE_APPLICATION_OVERLAY.

Jeśli używasz okna typu TYPE_APPLICATION_OVERLAY do wyświetlania ostrzeżeń w aplikacji, pamiętaj o tych cechach nowego typu okna:

  • Okna alertów aplikacji zawsze pojawiają się pod oknami krytycznymi systemu, takimi jak pasek stanu czy IME.
  • Aby usprawnić prezentację ekranu, system może przenosić lub zmieniać rozmiar okien w typie okna TYPE_APPLICATION_OVERLAY.
  • Po otwarciu obszaru powiadomień użytkownicy mogą uzyskać dostęp do ustawień, aby zablokować wyświetlanie okien alertów przez aplikację za pomocą typu okna TYPE_APPLICATION_OVERLAY.

Powiadomienia o zmianach treści

Android 8.0 (poziom interfejsu API 26) zmienia sposób działania funkcji ContentResolver.notifyChange() i registerContentObserver(Uri, boolean, ContentObserver) w aplikacjach kierowanych na Androida 8.0.

Te interfejsy API wymagają teraz, aby w przypadku wszystkich adresów URI autorytetu zdefiniowano prawidłową wartość parametru ContentProvider. Zdefiniowanie prawidłowego ContentProvider z odpowiednimi uprawnieniami pomoże Ci chronić aplikację przed zmianami treści w złośliwych aplikacjach i uniknąć wycieku potencjalnie prywatnych danych do szkodliwych aplikacji.

Wyświetlanie skupienia

Domyślnie możliwe do kliknięcia obiekty View są również możliwe do zaznaczenia. Jeśli chcesz, aby obiekt View był klikalny, ale nie można było go zaznaczyć, ustaw atrybut android:focusable na false w pliku XML układu zawierającym element View lub prześlij wartość false do elementu setFocusable() w logice interfejsu użytkownika aplikacji.

Dopasowywanie klienta użytkownika w wykrywaniu przeglądarki

Android 8.0 (poziom interfejsu API 26) i nowsze zawierają ciąg identyfikatora kompilacji OPR. Niektóre dopasowania wzorców mogą powodować, że logika wykrywania przeglądarki błędnie zidentyfikuje przeglądarkę inną niż Opera jako Operę. Przykładem takiego dopasowania do wzorca może być:

if(p.match(/OPR/)){k="Opera";c=p.match(/OPR\/(\d+.\d+)/);n=new Ext.Version(c[1])}

Aby uniknąć problemów wynikających z takiej błędnej identyfikacji, użyj w przypadku przeglądarki Opera ciągu innego niż OPR jako dopasowania do wzorca.

Bezpieczeństwo

Te zmiany wpływają na bezpieczeństwo w Androidzie 8.0 (poziom interfejsu API 26):

  • Jeśli konfiguracja bezpieczeństwa sieci w aplikacji wyłącza obsługę ruchu nieszyfrowanego, obiekty WebView w aplikacji nie mogą uzyskiwać dostępu do witryn przez HTTP. Każdy obiekt WebView musi używać protokołu HTTPS.
  • Usunęliśmy ustawienie systemowe Zezwalaj na nieznane źródła. Zamiast niego uprawnienie Instalowanie nieznanych aplikacji służy do zarządzania nieznanymi instalacjami aplikacji z nieznanych źródeł. Więcej informacji o tych nowych uprawnieniach znajdziesz w przewodniku na temat nieznanych uprawnień do instalowania aplikacji.

Więcej wskazówek na temat zwiększania bezpieczeństwa aplikacji znajdziesz w artykule Zabezpieczenia dla deweloperów aplikacji na Androida.

Dostęp do konta i wykrywalność

W Androidzie 8.0 (poziom interfejsu API 26) aplikacje nie mogą już uzyskiwać dostępu do kont użytkowników, chyba że uwierzytelniacz jest ich właścicielem lub użytkownik przyznał dostęp. Uprawnienie GET_ACCOUNTS nie wystarcza już do zalogowania się. Aby uzyskać dostęp do konta, aplikacje powinny używać AccountManager.newChooseAccountIntent()lub metody konkretnej dla uwierzytelniania. Po uzyskaniu dostępu do kont aplikacja może wywołać funkcję AccountManager.getAccounts(), aby z nich skorzystać.

Wycofujemy Androida 8.0 LOGIN_ACCOUNTS_CHANGED_ACTION. Zamiast tego aplikacje powinny używać interfejsu addOnAccountsUpdatedListener(), aby otrzymywać informacje o kontach w czasie działania.

Informacje o nowych interfejsach API i metodach dodanych do konta i wykrywalności konta znajdziesz w artykule Dostęp do konta i wykrywalność w sekcji Nowe interfejsy API w tym dokumencie.

Prywatność

Następujące zmiany wpływają na ochronę prywatności w Androidzie 8.0 (poziom interfejsu API 26).

  • Właściwości systemowe net.dns1, net.dns2, net.dns3 i net.dns4 nie są już dostępne. To zmiana poprawiająca ochronę prywatności na platformie.
  • Aby uzyskać informacje o sieci, takie jak serwery DNS, aplikacje z uprawnieniem ACCESS_NETWORK_STATE mogą zarejestrować obiekt NetworkRequest lub NetworkCallback. Te klasy są dostępne w Androidzie 5.0 (poziom interfejsu API 21) i nowszych.
  • Parametr Build.SERIAL został wycofany. Aplikacje, które muszą znać numer seryjny sprzętu, powinny zamiast tego używać nowej metody Build.getSerial(), która wymaga uprawnienia READ_PHONE_STATE.
  • Interfejs API LauncherApps nie zezwala już aplikacjom profilu służbowego na dostęp do informacji o profilu głównym. Gdy użytkownik znajduje się w profilu służbowym, interfejs API LauncherApps zachowuje się tak, jakby żadne aplikacje nie zostały zainstalowane w innych profilach w tej samej grupie profili. Jak wcześniej, próby uzyskania dostępu do niezwiązanych profili powodują SecurityExceptions.

Uprawnienia

W Androidzie 8.0 (poziom interfejsu API 26) w przypadku, gdy aplikacja poprosiła o uprawnienia w czasie działania i zostały one przyznane, system nieprawidłowo przyznawał aplikacji także pozostałe uprawnienia należące do tej samej grupy uprawnień, które były zarejestrowane w pliku manifestu.

W przypadku aplikacji kierowanych na Androida 8.0 to zachowanie zostało poprawione. Aplikacja otrzymuje tylko te uprawnienia, o które wyraźnie prosi. Gdy jednak użytkownik przyzna aplikacji uprawnienia, wszystkie kolejne prośby o uprawnienia z tej grupy uprawnień będą automatycznie przyznawane.

Załóżmy na przykład, że aplikacja zawiera w swoim pliku manifestu zarówno identyfikator READ_EXTERNAL_STORAGE, jak i WRITE_EXTERNAL_STORAGE. Aplikacja prosi o dostęp do READ_EXTERNAL_STORAGE, a użytkownik zezwala na to. Jeśli aplikacja jest kierowana na interfejs API na poziomie 25 lub niższym, system jednocześnie przyznaje też WRITE_EXTERNAL_STORAGE, ponieważ należy ona do tej samej grupy uprawnień STORAGE i jest też zarejestrowana w pliku manifestu. Jeśli aplikacja jest kierowana na Androida 8.0 (poziom interfejsu API 26), system przyznaje jej tylko uprawnienie READ_EXTERNAL_STORAGE. Jeśli jednak aplikacja poprosi o uprawnienie WRITE_EXTERNAL_STORAGE, system natychmiast przyzna je bez pytania użytkownika.

Multimedia

  • Platforma może samodzielnie przeprowadzać automatyczne wyciszanie dźwięku. W tym przypadku, gdy inna aplikacja żąda fokusa na kluczu AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, wybrana aplikacja zmniejsza głośność, ale zwykle nie otrzymuje wywołania zwrotnego onAudioFocusChange() i nie traci aktywności audio. W przypadku aplikacji, które muszą wstrzymywać, a nie wyciszać dźwięk, dostępne są nowe interfejsy API, które umożliwiają pominięcie tego zachowania.
  • Gdy użytkownik odbierze połączenie telefoniczne, aktywne strumienie multimediów będą wyciszone na czas rozmowy.
  • Aby opisać odtwarzanie dźwięku, należy użyć interfejsu API AudioAttributes, a nie typów strumieni audio. Nadal używaj typów strumieni audio tylko do sterowania głośnością. Inne zastosowania typów strumieni nadal działają (np. argument streamType w przypadku przestarzałego konstruktora AudioTrack), ale system rejestruje to jako błąd.
  • Jeśli podczas korzystania z AudioTrack aplikacja poprosi o wystarczająco duży bufor audio, framework spróbuje użyć wyjścia z głębokim buforem, jeśli jest ono dostępne.
  • W Androidzie 8.0 (poziom interfejsu API 26) obsługa zdarzeń przycisku multimedialnego jest inna:
    1. Sposób obsługi przycisków multimediów w działaniach interfejsu użytkownika nie uległ zmianie: działania na pierwszym planie nadal mają priorytet.
    2. Jeśli działanie na pierwszym planie nie obsługuje zdarzenia przycisku multimediów, system przekierowuje to zdarzenie do aplikacji, w której ostatnio odtwarzany jest dźwięk. Przy określaniu, która aplikacja ma otrzymywać zdarzenia przycisku multimediów, nie są brane pod uwagę stan aktywny, flagi ani stan odtwarzania sesji multimediów.
    3. Jeśli sesja multimediów w aplikacji została opublikowana, system wysyła zdarzenie przycisku multimediów do obiektu MediaButtonReceiver aplikacji (jeśli go ma).
    4. W każdym innym przypadku system odrzuca zdarzenie związane z przyciskiem multimediów.

Biblioteki natywne

W aplikacjach kierowanych na Androida 8.0 (poziom interfejsu API 26) natywne biblioteki nie są już wczytywane, jeśli zawierają segment ładowania, który jest jednocześnie zapisywalny i wykonalny. Z powodu tej zmiany niektóre aplikacje mogą przestać działać, jeśli mają biblioteki natywne z nieprawidłowymi segmentami wczytywania. Jest to środek zwiększający bezpieczeństwo.

Więcej informacji znajdziesz w artykule Segmenty możliwe do zapisu i wykonywalne.

Zmiany w linkowaniu są powiązane z poziomem interfejsu API, na który kierowana jest aplikacja. Jeśli nastąpi zmiana tagu łączącego na docelowym poziomie interfejsu API, aplikacja nie będzie mogła wczytać biblioteki. Jeśli kierujesz się na poziom interfejsu API niższy niż ten, na którym występuje zmiana w linkerze, logcat wyświetla ostrzeżenie.

Obsługa odbioru

W Androidzie 8.0 (poziom interfejsu API 26) zamiast List.sort() zaimplementowano interfejs Collections.sort(). W Androidzie 7.x (poziom interfejsu API 24 i 25) było to odwrotne: domyślna implementacja List.sort() nazywała się Collections.sort().

Ta zmiana pozwala Collections.sort() korzystać z optymalnych implementacji List.sort(), ale wiąże się z tymi ograniczeniami:

  • Implementacje funkcji List.sort() nie mogą wywoływać funkcji Collections.sort(), ponieważ spowodowałoby to przepełnienie stosu z powodu nieskończonej rekurencji. Jeśli chcesz, aby implementacja List działała domyślnie, unikaj zastępowania właściwości sort().

    Jeśli klasa nadrzędna implementuje funkcję sort() w nieodpowiedni sposób, zwykle można zastąpić funkcję List.sort() implementacją opartą na funkcjach List.toArray(), Arrays.sort()ListIterator.set(). Na przykład:

    @Override
    public void sort(Comparator<? super E> c) {
      Object[] elements = toArray();
      Arrays.sort(elements, c);
      ListIterator<E> iterator = (ListIterator<Object>) listIterator();
      for (Object element : elements) {
        iterator.next();
        iterator.set((E) element);
      }
    }

    W większości przypadków możesz też zastąpićList.sort()implementację implementacją, która deleguje do różnych domyślnych implementacji w zależności od poziomu interfejsu API. Na przykład:

    @Override
    public void sort(Comparator<? super E> comparator) {
      if (Build.VERSION.SDK_INT <= 25) {
        Collections.sort(this);
      } else {
        super.sort(comparator);
      }
    }

    Jeśli robisz to tylko dlatego, że chcesz mieć metodę sort() dostępną na wszystkich poziomach interfejsu API, rozważ nadanie jej unikalnej nazwy, np. sortCompat(), zamiast zastępować metodę sort().

  • Collections.sort() jest teraz uznawana za modyfikację strukturalną w implementacjach list, które wywołują sort(). Na przykład w wersjach platformy starszych niż Android 8.0 (poziom interfejsu API 26) iteracja z użyciem parametru ArrayList i wywołanie w niej funkcji sort() w trakcie iteracji skutkowało wywołaniem ConcurrentModificationException, jeśli sortowanie zostało wykonane przez wywołanie List.sort(). Collections.sort() nie zwrócił wyjątku.

    Ta zmiana powoduje, że działanie platformy jest bardziej spójne: ConcurrentModificationException.

zachowanie podczas wczytywania zajęć,

Android 8.0 (poziom interfejsu API 26) sprawdza, czy ładowarki klas nie naruszają założeń środowiska uruchomieniowego podczas wczytywania nowych klas. Te kontrole są wykonywane niezależnie od tego, czy klasa jest wywoływana z Java (z forName()), kodu bajtowego Dalvik czy JNI. Platforma nie przechwytuje bezpośrednich wywołań z Java do metody loadClass() ani nie sprawdza wyników takich wywołań. Takie działanie nie powinno wpływać na działanie dobrze zachowujących się ładowaczy klas.

Platforma sprawdza, czy deskryptor klasy zwracany przez moduł ładowania klas pasuje do oczekiwanego deskryptora. Jeśli zwrócony deskryptor nie jest zgodny, platforma zgłasza błąd NoClassDefFoundError, a w wyjątku zapisuje szczegółowy komunikat informujący o rozbieżnościach.

Platforma sprawdza również, czy deskryptory żądanych klas są prawidłowe. Ta weryfikacja wykrywa wywołania JNI, które pośrednio wczytują klasy takie jak GetFieldID(), przekazując nieprawidłowe deskryptory do tych klas. Na przykład pole z podpisem java/lang/String nie zostało znalezione, ponieważ podpis jest nieprawidłowy. Powinno być Ljava/lang/String;.

Jest to inne niż wywołanie JNI do funkcji FindClass(), gdzie java/lang/String jest prawidłową pełną nazwą.

Android 8.0 (poziom interfejsu API 26) nie pozwala na definiowanie klas przez wiele modułów ładowania klas przy użyciu tego samego obiektu DexFile. Podczas próby wykonania tej operacji środowisko uruchomieniowe Androida InternalErrorwyświetla błąd z komunikatem „Próba zarejestrowania pliku dex <filename> z wieloma ładowarkami klas”.

Interfejs DexFile API został wycofany. Zdecydowanie zalecamy korzystanie z jednego z modułów ładowania klas platformy, w tym PathClassLoader lub BaseDexClassLoader.

Uwaga: możesz utworzyć większą liczbę ładowarek klas, które odwołują się do tego samego kontenera pliku APK lub JAR w systemie plików. Zazwyczaj nie powoduje to dużego obciążenia pamięci. Jeśli pliki DEX w kontenerze są przechowywane zamiast skompresowane, platforma może wykonać na nich operację mmap, zamiast wyodrębniać je bezpośrednio. Jeśli jednak platforma musi wyodrębnić plik DEX z kontenera, odwoływanie się do tego pliku w ten sposób może zużywać dużo pamięci.

W Androidzie wszystkie ładowarki klas są uważane za zdolne do działania równoległego. Gdy kilka wątków rywalizuje o załadowanie tego samego zbioru za pomocą tego samego ładowarki klas, wygrywa pierwszy wątek, który ukończył operację, a jego wynik jest używany przez pozostałe wątki. Takie zachowanie występuje niezależnie od tego, czy ładownik klasy zwrócił tę samą klasę, inną klasę czy wyjątek. Platforma dyskretnie ignoruje takie wyjątki.

Uwaga: w wersjach platformy starszych niż Android 8.0 (poziom interfejsu API 26) naruszenie tych założeń może spowodować wielokrotne zdefiniowanie tej samej klasy, uszkodzenie stosu z powodu pomylenia klas i innych niepożądanych efektów.