Zmiany w działaniu Androida 8.0

Oprócz nowych funkcji i możliwości Android 8.0 (poziom interfejsu API 26) wprowadza różne zmiany w działaniu systemu i interfejsów API. W tym dokumencie opisujemy najważniejsze zmiany, które musisz zrozumieć i uwzględnić w swoich aplikacjach.

Większość z tych zmian dotyczy wszystkich aplikacji, niezależnie od wersji Androida, na którą są kierowane. Kilka zmian dotyczy jednak tylko aplikacji kierowanych na Androida 8.0. Aby była bardziej przejrzysta, podzieliliśmy tę stronę na 2 sekcje: Zmiany we wszystkich aplikacjach i Zmiany w aplikacjach kierowanych na Androida 8.0.

Zmiany we wszystkich aplikacjach

Te zmiany w działaniu dotyczą wszystkich aplikacji działających na platformie Androida 8.0 (poziom interfejsu API 26) niezależnie od docelowego poziomu interfejsu API. Wszyscy deweloperzy powinni zapoznać się z tymi zmianami i w stosownych przypadkach zmodyfikować swoje aplikacje tak, aby obsługiwały je prawidłowo.

Limity wykonywania w tle

Jedną ze zmian wprowadzonych przez Androida w wersji 8.0 (poziom interfejsu API 26) jest skrócenie czasu pracy na baterii – gdy aplikacja znajdzie się w pamięci podręcznej i nie będzie żadnych aktywnych komponentów, system uwalnia wszystkie blokady wybudzenia, które obsługuje aplikacja.

Ponadto, aby poprawić wydajność urządzenia, system ogranicza niektóre działania aplikacji, które nie działają na pierwszym planie. Więcej szczegółów:

  • Aplikacje działające w tle podlegają teraz ograniczeniom dotyczącym swobodnego dostępu do usług w tle.
  • Aplikacje nie mogą używać plików manifestu do rejestrowania większości komunikatów niejawnych (czyli takich, które nie są kierowane bezpośrednio na aplikację).

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

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

  • Metoda startService() zwraca teraz IllegalStateException, jeśli aplikacja kierowana na Androida 8.0 próbuje użyć tej metody w sytuacji, gdy nie można tworzyć usług w tle.
  • Nowa metoda Context.startForegroundService() uruchamia usługę na pierwszym planie. System pozwala aplikacjom na wywoływanie funkcji Context.startForegroundService() nawet wtedy, gdy działa w tle. Aplikacja musi jednak wywołać metodę startForeground() tej usługi w ciągu 5 sekund po jej utworzeniu.

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

Limity lokalizacji w tle Androida

Aby oszczędzać baterię, wygodę użytkowników i kondycję systemu, aplikacje działające w tle rzadziej otrzymują aktualizacje lokalizacji na urządzeniach z Androidem 8.0. Ta zmiana w działaniu wpływa na wszystkie aplikacje, które pobierają 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 będzie działać zgodnie z oczekiwaniami, wykonaj te czynności:

  • Sprawdź logikę aplikacji i upewnij się, że używasz najnowszych interfejsów API lokalizacji.
  • Sprawdź w każdym przypadku użycia, czy aplikacja działa zgodnie z oczekiwaniami.
  • Skorzystaj z dostawcy uśrednionej lokalizacji (FLP) lub geofencingu, aby obsługiwać przypadki użycia, które zależą od bieżącej lokalizacji użytkownika.

Więcej informacji o tych zmianach znajdziesz w artykule Limity lokalizacji w tle.

Skróty do aplikacji

W Androidzie 8.0 (poziom interfejsu API 26) wprowadzono te zmiany w skrótach aplikacji:

  • Transmisja com.android.launcher.action.INSTALL_SHORTCUT nie ma już żadnego wpływu na Twoją aplikację, ponieważ jest teraz prywatna i niejawna. Zamiast tego utwórz skrót do aplikacji przy użyciu metody requestPinShortcut() z klasy ShortcutManager.
  • Intencja ACTION_CREATE_SHORTCUT może teraz tworzyć skróty do aplikacji, którymi zarządzasz za pomocą klasy ShortcutManager. Ten intencja może też utworzyć starsze skróty do Menu z aplikacjami, które nie wchodzą w interakcje z funkcją ShortcutManager. Wcześniej ta intencja mogła tworzyć tylko starsze skróty do menu z aplikacjami.
  • Skróty utworzone za pomocą funkcji requestPinShortcut() i skróty utworzone w działaniu, które obsługuje intencję ACTION_CREATE_SHORTCUT, są teraz w pełni funkcjonalnymi skrótami do aplikacji. W rezultacie aplikacje mogą teraz aktualizować je za pomocą metod w ShortcutManager.
  • Starsze skróty zachowują swoje funkcje z poprzednich wersji Androida, ale musisz ręcznie przekonwertować je na skróty do aplikacji.

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

Język i internacjonalizacja

W Androidzie 7.0 (poziom interfejsu API 24) wprowadzono koncepcję określania domyślnego języka kategorii, jednak niektóre interfejsy API w dalszym ciągu korzystały z ogólnej metody Locale.getDefault() bez argumentów, gdy zamiast tego należało użyć domyślnego języka kategorii DISPLAY. W Androidzie 8.0 (poziom interfejsu API 26) poniższe metody zamiast Locale.getDefault() używają teraz Locale.getDefault(Category.DISPLAY):

Locale.getDisplayScript(Locale) zwraca też wartość Locale.getDefault(), gdy wartość displayScript określona dla argumentu Locale jest niedostępna.

Dodatkowe zmiany związane z ustawieniami regionalnymi i międzynarodową:

  • Wywołanie Currency.getDisplayName(null) powoduje zgłoszenie błędu NullPointerException, który odpowiada udokumentowanemu zachowaniu.
  • Zmieniła się analiza nazwy strefy czasowej. Wcześniej urządzenia z Androidem korzystały z wartości zegara systemowej próbkowanej podczas uruchamiania, aby zapisywać w pamięci podręcznej nazwy stref czasowych używane do analizowania dat i godzin. W rezultacie na analizowanie może to negatywnie wpłynąć, jeśli zegar systemowy był nieprawidłowy podczas uruchamiania lub w innych, rzadszych przypadkach.

    Obecnie podczas analizy nazw stref czasowych logika analizy często używa ICU i bieżącej wartości zegara systemowego. Ta zmiana daje dokładniejsze wyniki, które mogą różnić się od 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_WINDOW i używa jednego z tych typów okien do wyświetlania okien alertów nad innymi aplikacjami i oknami systemowymi:

...te okna są zawsze wyświetlane pod oknami typu TYPE_APPLICATION_OVERLAY. Jeśli aplikacja jest kierowana na Androida 8.0 (poziom interfejsu API 26), okna alertów wyświetlają się za pomocą typu okna TYPE_APPLICATION_OVERLAY.

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

Wprowadzanie i nawigacja

Wraz z pojawieniem się aplikacji na Androida na ChromeOS i innych dużych urządzeniach, takich jak tablety, następuje ponowne wzmożone korzystanie z nawigacji za pomocą klawiatury w aplikacjach na Androida. W Androidzie 8.0 (poziom interfejsu API 26) to udoskonaliliśmy używanie klawiatury jako urządzenia wejściowego nawigacji, co pozwoliło uzyskać bardziej niezawodny i przewidywalny model nawigacji przy użyciu strzałek i kart.

Wprowadziliśmy następujące zmiany w zachowaniu skupienia elementów:

  • Jeśli nie masz zdefiniowanych żadnych kolorów stanu zaznaczenia dla obiektu View (jego pierwszego planu lub tła), platforma ustawia teraz domyślny kolor zaznaczenia elementu View. To wyróżnienie to fali, które można rysować, związane z motywem aktywności.

    Jeśli nie chcesz, aby obiekt View używał tego domyślnego zaznaczenia po zaznaczeniu, ustaw atrybut android:defaultFocusHighlightEnabled na false w pliku XML układu zawierającym View lub przekaż false do setDefaultFocusHighlightEnabled() w logice interfejsu aplikacji.

  • Aby sprawdzić, jak wprowadzanie tekstu z klawiatury wpływa na zaznaczenie elementów interfejsu, możesz włączyć opcję programisty Rysunek > Pokaż granice układu. W Androidzie 8.0 ta opcja powoduje wyświetlenie ikony „X” nad elementem, który jest obecnie zaznaczony.

Poza tym wszystkie elementy paska narzędzi w Androidzie 8.0 są automatycznie klastrami nawigacji z klawiatury, co ułatwia użytkownikom poruszanie się po każdym pasku narzędzi i poruszanie się po nim.

Więcej informacji o ulepszeniu obsługi nawigacji za pomocą klawiatury w aplikacji znajdziesz w przewodniku Obsługiwanie nawigacji za pomocą klawiatury.

Autouzupełnianie formularzy internetowych

Gdy funkcja autouzupełniania na Androidzie ma wbudowaną obsługę autouzupełniania, te metody związane z obiektami WebView uległy zmianie w aplikacjach zainstalowanych na urządzeniach z Androidem 8.0 (poziom API 26):

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

Ułatwienia dostępu

W Androidzie 8.0 (poziom interfejsu API 26) wprowadziliśmy te zmiany w ułatwieniach dostępu:

  • Platforma ułatwień dostępu konwertuje teraz wszystkie gesty dwukrotnego kliknięcia na działania ACTION_CLICK. Ta zmiana sprawi, że TalkBack będzie działać bardziej jak inne usługi ułatwień dostępu.

    Jeśli obiekty View Twojej aplikacji korzystają z niestandardowej obsługi dotyku, sprawdź, czy nadal działają z TalkBack. Może być konieczne zarejestrowanie modułu obsługi kliknięć, którego używają obiekty View. Jeśli TalkBack nadal nie rozpoznaje gestów wykonywanych na tych View obiektach, zastąp performAccessibilityAction().

  • Usługi ułatwień dostępu rozpoznają teraz wszystkie instancje ClickableSpan w obiektach TextView aplikacji.

Aby dowiedzieć się, jak zwiększyć dostępność aplikacji, przeczytaj sekcję Ułatwienia dostępu.

Sieć i połączenia HTTP(S)

Android 8.0 (poziom interfejsu API 26) obejmuje te zmiany w sposobie działania 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 po nazwie hosta lub urzędu ukośnik. Na przykład przelicza http://example.com na http://example.com/.
  • Niestandardowy selektor serwera proxy ustawiony za pomocą ProxySelector.setDefault() jest kierowany tylko na adres (schemat, host i port) żądanego adresu URL. W związku z tym wybór serwera proxy może się opierać tylko na tych wartościach. Adres URL przekazany do niestandardowego selektora 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 pozwalające na akceptowanie pustych etykiet w nazwach hostów, co uniemożliwiało korzystanie z identyfikatorów URI. To obejście miało na celu zapewnienie zgodności ze starszymi wersjami biblioteki libcore. Deweloperzy używający interfejsu API w nieprawidłowy sposób zobaczą komunikat ADB: „Identyfikator URI example.com ma puste etykiety w nazwie hosta. Ten format jest zniekształcony i nie będzie akceptowany w kolejnych wersjach Androida”. Android 8.0 usuwa to obejście; w przypadku nieprawidłowych identyfikatorów URI system zwraca wartość null.

  • Implementacja HttpsURLConnection w Androidzie 8.0 nie obsługuje zastępczej wersji protokołu TLS/SSL.
  • Obsługa tunelowania połączeń HTTP(S) zmieniła się w następujący sposób:
    • Gdy tunelujesz połączenie HTTPS przez połączenie, system prawidłowo umieszcza numer portu (:443) w wierszu Host podczas wysyłania tych informacji do serwera pośredniego. Wcześniej numer portu występował tylko na linii CONNECT.
    • System nie wysyła już nagłówków klienta użytkownika ani autoryzacji serwera proxy z tunelu żądania do serwera proxy.

      Podczas konfigurowania tunelu system nie wysyła już nagłówka autoryzacji serwera proxy przez tunel HTTPConnection do serwera proxy. Zamiast tego system generuje nagłówek autoryzacji serwera proxy i wysyła go do serwera proxy, gdy serwer proxy wysyła kod 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 dla tego żądania biblioteka generuje nagłówek klienta użytkownika.

  • Metoda send(java.net.DatagramPacket) zwraca wyjątek SocketException, jeśli wcześniej wykonywana metoda connect() nie powiodła się.
    • DatagramSocket.connect() ustawia wyjątek pendingSocketException w przypadku wystąpienia błędu wewnętrznego. Przed Androidem 8.0 kolejne wywołanie recv() zwróciło wyjątek SocketException, mimo że wywołanie send() mogłoby się udać. Aby zachować spójność, oba wywołania zgłaszają teraz wyjątek SocketException.
  • InetAddress.isReachable() próbuje ICMP, zanim przełączy się na protokół TCP Echo.
    • Niektóre hosty blokujące port 7 (Echo TCP), takie jak google.com, mogą być teraz osiągalne, jeśli akceptują protokół Echo ICMP.
    • W przypadku naprawdę nieosiągalnych hostów ta zmiana oznacza, że czas potrzebny na zwrócenie wywołania jest 2 razy dłuższy.

Bluetooth

Android 8.0 (poziom interfejsu API 26) wprowadza te zmiany długości danych pobieranych przez metodę ScanRecord.getBytes():

  • Metoda getBytes() nie przyjmuje żadnych założeń dotyczących liczby odebranych bajtów. Dlatego aplikacje nie powinny wykorzystywać żadnej minimalnej ani maksymalnej liczby zwracanych bajtów. Zamiast tego powinny oszacować długość wynikowej tablicy.
  • Urządzenia zgodne z Bluetoothem 5 mogą zwracać dane o długości przekraczającej poprzednie maksimum wynoszące około 60 bajtów.
  • Jeśli urządzenie zdalne nie zwraca odpowiedzi skanowania, może też zostać zwróconych mniej niż 60 bajtów.

Płynna łączność

Android 8.0 (poziom interfejsu API 26) zawiera szereg udoskonaleń w ustawieniach Wi-Fi, aby ułatwić wybór sieci Wi-Fi, która zapewni użytkownikom najlepsze wrażenia. Konkretne zmiany:

  • Większa stabilność i niezawodność.
  • Bardziej intuicyjny interfejs.
  • Jedno, skonsolidowane menu ustawień Wi-Fi.
  • Na zgodnych urządzeniach automatyczne aktywowanie Wi-Fi, gdy w pobliżu znajduje się zapisana sieć o wysokiej jakości.

Zabezpieczenia

W Androidzie 8.0 wprowadzono te zmiany związane z bezpieczeństwem:

  • Platforma nie obsługuje już SSLv3.
  • W przypadku nawiązywania połączenia HTTPS z serwerem, który nieprawidłowo implementuje negocjowanie wersji protokołu TLS, HttpsURLConnection nie próbuje obejść tego problemu przez powrót do wcześniejszych wersji protokołu TLS i ponawianie próby.
  • Android 8.0 (poziom interfejsu API 26) stosuje filtr Secure Computing (SECCOMP) do wszystkich aplikacji. Lista dozwolonych wywołań Syscall jest ograniczona do tych, które są udostępniane metodą bioniczną. Chociaż dostępnych jest kilka innych komunikatów syscall na potrzeby zgodności wstecznej, odradzamy ich korzystanie.
  • Obiekty WebView Twojej aplikacji działają teraz w trybie wielu procesów. Aby zwiększyć bezpieczeństwo, treści internetowe są obsługiwane w innym, odizolowanym procesie od procesu aplikacji, który zawiera.
  • Nie możesz już zakładać, że pliki APK znajdują się w katalogach, których nazwy kończą się na -1 lub -2. Aby pobrać katalog, aplikacje powinny używać polecenia sourceDir i nie mogą korzystać bezpośrednio z formatu katalogu.
  • Informacje o rozszerzeniach zabezpieczeń związanych z korzystaniem z bibliotek natywnych znajdziesz w artykule Biblioteki natywne.

Ponadto w Androidzie 8.0 (poziom interfejsu API 26) wprowadziliśmy te zmiany związane z instalowaniem nieznanych aplikacji z nieznanych źródeł:

Więcej informacji o instalowaniu nieznanych aplikacji znajdziesz w przewodniku Uprawnienia nieznanych instalacji aplikacji.

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

prywatność

Android 8.0 (poziom interfejsu API 26) wprowadza na platformie podane niżej zmiany związane z ochroną prywatności.

  • Platforma obsługuje teraz identyfikatory w inny sposób.
    • 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 następnie ponownie zainstalowana po tej aktualizacji. Aby zachować wartości po odinstalowaniu OTA, deweloperzy mogą powiązać stare i nowe wartości za pomocą zapasowej wartości klucza/wartości.
    • W przypadku aplikacji zainstalowanych na urządzeniach z Androidem 8.0 wartość ANDROID_ID jest teraz ograniczona do każdego klucza podpisywania aplikacji i użytkownika. Wartość ANDROID_ID jest unikalna dla każdej kombinacji klucza podpisywania aplikacji, użytkownika i urządzenia. W związku z tym aplikacje z różnymi kluczami podpisywania działające na tym samym urządzeniu nie będą już widzieć tego samego identyfikatora Androida (nawet tego samego użytkownika).
    • Wartość ANDROID_ID nie zmienia się po odinstalowaniu ani ponownym zainstalowaniu pakietu, o ile klucz podpisywania jest taki sam (a aplikacja nie została zainstalowana przed aktualizacją OTA do Androida w wersji 8.0).
    • Wartość ANDROID_ID nie zmienia się nawet wtedy, gdy aktualizacja systemu powoduje zmianę klucza podpisywania pakietu.
    • W przypadku urządzeń, które są dostarczane z Usługami Google Play i identyfikatorem wyświetlania reklam, musisz użyć 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 świadczona przez Usługi Google Play.

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

  • Zapytanie dotyczące właściwości systemowej net.hostname da wynik o wartości null.

Logowanie niewykrytych wyjątków

Jeśli aplikacja zainstaluje Thread.UncaughtExceptionHandler, który nie wywołuje domyślnej wartości Thread.UncaughtExceptionHandler, system nie zakończy jej działania w przypadku wystąpienia nieobsłużonego wyjątku. Począwszy od Androida 8.0 (poziom interfejsu API 26) system w tej sytuacji rejestruje zrzut stosu wyjątków. We wcześniejszych wersjach platformy system nie rejestrował zrzutu stosu wyjątków.

Zalecamy, aby niestandardowe implementacje Thread.UncaughtExceptionHandler zawsze wywoływały domyślny moduł obsługi.Zmiana wersji Androida nie ma wpływu na aplikacje, które są zgodne z tą rekomendacją.

Zmiana podpisu findViewById()

Wszystkie wystąpienia metody findViewById() zwracają teraz wartość <T extends View> T zamiast View. Ta zmiana ma następujące konsekwencje:

  • Może to spowodować, że istniejący kod będzie miał teraz niejednoznaczny typ zwracanego kodu, np. jeśli zarówno someMethod(View), jak i someMethod(TextView) pobiera wynik wywołania findViewById().
  • W przypadku języka źródłowego Java 8 wymaga to jawnego rzutu na View, gdy zwracany typ nie jest ograniczony (np. assertNotNull(findViewById(...)).someViewMethod())).
  • Zastąpienia nieostatecznej metody findViewById() (np. Activity.findViewById()) wymagają zmiany typu zwracanego kodu.

Zmiana statystyk użytkowania dostawców kontaktów

W poprzednich wersjach Androida komponent Dostawca kontaktów umożliwia deweloperom pobieranie danych o korzystaniu z każdego kontaktu. Te dane o korzystaniu ujawniają informacje dla każdego adresu e-mail i każdego numeru telefonu powiązanego z kontaktem, w tym liczbę i datę ostatniego kontaktu z kontaktem. Aplikacje, które proszą o uprawnienie READ_CONTACTS, mogą odczytywać te dane.

Aplikacje nadal będą mogły odczytać te dane, jeśli poproszą o uprawnienie READ_CONTACTS. W Androidzie 8.0 (poziom interfejsu API 26) i nowszych zapytania o dane o korzystaniu zwracają wartości przybliżone, a nie dokładne. System Android zapisuje wewnętrznie dokładne wartości, więc ta zmiana nie ma wpływu na interfejs API autouzupełniania.

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

Obsługa kolekcji

AbstractCollection.removeAll() i AbstractCollection.retainAll() teraz zawsze zgłaszają NullPointerException; wcześniej NullPointerException nie był wywoływany, gdy kolekcja była pusta. Ta zmiana sprawi, że zachowanie będzie spójne z dokumentacją.

Android Enterprise

Android 8.0 (poziom interfejsu API 26) zmienia działanie niektórych interfejsów API i funkcji przeznaczonych dla aplikacji biznesowych, w tym kontrolerów zasad urządzeń (DPC). Zmiany te obejmują:

  • Nowe zachowania ułatwiające aplikacjom obsługę profili służbowych na w pełni zarządzanych urządzeniach.
  • Zmiany w obsłudze aktualizacji systemu, weryfikacji aplikacji i uwierzytelnianiu, które mają poprawić integralność urządzenia i systemu.
  • Ulepszenia obsługi administracyjnej użytkowników, powiadomień, ekranu Ostatnie i stałej sieci VPN.

Aby poznać wszystkie zmiany wprowadzone w Androidzie 8.0 (poziom interfejsu API 26) i dowiedzieć się, jak mogą one wpłynąć na Twoją aplikację, przeczytaj artykuł Android w firmach.

Aplikacje na Androida 8.0

Te zmiany w działaniu dotyczą tylko aplikacji kierowanych na Androida 8.0 (poziom API 26) lub nowszy. Aplikacje, które kompilują się z Androidem 8.0 lub mają system targetSdkVersion na Androidzie 8.0 lub nowszym, w stosownych przypadkach muszą zmodyfikować swoje aplikacje, aby prawidłowo obsługiwały te zachowania.

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.

Gdy używasz okna TYPE_APPLICATION_OVERLAY do wyświetlania okien alertów dla aplikacji, pamiętaj o tych cechach nowego typu okna:

  • Okna alertów aplikacji są zawsze wyświetlane pod krytycznymi oknami systemowymi, takimi jak pasek stanu czy edytory IME.
  • Aby poprawić prezentację ekranu, system może przenosić okna typu TYPE_APPLICATION_OVERLAY lub zmieniać ich rozmiar.
  • Po otwarciu obszaru powiadomień użytkownicy mogą uzyskać dostęp do ustawień, które uniemożliwiają aplikacji wyświetlanie okien alertów wyświetlanych jako okno typu TYPE_APPLICATION_OVERLAY.

Powiadomienia o zmianie treści

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

Te interfejsy API wymagają teraz zdefiniowania prawidłowego atrybutu ContentProvider dla urzędu we wszystkich identyfikatorach URI. Zdefiniowanie prawidłowego elementu ContentProvider z odpowiednimi uprawnieniami pomoże chronić aplikację przed zmianą treści ze złośliwych aplikacji oraz zapobiegnie wyciekowi potencjalnie prywatnych danych do szkodliwych aplikacji.

Wyświetl zaznaczenie

Klikalne obiekty View są teraz domyślnie dostępne także do zaznaczenia. Jeśli chcesz, aby obiekt View był klikalny, ale nie można go zaznaczyć, ustaw atrybut android:focusable na false w pliku XML układu zawierającym View albo przekaż false do setFocusable() w logice interfejsu aplikacji.

Dopasowywanie klienta użytkownika podczas wykrywania przeglądarki

Android 8.0 (poziom interfejsu API 26) i nowsze zawierają ciąg identyfikatora kompilacji OPR. Niektóre dopasowania wzorców mogą powodować błędy w identyfikowaniu przeglądarki innej niż Opera jako przeglądarki Opera. Przykład takiego dopasowania:

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 błędnego rozpoznania, jako dopasowania do wzorca dla przeglądarki Opera użyj ciągu innego niż OPR.

Zabezpieczenia

Te zmiany mają wpływ na zabezpieczenia w Androidzie 8.0 (poziom API 26):

  • Jeśli konfiguracja zabezpieczeń sieci Twojej aplikacji wyłączy obsługę ruchu nieszyfrowanego, obiekty WebView aplikacji nie będą mieć dostępu do witryn przez HTTP. Każdy obiekt WebView musi zamiast tego używać protokołu HTTPS.
  • Ustawienie systemowe Zezwalaj na nieznane źródła zostało usunięte. Zamiast niego uprawnienie Zainstaluj nieznane aplikacje 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 uprawnień do instalacji nieznanych aplikacji.

Dodatkowe wskazówki dotyczące zwiększania bezpieczeństwa aplikacji znajdziesz w artykule Bezpieczeństwo 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 właściciel konta jest właścicielem konta lub użytkownik przyznał taki dostęp. Uprawnienie GET_ACCOUNTS nie jest już wystarczające. Aby uzyskać dostęp do konta, aplikacje powinny używać metody AccountManager.newChooseAccountIntent() lub metody związanej z uwierzytelnianiem. Po uzyskaniu dostępu do kont aplikacja może wywołać metodę AccountManager.getAccounts(), aby uzyskać do nich dostęp.

Android 8.0 zostanie wycofany LOGIN_ACCOUNTS_CHANGED_ACTION. Aplikacje powinny używać metody addOnAccountsUpdatedListener() do pobierania aktualnych informacji o kontach w czasie działania.

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

prywatność

Opisane poniżej zmiany dotyczą prywatności w Androidzie 8.0 (poziom API 26).

  • Właściwości systemowe net.dns1, net.dns2, net.dns3 i net.dns4 nie są już dostępne. Jest to zmiana, która zwiększa prywatność 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 na urządzeniach z Androidem 5.0 (poziom interfejsu API 21) i nowszymi.
  • Interfejs Build.SERIAL został wycofany. Aplikacje, które potrzebują dostępu do numeru seryjnego sprzętu, powinny używać nowej metody Build.getSerial(), która wymaga uprawnienia READ_PHONE_STATE.
  • Interfejs LauncherApps API nie zezwala już aplikacjom profilu służbowego na pobieranie informacji o profilu głównym. Gdy użytkownik korzysta z profilu służbowego, interfejs API LauncherApps działa tak, jakby żadne aplikacje nie były zainstalowane w innych profilach w tej samej grupie. Tak jak wcześniej próby uzyskania dostępu do niepowiązanych profili powoduje wystąpienie wyjątków SecurityException.

Uprawnienia

Starsze wersje Androida 8.0 (poziom interfejsu API 26): jeśli aplikacja prosiła o uprawnienia w czasie działania i zostały one przyznane, system nieprawidłowo przyznał aplikacji pozostałe uprawnienia, które należały do tej samej grupy uprawnień i które były zarejestrowane w pliku manifestu.

Naprawiliśmy ten błąd w aplikacjach kierowanych na Androida 8.0. Aplikacja otrzymuje tylko te uprawnienia, o które bezpośrednio prosi. Gdy jednak użytkownik przyzna aplikacji uprawnienia, wszystkie kolejne prośby o uprawnienia z tej grupy będą automatycznie przyznawane.

Załóżmy na przykład, że w pliku manifestu aplikacji są wymienione zarówno READ_EXTERNAL_STORAGE, jak i WRITE_EXTERNAL_STORAGE. Aplikacja prosi o READ_EXTERNAL_STORAGE, a użytkownik przyznaje jej uprawnienia. Jeśli aplikacja jest kierowana na interfejs API na poziomie 25 lub niższym, system przyznaje jednocześnie uprawnienia WRITE_EXTERNAL_STORAGE, ponieważ należy ona do tej samej grupy uprawnień STORAGE i jest zarejestrowana w pliku manifestu. Jeśli aplikacja jest kierowana na Androida 8.0 (poziom interfejsu API 26), system przyznaje w tym momencie tylko READ_EXTERNAL_STORAGE. Jeśli jednak aplikacja później zażąda uprawnienia WRITE_EXTERNAL_STORAGE, system natychmiast przyzna te uprawnienia, nie pytając użytkownika o zgodę.

Multimedia

  • Platforma może sama wykonywać automatyczne wyciszanie dźwięku. W tym przypadku, gdy inna aplikacja wysyła żądanie skupiające się na AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, zaznaczona aplikacja zmniejsza głośność, ale zwykle nie otrzymuje wywołania zwrotnego onAudioFocusChange() i nie traci zaznaczenia audio. Dostępne są nowe interfejsy API, które zastępują to zachowanie w przypadku aplikacji, które muszą się wstrzymywać, a nie wyciszać.
  • Gdy użytkownik odbiera połączenie telefoniczne, na czas połączenia aktywne strumienie multimediów są wyciszone.
  • Do opisania przypadku użycia odtwarzania dźwięku wszystkie interfejsy API związane z dźwiękiem powinny używać elementu 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 do wycofanego konstruktora AudioTrack), ale system rejestruje to jako błąd.
  • Gdy używasz obiektu AudioTrack, a aplikacja żąda odpowiednio dużego bufora dźwięku, platforma spróbuje wykorzystać dane wyjściowe bufora głębokiego (jeśli będzie dostępne).
  • W Androidzie 8.0 (poziom interfejsu API 26) obsługa zdarzeń przycisków multimediów wygląda inaczej:
    1. Sposób obsługi przycisków multimediów w działaniu w interfejsie nie uległ zmianie: działania na pierwszym planie nadal mają wyższy priorytet przy obsłudze zdarzeń przycisków multimediów.
    2. Jeśli aktywność na pierwszym planie nie obsługuje zdarzenia przycisku multimediów, system przekierowuje to zdarzenie do aplikacji, która ostatnio odtworzyła dźwięk lokalnie. Stan aktywności, flagi i stan odtwarzania sesji multimediów nie są brane pod uwagę przy określaniu, która aplikacja odbiera zdarzenia przycisku multimediów.
    3. Jeśli sesja multimediów w aplikacji została zwolniona, system wysyła zdarzenie przycisku multimediów do identyfikatora MediaButtonReceiver aplikacji (jeśli go ma).
    4. W pozostałych przypadkach system odrzuca zdarzenie przycisku multimediów.

Biblioteki natywne

W przypadku aplikacji kierowanych na Androida 8.0 (poziom interfejsu API 26) biblioteki natywne nie są dłużej ładowane, jeśli zawierają segment wczytywania, który można jednocześnie zapisać i wykonać. 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 o segmentach dostępnych do zapisu i wykonywalnych.

Zmiany w tagach łączących są powiązane z poziomem interfejsu API, na który kierowana jest aplikacja. W przypadku zmiany tagu łączącego na docelowym poziomie interfejsu API aplikacja nie może wczytać biblioteki. Jeśli kierujesz reklamy na poziom API niższy niż ten, na którym następuje zmiana tagu łączącego, logcat wyświetli ostrzeżenie.

Obsługa kolekcji

W Androidzie 8.0 (poziom interfejsu API 26) Collections.sort() jest zaimplementowany na platformie List.sort(). Odwrotna sytuacja miała miejsce w Androidzie 7.x (poziomy interfejsu API 24 i 25): domyślna implementacja List.sort() o nazwie Collections.sort().

Ta zmiana pozwala usłudze Collections.sort() na korzystanie ze zoptymalizowanych implementacji List.sort(), ale podlega tym ograniczeniom:

  • Implementacje funkcji List.sort() nie mogą wywoływać metody Collections.sort(), ponieważ spowodowałoby to przepełnienie stosu z powodu nieskończonej rekurencji. Jeśli chcesz korzystać z domyślnego działania w implementacji List, unikaj zastępowania metody sort().

    Jeśli klasa nadrzędna implementuje interfejs sort() w nieprawidłowy sposób, zwykle można zastąpić właściwość List.sort() implementacją utworzoną na podstawie komponentów List.toArray(), Arrays.sort() i 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() za pomocą implementacji, która przekazuje dostęp do różnych implementacji domyślnych 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 wykonujesz tę drugą czynność tylko, ponieważ chcesz, aby metoda sort() była dostępna na wszystkich poziomach interfejsu API, rozważ nadanie jej unikalnej nazwy, na przykład sortCompat(), zamiast zastępowania sort().

  • Pole Collections.sort() jest teraz liczone jako modyfikacja strukturalna w implementacjach list, które wywołują metodę sort(). Na przykład w wersjach platformy starszych niż 8.0 (poziom interfejsu API 26) iterowanie za pomocą obiektu ArrayList i wywoływanie na nim obiektu sort() w trakcie iteracji skutkowało wygenerowaniem ConcurrentModificationException, jeśli sortowanie zostało wykonane przez wywołanie List.sort(). Usługa Collections.sort() nie zgłosiła wyjątku.

    Ta zmiana sprawi, że zachowanie platformy będzie bardziej spójne: każde z tych rozwiązań spowoduje teraz wyświetlenie ConcurrentModificationException.

Sposób ładowania zajęć

Android 8.0 (poziom interfejsu API 26) sprawdza, czy podczas wczytywania nowych klas mechanizmy ładowania klas nie łamią założeń dotyczących środowiska wykonawczego. Te kontrole są wykonywane, czy do klasy odwołują się odwołania do klasy Java (z forName()), kodu bajtowego Dalvik lub JNI. Platforma nie przechwytuje bezpośrednich wywołań Javy do metody loadClass() ani nie sprawdza wyników takich wywołań. To zachowanie nie powinno wpływać na działanie prawidłowo wczytywanych klas.

Platforma sprawdza, czy deskryptor klasy zwracany przez mechanizm ładowania klas odpowiada oczekiwanemu deskryptorowi. Jeśli zwrócony deskryptor nie pasuje, platforma zgłasza błąd NoClassDefFoundError i zapisuje w tym wyjątku szczegółowy komunikat z informacją o rozbieżnościach.

Platforma sprawdza też, czy deskryptory żądanych klas są prawidłowe. W ten sposób wykrywane są wywołania JNI, które pośrednio wczytują klasy takie jak GetFieldID(), przekazując do nich nieprawidłowe deskryptory. Na przykład nie znaleziono pola z podpisem java/lang/String, ponieważ ten podpis jest nieprawidłowy – powinien mieć wartość Ljava/lang/String;.

Różni się ona od wywołania JNI dla FindClass(), gdzie java/lang/String jest prawidłową pełną i jednoznaczną nazwą.

Android 8.0 (poziom interfejsu API 26) nie obsługuje sytuacji, gdy wiele modułów ładowania klas próbuje definiować klasy przy użyciu tego samego obiektu DexFile. Próba wykonania tej czynności powoduje, że środowisko wykonawcze Androida zgłasza błąd InternalError z komunikatem „Spróbuj zarejestrować plik .dex <filename> z wieloma klasami wczytywania”.

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ć wiele modułów ładowania klas, które odwołują się do tego samego kontenera plików APK lub JAR z systemu plików. Zwykle nie powoduje to dużego obciążenia pamięci: jeśli pliki DEX w kontenerze są przechowywane, a nie skompresowane, platforma może wykonać na nich operację mmap, zamiast je bezpośrednio wyodrębnić. Jeśli jednak platforma musi wyodrębnić plik DEX z kontenera, podawanie pliku DEX w ten sposób może zużywać dużą ilość pamięci.

W Androidzie wszystkie moduły ładowania klas są uznawane za działające równolegle. Gdy wiele wątków ściga się o wczytanie tej samej klasy przy użyciu tego samego modułu ładowania klas, wygrywa pierwszy wątek, który zakończy operację, a wynik jest używany w pozostałych wątkach. Dzieje się tak niezależnie od tego, czy mechanizm ładowania klas zwrócił tę samą klasę, inną klasę, czy zgłosił 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 doprowadzić do wielokrotnego zdefiniowania tej samej klasy, do uszkodzenia sterty z powodu pomylenia klas i innych niepożądanych efektów.