Zmiany w działaniu Androida 7.0

Oprócz nowych funkcji i możliwości Android 7.0 wprowadza szereg zmian w działaniu systemów i interfejsów API. W tym dokumencie opisujemy najważniejsze zmiany, które musisz zrozumieć i uwzględnić w swoich aplikacjach.

Jeśli masz już opublikowaną aplikację na Androida, pamiętaj, że te zmiany na platformie mogą mieć wpływ na nią.

Bateria i pamięć

Android 7.0 zawiera zmiany w działaniu systemu, które mają na celu wydłużenie czasu pracy urządzeń na baterii i zmniejszenie wykorzystania pamięci RAM. Zmiany te mogą wpływać na dostęp aplikacji do zasobów systemowych oraz na sposób interakcji aplikacji z innymi aplikacjami poprzez określone intencje niejawne.

Uśpienie

Wprowadzona w Androidzie 6.0 (poziom interfejsu API 23) funkcja Doze skraca czas pracy na baterii, opóźniając działanie procesora i aktywności sieciowej, gdy użytkownik pozostawia urządzenie odłączone, nieruchome i przy wyłączonym ekranie. Android 7.0 wprowadza dalsze ulepszenia funkcji Uśpienie, stosując podzbiór procesorów i ograniczeń sieci, gdy użytkownik jest odłączony od zasilania, a urządzenie nie jest w kieszeni, ale nie zawsze jest w kieszeni.

Ilustracja pokazująca, jak Uśpienie stosuje pierwszy poziom ograniczeń aktywności systemu, aby wydłużyć czas pracy na baterii

Rysunek 1. Ilustracja pokazująca, jak Uśpienie stosuje pierwszy poziom ograniczeń aktywności systemu, aby wydłużyć czas pracy na baterii.

Gdy urządzenie jest zasilane z baterii, a jego ekran był wyłączony przez określony czas, przechodzi w tryb uśpienia i stosuje pierwszy podzbiór ograniczeń: wyłącza dostęp do sieci aplikacji oraz opóźnia zadania i synchronizację. Jeśli po uruchomieniu funkcji Uśpienie urządzenie pozostanie nieruchome przez pewien czas, system zastosuje pozostałe ograniczenia trybu uśpienia do alarmów PowerManager.WakeLock, AlarmManager, GPS-a i skanowań Wi-Fi. Niezależnie od tego, czy stosowane są niektóre czy wszystkie ograniczenia uśpienia, system wybudza urządzenie na krótkie okresy konserwacji, podczas których aplikacje mają dostęp do sieci i mogą wykonywać wszelkie odroczone zadania/synchronizacje.

Ilustracja pokazująca, jak Uśpienie stosuje drugi poziom ograniczeń aktywności systemu, gdy urządzenie przez określony czas jest nieaktywne

Rysunek 2. Ilustracja pokazująca, jak Uśpienie stosuje drugi poziom ograniczeń aktywności systemu, gdy urządzenie przez określony czas jest nieruchome.

Pamiętaj, że aktywowanie ekranu lub podłączenie urządzenia spowoduje zamknięcie funkcji Uśpienie i usunięcie tych ograniczeń przetwarzania. To dodatkowe zachowanie nie ma wpływu na rekomendacje ani sprawdzone metody dostosowywania aplikacji do poprzedniej wersji funkcji Uśpienie wprowadzonej w Androidzie 6.0 (poziom interfejsu API 23), co zostało omówione w artykule Optymalizowanie pod kątem funkcji uśpienia i czuwania aplikacji. Należy nadal stosować się do tych zaleceń, na przykład używać Komunikacji w chmurze Firebase (FCM) do wysyłania i odbierania wiadomości, oraz planować aktualizacje dostosowane do dodatkowego działania funkcji Uśpienie.

Projekt Svelte: optymalizacje tła

Android 7.0 usuwa 3 niejawne komunikaty, aby zoptymalizować wykorzystanie pamięci i zużycie energii. Ta zmiana jest konieczna, ponieważ niejawne transmisje często uruchamiają aplikacje, które zarejestrowały się, by nasłuchiwać ich w tle. Usunięcie tych komunikatów może znacznie poprawić wydajność urządzenia i poprawić wygodę użytkowników.

Na urządzeniach mobilnych często występują zmiany w połączeniach, np. podczas przełączania się między Wi-Fi a mobilną transmisją danych. Obecnie aplikacje mogą monitorować zmiany w połączeniach, rejestrując odbiornik niejawnej transmisji CONNECTIVITY_ACTION w swoim pliku manifestu. Ponieważ wiele aplikacji rejestruje się, by odbierać tę transmisję, 1 przełącznik sieci może spowodować, że wszystkie zostaną wybudzone i przetworzone jednocześnie.

Analogicznie w poprzednich wersjach Androida aplikacje mogły się rejestrować, aby otrzymywać niejawne komunikaty ACTION_NEW_PICTURE i ACTION_NEW_VIDEO z innych aplikacji, takich jak Aparat. Gdy użytkownik zrobi zdjęcie za pomocą aplikacji Aparat, aplikacje te wybudzają się i przetwarzają transmisję.

Aby rozwiązać te problemy, Android 7.0 stosuje te optymalizacje:

Jeśli Twoja aplikacja korzysta z któregokolwiek z tych intencji, musisz jak najszybciej usunąć od nich zależności, by umożliwić prawidłowe kierowanie na urządzenia z Androidem 7.0. Platforma Androida udostępnia kilka rozwiązań, które zmniejszą zapotrzebowanie na przesyłanie niejawne. Na przykład interfejs API JobScheduler zapewnia niezawodny mechanizm planowania operacji sieciowych po spełnieniu określonych warunków, takich jak połączenie z siecią bez pomiaru. Możesz nawet używać usługi JobScheduler, aby reagować na zmiany dotyczące dostawców treści.

Więcej informacji o optymalizacji w tle w Androidzie 7.0 (poziom interfejsu API 24) i dostosowywaniu aplikacji znajdziesz w artykule na temat optymalizacji w tle.

Zmiany uprawnień

Android 7.0 zawiera zmiany w uprawnieniach, które mogą mieć wpływ na Twoją aplikację.

Zmiany uprawnień systemu plików

Aby zwiększyć bezpieczeństwo prywatnych plików, dostęp do prywatnego katalogu aplikacji kierowanych na Androida 7.0 lub nowszego jest ograniczony (0700). To ustawienie zapobiega wyciekom metadanych prywatnych plików, takich jak ich rozmiar lub fakt istnienia. Ta zmiana uprawnień ma wiele skutków ubocznych:

Udostępnianie plików między aplikacjami

W przypadku aplikacji kierowanych na Androida 7.0 platforma Androida egzekwuje zasadę interfejsu API StrictMode, która zabrania ujawniania identyfikatorów URI file:// poza aplikacją. Jeśli intencja zawierająca identyfikator URI pliku opuści Twoją aplikację, aplikacja będzie miała wyjątek FileUriExposedException.

Aby udostępniać pliki między aplikacjami, należy wysłać identyfikator URI content:// i przyznać tymczasowe uprawnienia dostępu do identyfikatora URI. Najprostszym sposobem na przyznanie tego uprawnienia jest użycie klasy FileProvider. Więcej informacji o uprawnieniach i udostępnianiu plików znajdziesz w artykule Udostępnianie plików.

udoskonalone ułatwienia dostępu.

W Androidzie 7.0 wprowadzono zmiany, które mają ułatwić korzystanie z platformy użytkownikom niedowidzącym i niedowidzącym. Te zmiany zasadniczo nie powinny wymagać zmian w kodzie aplikacji, ale zalecamy zapoznanie się z tymi funkcjami i przetestowanie ich w aplikacji, aby ocenić potencjalny wpływ zmian na wrażenia użytkowników.

Powiększenie ekranu

Android 7.0 umożliwia użytkownikom ustawienie rozmiaru wyświetlacza, który powiększa lub pomniejsza wszystkie elementy na ekranie, dzięki czemu użytkownicy niedowidzący mogą korzystać z urządzeń. Użytkownicy nie mogą powiększać ekranu ponad minimalną szerokość ekranu wynoszącą sw320dp, czyli szerokość typowego tabletu średniej wielkości Nexus 4.

Ekran z wyświetlonym bez powiększania ekranem urządzenia z obrazem systemu Android 7.0
Ekran pokazujący efekt zwiększenia rozmiaru wyświetlacza urządzenia z obrazem systemu Android 7.0

Rysunek 3. Ekran po prawej stronie pokazuje efekt zwiększenia rozmiaru wyświetlacza na urządzeniu z obrazem systemu Android 7.0.

Gdy zmieni się gęstość urządzeń, system powiadamia uruchomione aplikacje na te sposoby:

  • Jeśli aplikacja jest kierowana na interfejs API na poziomie 23 lub niższym, system automatycznie zamknie wszystkie jej procesy w tle. Oznacza to, że jeśli użytkownik wyłączy taką aplikację, aby otworzyć ekran Ustawienia i zmienić ustawienie Rozmiar wyświetlacza, system zamknie aplikację w taki sam sposób jak w przypadku małej ilości pamięci. Jeśli aplikacja ma procesy na pierwszym planie, system powiadamia te procesy o zmianie konfiguracji w sposób opisany w sekcji Obsługa zmian środowiska wykonawczego, tak jak gdyby zmieniła się orientacja urządzenia.
  • Jeśli aplikacja jest kierowana na Androida 7.0, wszystkie jej procesy (na pierwszym planie i w tle) są powiadamiane o zmianie konfiguracji zgodnie z opisem w sekcji Obsługa zmian środowiska wykonawczego.

W przypadku większości aplikacji nie trzeba wprowadzać żadnych zmian, aby obsługiwać tę funkcję, o ile są one zgodne ze sprawdzonymi metodami dotyczącymi Androida. Konkretne kwestie, które należy sprawdzić:

  • Przetestuj aplikację na urządzeniu o szerokości ekranu sw320dp i upewnij się, że działa nieźle.
  • Gdy konfiguracja urządzenia ulegnie zmianie, zaktualizuj wszelkie informacje z pamięci podręcznej zależne od gęstości, takie jak mapy bitowe zapisane w pamięci podręcznej lub zasoby ładowane z sieci. Sprawdź, czy konfiguracja nie zmienia się po wznowieniu aplikacji ze stanu wstrzymania.

    Uwaga: jeśli dane zależne od konfiguracji przechowujesz w pamięci podręcznej, warto dodać odpowiednie metadane, np. odpowiedni rozmiar ekranu lub gęstość pikseli w przypadku tych danych. Zapisanie tych metadanych pozwoli Ci zdecydować, czy po zmianie konfiguracji musisz odświeżyć dane z pamięci podręcznej.

  • Unikaj określania wymiarów za pomocą jednostek w pikselach, ponieważ nie są one skalowane razem z gęstością ekranu. Zamiast tego określ wymiary za pomocą jednostek pikseli niezależnych od gęstości (dp).

Ustawienia widoczności w kreatorze konfiguracji

Android 7.0 zawiera ustawienia widoczności na ekranie powitalnym, które pozwalają użytkownikom skonfigurować te ustawienia ułatwień dostępu na nowym urządzeniu: gesty powiększenia, rozmiar czcionki, rozmiar wyświetlacza i TalkBack. Ta zmiana zwiększa widoczność błędów związanych z różnymi ustawieniami ekranu. Aby ocenić wpływ tej funkcji, przetestuj swoje aplikacje z włączonymi tymi ustawieniami. Ustawienia znajdziesz w sekcji Ustawienia > Ułatwienia dostępu.

Łączenie aplikacji NDK z bibliotekami platform

Począwszy od Androida 7.0 system uniemożliwia aplikacjom dynamiczne łączenie się z bibliotekami innymi niż NDK, co może spowodować awarię aplikacji. Ta zmiana sposobu działania ma na celu zapewnienie spójnego sposobu korzystania z aplikacji w przypadku aktualizacji platformy i urządzeń. Nawet jeśli Twój kod nie zawiera linków do bibliotek prywatnych, może to robić biblioteka statyczna innej firmy, dlatego wszyscy deweloperzy powinni sprawdzić, czy ich aplikacje na urządzeniach z Androidem 7.0 nie ulegają awariom. Jeśli aplikacja używa kodu natywnego, używaj tylko publicznych interfejsów API NDK.

Aplikacja może próbować uzyskać dostęp do interfejsów API platformy prywatnej na 3 sposoby:

  • Twoja aplikacja ma bezpośredni dostęp do bibliotek platform prywatnych. Zaktualizuj aplikację, aby zawierała ich własne kopie tych bibliotek lub użyj publicznych interfejsów API NDK.
  • Twoja aplikacja używa biblioteki zewnętrznej, która ma dostęp do bibliotek platformy prywatnej. Nawet jeśli masz pewność, że Twoja aplikacja nie ma bezpośredniego dostępu do bibliotek prywatnych, i tak warto ją przetestować pod kątem tego scenariusza.
  • Aplikacja odwołuje się do biblioteki, która nie jest uwzględniona w jej pliku APK. Może się tak na przykład zdarzyć, jeśli próbujesz użyć własnej kopii OpenSSL, ale zapomniałeś dodać ją do pakietu APK aplikacji. Aplikacja może działać normalnie na urządzeniach z Androidem w tych wersjach: libcrypto.so. Aplikacja może jednak ulec awarii w nowszych wersjach Androida, które nie zawierają tej biblioteki (np. na Androidzie 6.0 i nowszych). Aby rozwiązać ten problem, połącz z plikiem APK wszystkie biblioteki inne niż NDK.

Aplikacje nie powinny używać bibliotek natywnych, które nie znajdują się w pakiecie NDK, ponieważ mogą one ulec zmianie lub zostać usunięte w różnych wersjach Androida. Przykładem tego typu zmiany jest przejście z OpenSSL na BoringSSL. Nie ma też wymagań w zakresie zgodności bibliotek platform, które nie znajdują się w pakiecie NDK, dlatego różne urządzenia mogą oferować różne poziomy zgodności.

Aby ograniczyć wpływ tego ograniczenia na obecnie opublikowane aplikacje, zestaw bibliotek o dużym wykorzystaniu, np. libandroid_runtime.so, libcutils.so, libcrypto.so i libssl.so, jest tymczasowo dostępny na Androidzie 7.0 (poziom API 24) dla aplikacji kierowanych na interfejs API na poziomie 23 lub niższym. Jeśli aplikacja wczytuje jedną z tych bibliotek, logcat wygeneruje ostrzeżenie, a na urządzeniu docelowym wyświetli się komunikat z powiadomieniem. Jeśli widzisz te ostrzeżenia, zaktualizuj aplikację, aby zawierała ich własną kopię tych bibliotek lub używała tylko publicznych interfejsów API NDK. W kolejnych wersjach platformy Android można całkowicie ograniczyć korzystanie z bibliotek prywatnych i spowodować awarię aplikacji.

Gdy wywołujesz interfejs API, który nie jest publiczny ani tymczasowo dostępny, wszystkie aplikacje generują błąd środowiska wykonawczego. W efekcie funkcje System.loadLibrary i dlopen(3) zwracają wartości NULL, co może spowodować awarię aplikacji. Sprawdź kod aplikacji, aby usunąć możliwość korzystania z interfejsów API platformy prywatnej, i dokładnie przetestuj swoje aplikacje za pomocą urządzenia lub emulatora z Androidem 7.0 (poziom API 24). Jeśli nie masz pewności, czy Twoja aplikacja używa bibliotek prywatnych, sprawdź plik logcat, aby zidentyfikować błąd środowiska wykonawczego.

W tabeli poniżej opisujemy działanie, którego należy spodziewać się w aplikacji w zależności od wykorzystania w niej prywatnych bibliotek natywnych i jej docelowego poziomu interfejsu API (android:targetSdkVersion).

Biblioteki Docelowy poziom interfejsu API Dostęp do środowiska wykonawczego za pomocą dynamicznego tagu łączącego Zachowanie Androida 7.0 (poziom interfejsu API 24) Zachowanie platformy Androida w przyszłości
Pakiet NDK publiczny Dowolna Ułatwienia dostępu Działa zgodnie z oczekiwaniami Działa zgodnie z oczekiwaniami
Prywatne (tymczasowo dostępne biblioteki prywatne) 23 lub mniej Tymczasowo dostępny Działa zgodnie z oczekiwaniami, ale pojawia się ostrzeżenie dotyczące logcat. Błąd środowiska wykonawczego
Prywatne (tymczasowo dostępne biblioteki prywatne) 24 lub więcej Z ograniczeniem Błąd środowiska wykonawczego Błąd środowiska wykonawczego
Prywatne (inne) Dowolna Z ograniczeniem Błąd środowiska wykonawczego Błąd środowiska wykonawczego

Sprawdzanie, czy aplikacja korzysta z bibliotek prywatnych

Aby ułatwić identyfikowanie problemów z wczytywaniem bibliotek prywatnych, narzędzie logcat może generować ostrzeżenie lub błąd środowiska wykonawczego. Jeśli na przykład aplikacja jest kierowana na interfejs API na poziomie 23 lub niższym i próbuje uzyskać dostęp do prywatnej biblioteki na urządzeniu z Androidem 7.0, może pojawić się ostrzeżenie podobne do tego:

03-21 17:07:51.502 31234 31234 W linker  : library "libandroid_runtime.so"
("/system/lib/libandroid_runtime.so") needed or dlopened by
"/data/app/com.popular-app.android-2/lib/arm/libapplib.so" is not accessible
for the namespace "classloader-namespace" - the access is temporarily granted
as a workaround for http://b/26394120

Te ostrzeżenia logcat informują, która biblioteka próbuje uzyskać dostęp do interfejsu API platformy prywatnej, ale nie powoduje awarii aplikacji. Jeśli jednak aplikacja jest kierowana na interfejs API na poziomie 24 lub wyższym, logcat wygeneruje ten błąd środowiska wykonawczego, a aplikacja może ulec awarii:

java.lang.UnsatisfiedLinkError: dlopen failed: library "libcutils.so"
("/system/lib/libcutils.so") needed or dlopened by
"/system/lib/libnativeloader.so" is not accessible for the namespace
"classloader-namespace"
  at java.lang.Runtime.loadLibrary0(Runtime.java:977)
  at java.lang.System.loadLibrary(System.java:1602)

Te dane wyjściowe logcat mogą też być widoczne, jeśli Twoja aplikacja korzysta z bibliotek innych firm, które dynamicznie łączą się z interfejsami API platformy prywatnej. Narzędzie readelf w Androidzie 7.0DK umożliwia wygenerowanie listy wszystkich dynamicznie połączonych bibliotek udostępnionych danego pliku .so. Aby to zrobić, uruchom następujące polecenie:

aarch64-linux-android-readelf -dW libMyLibrary.so

Zaktualizuj aplikację

Oto kilka czynności, które możesz wykonać, aby naprawić tego typu błędy i upewnić się, że aplikacja nie ulega awarii przy kolejnych aktualizacjach platformy:

  • Jeśli Twoja aplikacja używa bibliotek platformy prywatnej, zaktualizuj ją, aby zawierała ich własne kopie tych bibliotek lub użyj publicznych interfejsów API NDK.
  • Jeśli Twoja aplikacja korzysta z biblioteki innej firmy, która ma dostęp do symboli prywatnych, skontaktuj się z autorem biblioteki, aby ją zaktualizować.
  • Pamiętaj, by w pakiecie APK umieścić wszystkie biblioteki inne niż NDK.
  • Użyj standardowych funkcji JNI zamiast getJavaVM i getJNIEnv z libandroid_runtime.so:
    AndroidRuntime::getJavaVM -> GetJavaVM from <jni.h>
    AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or
    JavaVM::AttachCurrentThread from <jni.h>.
    
  • Użyj __system_property_get zamiast prywatnego symbolu property_get z libcutils.so. Aby to zrobić, użyj polecenia __system_property_get z tymi danymi:
    #include <sys/system_properties.h>
    

    Uwaga: dostępność i zawartość właściwości systemowych nie są testowane za pomocą narzędzia CTS. Lepszym rozwiązaniem jest całkowite unikanie tych właściwości.

  • Użyj lokalnej wersji symbolu SSL_ctrl z libcrypto.so. Na przykład dodaj statycznie link libcyrpto.a w pliku .so lub dołącz dynamicznie powiązaną wersję libcrypto.so z BoringSSL/OpenSSL i spakuj ją w pliku APK.

Android for Work

Android 7.0 zawiera zmiany w aplikacjach kierowanych na Android for Work, w tym zmiany dotyczące instalacji certyfikatów, resetowania haseł, dodatkowego zarządzania użytkownikami i dostępu do identyfikatorów urządzeń. Jeśli tworzysz aplikacje na środowiska Android for Work, zapoznaj się z tymi zmianami i odpowiednio zmodyfikuj aplikację.

  • Musisz zainstalować instalatora delegowanego certyfikatu, zanim DPC będzie mógł go ustawić. Zarówno w przypadku aplikacji profilowych, jak i aplikacji właściciela urządzenia kierowanych na Androida 7.0 (poziom interfejsu API 24) należy zainstalować instalator certyfikatów delegowanych przed wywołaniem funkcji DevicePolicyManager.setCertInstallerPackage() przez kontroler zasad dotyczących urządzeń (DPC). Jeśli instalator nie jest jeszcze zainstalowany, system zwróci błąd IllegalArgumentException.
  • Resetowanie ograniczeń dotyczących haseł na potrzeby administratorów urządzeń jest teraz stosowane do właścicieli profili. Administratorzy urządzeń nie mogą już używać DevicePolicyManager.resetPassword() do czyszczenia haseł ani zmieniania tych, które zostały już ustawione. Administratorzy urządzeń mogą nadal ustawiać hasło, ale tylko wtedy, gdy na urządzeniu nie ma hasła, kodu PIN ani wzoru.
  • Właściciele urządzeń i profili mogą zarządzać kontami, nawet jeśli są nałożone ograniczenia. Właściciele urządzeń i właściciele profili mogą wywoływać interfejsy API do zarządzania kontem, nawet jeśli stosowane są ograniczenia dotyczące użytkowników DISALLOW_MODIFY_ACCOUNTS.
  • Właściciele urządzeń mogą łatwiej zarządzać użytkownikami dodatkowymi. Gdy urządzenie działa w trybie właściciela urządzenia, ograniczenie DISALLOW_ADD_USER jest stosowane automatycznie. Uniemożliwia to użytkownikom tworzenie niezarządzanych użytkowników dodatkowych. Poza tym metody CreateUser() i createAndInitializeUser() zostały wycofane, a zastępuje je nowa metoda DevicePolicyManager.createAndManageUser().
  • Właściciele urządzeń mają dostęp do identyfikatorów. Właściciel urządzenia może uzyskać dostęp do adresu MAC sieci Wi-Fi urządzenia za pomocą DevicePolicyManager.getWifiMacAddress(). Jeśli sieć Wi-Fi nie była nigdy włączona na urządzeniu, ta metoda zwraca wartość null.
  • Ustawienie Tryb pracy kontroluje dostęp do aplikacji służbowych. Gdy tryb pracy jest wyłączony, system uruchamiający system wskazuje, że aplikacje służbowe są niedostępne. W tym celu są one wyszarzone. Ponowne włączenie trybu pracy przywraca normalne działanie.
  • W przypadku instalowania pliku PKCS #12 zawierającego łańcuch certyfikatów klienta i odpowiedni klucz prywatny z interfejsu ustawień, certyfikat CA w łańcuchu nie jest już zainstalowany w magazynie zaufanych danych logowania. Nie ma to wpływu na wynik KeyChain.getCertificateChain(), gdy aplikacje próbują później pobrać łańcuch certyfikatów klienta. W razie potrzeby certyfikat CA należy zainstalować w magazynie zaufanych danych logowania za pomocą interfejsu ustawień osobno w formacie DER z rozszerzeniem .crt lub .cer.
  • Od Androida 7.0 rejestrowanie i przechowywanie odcisku palca są zarządzane dla poszczególnych użytkowników. Jeśli klient Device Policy (DPC) właściciela profilu kieruje reklamy na interfejs API na poziomie 23 (lub niższym) na urządzeniu z Androidem 7.0 (poziom API 24), użytkownik nadal może ustawiać odcisk cyfrowy na urządzeniu, ale aplikacje służbowe nie mają dostępu do odcisku cyfrowego urządzenia. Jeśli DPC jest kierowany na interfejs API na poziomie 24 lub wyższym, użytkownik może ustawić odcisk cyfrowy specjalnie dla profilu służbowego, klikając Ustawienia > Zabezpieczenia > Zabezpieczenia profilu służbowego.
  • DevicePolicyManager.getStorageEncryptionStatus() zwraca nowy stan szyfrowania ENCRYPTION_STATUS_ACTIVE_PER_USER, aby wskazać, że szyfrowanie jest aktywne, a klucz szyfrowania jest powiązany z użytkownikiem. Nowy stan jest zwracany tylko wtedy, gdy DPC kieruje reklamy na interfejs API na poziomie 24 lub wyższym. W przypadku aplikacji kierowanych na wcześniejsze poziomy interfejsu API zwracany jest kod ENCRYPTION_STATUS_ACTIVE, nawet jeśli klucz szyfrowania jest przypisany do użytkownika lub profilu.
  • W Androidzie 7.0 kilka metod, które zwykle wpływają na całe urządzenie, działa inaczej, jeśli na urządzeniu jest zainstalowany profil służbowy z osobnym zadaniem. Zamiast wpływać na całe urządzenie, metody te mają zastosowanie tylko do profilu służbowego. (Pełną listę takich metod znajdziesz w dokumentacji DevicePolicyManager.getParentProfileInstance()). Na przykład DevicePolicyManager.lockNow() zablokuje tylko profil służbowy, a nie całe urządzenie. W przypadku każdej z tych metod możesz przywrócić poprzednie działanie, wywołując ją w instancji nadrzędnej DevicePolicyManager. Możesz uzyskać ten element nadrzędny, wywołując DevicePolicyManager.getParentProfileInstance(). Jeśli na przykład wywołasz metodę lockNow() instancji nadrzędnej, całe urządzenie zostanie zablokowane.

Przechowywanie adnotacji

W Androidzie 7.0 naprawiono błąd, który powodował, że widoczność adnotacji była ignorowana. Ten problem umożliwił środowisku wykonawczemu dostęp do adnotacji, które nie powinny być dostępne. Adnotacje te obejmowały:

  • VISIBILITY_BUILD: ma być widoczne tylko w czasie kompilacji.
  • VISIBILITY_SYSTEM: ma być widoczne w czasie działania, ale tylko dla systemu bazowego.

Jeśli Twoja aplikacja jest oparta na takim działaniu, dodaj zasady przechowywania do adnotacji, które muszą być dostępne w czasie działania. Aby to zrobić, użyj @Retention(RetentionPolicy.RUNTIME).

Zmiany domyślnej konfiguracji TLS/SSL

Android 7.0 wprowadza poniższe zmiany w domyślnej konfiguracji TLS/SSL używanej przez aplikacje do obsługi protokołu HTTPS i innego ruchu TLS/SSL:

  • Zestawy szyfrów RC4 są teraz wyłączone.
  • Zestawy szyfrów CHACHA20-POLY1305 są teraz włączone.

Domyślnie wyłączenie RC4 może spowodować zakłócenia w połączeniu HTTPS lub TLS/SSL, gdy serwer nie negocjuje nowoczesnych zestawów szyfrów. Preferowaną metodą jest poprawa konfiguracji serwera w celu włączenia silniejszych i bardziej nowoczesnych zestawów szyfrów oraz protokołów. Najlepiej jest włączyć TLSv1.2 i AES-GCM oraz włączyć i preferowane zestawy szyfrów Forward Secrecy (ECDHE).

Możesz też zmodyfikować aplikację, aby do komunikacji z serwerem używała niestandardowego elementu SSLSocketFactory. Fabryka powinna tworzyć instancje SSLSocket, które oprócz domyślnych zestawów szyfrów mają niektóre zestawy szyfrów wymagane przez serwer.

Uwaga: te zmiany nie dotyczą WebView.

Aplikacje na Androida 7.0

Te zmiany w działaniu dotyczą tylko aplikacji kierowanych na Androida 7.0 (poziom API 24) lub nowszy. Aplikacje, które skompilują Androida 7.0 lub system targetSdkVersion na Androida w wersji 7.0 lub nowszej, w stosownych przypadkach muszą zmodyfikować swoje aplikacje, aby prawidłowo obsługiwały te zachowania.

Zmiany w serializacji

W Androidzie 7.0 (poziom interfejsu API 24) naprawiliśmy błąd w obliczaniu domyślnej wartości serialVersionUID, który nie był zgodny ze specyfikacją.

Klasy, które implementują Serializable, ale nie mają jawnego pola serialVersionUID, mogłyby spowodować zmianę domyślnej wartości serialVersionUID, co spowodowałoby zgłoszenie wyjątku podczas próby deserializacji instancji klasy, które zostały zserializowane we wcześniejszej wersji lub zserializowane przez aplikację kierowaną na wcześniejszą wersję. Komunikat o błędzie będzie wyglądał mniej więcej tak:

local class incompatible: stream classdesc serialVersionUID = 1234, local class serialVersionUID = 4567

Rozwiązanie tych problemów wymaga dodania pola serialVersionUID do każdej klasy, której dotyczy problem, o wartości stream classdesc serialVersionUID z komunikatu o błędzie (w tym przypadku 1234). Ta zmiana jest zgodna ze wszystkimi zaleceniami dotyczącymi pisania kodu serializacji i będzie działać we wszystkich wersjach Androida.

Naprawiony błąd był związany z obecnością statycznych metod inicjatora, np. <clinit>. Zgodnie ze specyfikacją obecność lub brak statycznej metody inicjatora w klasie wpływa na domyślną wartość serialVersionUID obliczoną dla tej klasy. Przed poprawką błędu obliczenie sprawdzało też klasę superklasyczną dla statycznego inicjatora, jeśli klasa go nie miała.

Ta zmiana nie dotyczy aplikacji kierowanych na interfejsy API na poziomie 23 lub niższym, klas zawierających pole serialVersionUID lub klas z metodą inicjatora statycznego.

Inne ważne kwestie

  • Gdy aplikacja działa na Androidzie 7.0, ale jest kierowana na niższy poziom interfejsu API, a użytkownik zmieni rozmiar wyświetlacza, proces aplikacji zostaje zakończony. Aplikacja musi umieć płynnie poradzić sobie z tym zadaniem. W przeciwnym razie ulega awarii, gdy użytkownik przywróci ją z Ostatnich.

    Przetestuj aplikację, aby się upewnić, że nie występują takie błędy. Aby to zrobić, wywołaj identyczną awarię podczas ręcznego zamykania aplikacji w DDMS.

    Aplikacje kierowane na Androida 7.0 (poziom interfejsu API 24) lub nowszego nie są automatycznie zatrzymywane po zmianie gęstości, ale nadal mogą słabo reagować na zmiany w konfiguracji.

  • Aplikacje na Androida 7.0 powinny płynnie obsługiwać zmiany w konfiguracji i nie powinny ulegać awarii przy kolejnych uruchomieniach. Możesz sprawdzić działanie aplikacji, zmieniając rozmiar czcionki (Ustawienie > Wyświetlanie > Rozmiar czcionki), a następnie przywróć aplikację z sekcji Ostatnie.
  • Z powodu błędu w poprzednich wersjach Androida system nie oznaczył zapisu zapisu do gniazda TCP w wątku głównym jako naruszenia w trybie ścisłym. Android 7.0 naprawia ten błąd. Aplikacje, które wykazują takie działanie, generują teraz zdarzenie android.os.NetworkOnMainThreadException. Ogólnie rzecz biorąc, wykonywanie operacji sieciowych w wątku głównym nie jest dobrym pomysłem, ponieważ zwykle charakteryzują się długim czasem oczekiwania, który powoduje błędy ANR i zacinanie.
  • Rodzina metod Debug.startMethodTracing() domyślnie przechowuje dane wyjściowe w katalogu związanym z pakietem w pamięci współdzielonej, a nie na najwyższym poziomie karty SD. Oznacza to, że aplikacje nie muszą już prosić o uprawnienie WRITE_EXTERNAL_STORAGE, aby używać tych interfejsów API.
  • Wiele interfejsów API platformy rozpoczęło sprawdzanie dużych ładunków wysyłanych w ramach transakcji Binder. System przesyła teraz TransactionTooLargeExceptions jako RuntimeExceptions zamiast dyskretnego logowania czy blokowania tych transakcji. Typowym przykładem jest przechowywanie zbyt dużej ilości danych w usłudze Activity.onSaveInstanceState(), przez co ActivityThread.StopInfo zwraca błąd RuntimeException, gdy aplikacja jest kierowana na Androida 7.0.
  • Jeśli aplikacja opublikuje zadania Runnable w elemencie View, a View nie jest podłączony do okna, system doda zadanie Runnable do kolejki z identyfikatorem View. Zadanie Runnable nie zostanie wykonane, dopóki do okna nie zostanie dołączony element View. Usunięto te błędy:
    • Jeśli aplikacja została opublikowana w elemencie View z wątku innego niż wątek interfejsu użytkownika odpowiedniego okna, Runnable może w rezultacie działać w niewłaściwym wątku.
    • Jeśli zadanie Runnable zostało opublikowane w wątku innym niż wątek looper, aplikacja może ujawnić zadanie Runnable.
  • Jeśli aplikacja na Androida 7.0 z uprawnieniami DELETE_PACKAGES próbuje usunąć pakiet, ale inna aplikacja go zainstalowała, system wymaga potwierdzenia użytkownika. W tym scenariuszu przy wywołaniu metody PackageInstaller.uninstall() aplikacje powinny się spodziewać stanu zwrotu STATUS_PENDING_USER_ACTION.
  • Dostawca JCA o nazwie Crypto został wycofany, ponieważ jego jedyny algorytm – SHA1PRNG, jest słaby pod względem kryptograficznym. Aplikacje nie mogą już używać algorytmu SHA1PRNG do (niebezpiecznego) wykrywania kluczy, ponieważ ten dostawca nie jest już dostępny. Więcej informacji znajdziesz w poście na blogu o wycofaniu dostawcy zabezpieczeń „Crypto” na Androidzie N.