Poziom API: 18
Android 4.3 (JELLY_BEAN_MR2
) to aktualizacja wersji Jelly Bean, która udostępnia nowe funkcje dla użytkowników i deweloperów aplikacji. Ten dokument zawiera wprowadzenie do najbardziej znanych nowych interfejsów API.
Deweloper aplikacji powinien jak najszybciej pobrać obraz systemu Android 4.3 i platformę SDK z Menedżera pakietów SDK. Jeśli nie masz urządzenia z Androidem 4.3, na którym chcesz przetestować aplikację, użyj obrazu systemu Android 4.3, by przetestować aplikację w emulatorze Androida. Następnie skompiluj aplikacje na platformie Androida 4.3, aby zacząć korzystać z najnowszych interfejsów API.
Aktualizowanie docelowego poziomu interfejsu API
Aby lepiej zoptymalizować aplikację pod kątem urządzeń z Androidem 4.3, ustaw targetSdkVersion
na "18"
, zainstaluj ją na obrazie systemu Androida 4.3, przetestuj ją, a następnie opublikuj aktualizację z tą zmianą.
Możesz używać interfejsów API w Androidzie 4.3, a jednocześnie obsługiwać starsze wersje. Aby to zrobić, dodaj do kodu warunki, które przed wykonaniem interfejsów API nieobsługiwanych przez minSdkVersion
sprawdzają poziom interfejsu API systemu.
Więcej informacji o utrzymywaniu zgodności wstecznej znajdziesz w artykule Obsługa różnych wersji platformy.
W bibliotece pomocy Androida dostępne są różne interfejsy API, które umożliwiają wdrażanie nowych funkcji w starszych wersjach platformy.
Więcej informacji o tym, jak działają poziomy interfejsu API, znajdziesz w artykule Co to jest poziom interfejsu API?.
Ważne zmiany w działaniu
Jeśli masz już opublikowaną aplikację na Androida, pamiętaj, że zmiany w Androidzie 4.3 mogą na nią wpływać.
Jeśli aplikacja używa intencji niejawnych...
Twoja aplikacja może działać nieprawidłowo w środowisku profilu ograniczonego.
Użytkownicy w środowisku o profilu z ograniczonym dostępem mogą nie mieć dostępu do wszystkich standardowych aplikacji na Androida. Na przykład profil z ograniczonym dostępem może mieć wyłączoną
przeglądarkę i aplikację aparatu. Aplikacja nie powinna więc sugerować, które aplikacje są dostępne, ponieważ jeśli wywołasz startActivity()
bez sprawdzenia, czy aplikacja jest dostępna do obsługi funkcji Intent
, może się ona popsuć w profilu z ograniczonym dostępem.
Jeśli korzystasz z intencji niejawnej, zawsze sprawdzaj, czy aplikacja jest dostępna do obsługi intencji, wywołując metodę resolveActivity()
lub queryIntentActivities()
. Na przykład:
Kotlin
val intent = Intent(Intent.ACTION_SEND) ... if (intent.resolveActivity(packageManager) != null) { startActivity(intent) } else { Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show() }
Java
Intent intent = new Intent(Intent.ACTION_SEND); ... if (intent.resolveActivity(getPackageManager()) != null) { startActivity(intent); } else { Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show(); }
Jeśli Twoja aplikacja wymaga kont...
Twoja aplikacja może działać nieprawidłowo w środowisku profilu ograniczonego.
Użytkownicy w środowisku profili z ograniczonym dostępem domyślnie nie mają dostępu do kont użytkowników.
Jeśli aplikacja zależy od typu Account
, może ulec awarii lub działać w nieoczekiwany sposób po użyciu w profilu z ograniczeniami.
Jeśli chcesz całkowicie uniemożliwić profilom z ograniczonym dostępem korzystanie z Twojej aplikacji, ponieważ działanie aplikacji zależy od poufnych informacji o koncie, podaj atrybut android:requiredAccountType
w elemencie <application>
pliku manifestu.
Jeśli chcesz, aby profile z ograniczonym dostępem mogły nadal korzystać z Twojej aplikacji, nawet jeśli nie mogą tworzyć własnych kont, możesz wyłączyć funkcje aplikacji, które wymagają konta, lub zezwolić profilom z ograniczonym dostępem na dostęp do kont utworzonych przez głównego użytkownika. Więcej informacji znajdziesz w poniższej sekcji dotyczącej obsługi kont w profilu z ograniczonym dostępem.
Jeśli aplikacja korzysta z funkcji VideoView...
W Androidzie 4.3 Twój film może być mniejszy.
W poprzednich wersjach Androida widżet VideoView
nieprawidłowo obliczył wartość "wrap_content"
dla właściwości layout_height
i layout_width
, tak aby była identyczna z wartością "match_parent"
. Jeśli więc ustawisz właściwość "wrap_content"
na potrzeby wysokości lub szerokości, możesz wcześniej uzyskać pożądany układ wideo, co może spowodować zmniejszenie filmu w Androidzie 4.3 i nowszych. Aby rozwiązać ten problem, zastąp "wrap_content"
fragmentem "match_parent"
i sprawdź, czy film wyświetla się prawidłowo na Androidzie 4.3 i w starszych wersjach.
Profile z ograniczonym dostępem
Na tabletach z Androidem użytkownicy mogą teraz tworzyć profile z ograniczeniami na podstawie głównego użytkownika. Gdy użytkownicy utworzą profil z ograniczonym dostępem, mogą włączyć ograniczenia, np. dotyczące dostępności aplikacji. Nowy zestaw interfejsów API w Androidzie 4.3 pozwala też na tworzenie szczegółowych ustawień ograniczeń dla aplikacji, które tworzysz. Na przykład nowe interfejsy API pozwalają użytkownikom kontrolować, jakie typy treści są dostępne w Twojej aplikacji, gdy działa ona w środowisku profilu z ograniczeniami.
Interfejs umożliwiający użytkownikom kontrolowanie utworzonych przez Ciebie ograniczeń jest zarządzany przez aplikację Ustawienia systemu. Aby wyświetlić użytkownikom ustawienia ograniczeń aplikacji, musisz zadeklarować ograniczenia, które ona zapewnia. W tym celu utwórz BroadcastReceiver
, który odbiera intencję ACTION_GET_RESTRICTION_ENTRIES
. System wywołuje tę intencję, aby wysyłać zapytania o dostępne ograniczenia do wszystkich aplikacji, a następnie kompilowa interfejs użytkownika tak, aby mógł zarządzać ograniczeniami w przypadku każdego profilu z ograniczeniami.
W metodzie onReceive()
BroadcastReceiver
musisz utworzyć RestrictionEntry
dla każdego ograniczenia nakładanego przez aplikację. Każdy element RestrictionEntry
ma tytuł, opis i jeden z tych typów danych:
TYPE_BOOLEAN
w przypadku ograniczenia, które ma wartość prawda lub fałsz.TYPE_CHOICE
w przypadku ograniczenia zawierającego wiele wzajemnie wykluczających się opcji (opcje).TYPE_MULTI_SELECT
w przypadku ograniczenia zawierającego wiele opcji, które nie wzajemnie się wykluczają (opcje pól wyboru).
Następnie umieszczasz wszystkie obiekty RestrictionEntry
w obiekcie ArrayList
i umieszczasz je w wyniku odbiornika jako wartość nadmiarowego EXTRA_RESTRICTIONS_LIST
.
System tworzy interfejs z ograniczeniami aplikacji w aplikacji Ustawienia i zapisuje je za pomocą unikalnego klucza podanego dla każdego obiektu RestrictionEntry
. Gdy użytkownik otworzy aplikację, możesz przesłać zapytanie o obecne ograniczenia, wywołując getApplicationRestrictions()
.
Zwraca ono Bundle
zawierające pary klucz-wartość dla każdego ograniczenia zdefiniowanego w obiektach RestrictionEntry
.
Jeśli chcesz podać bardziej szczegółowe ograniczenia, których nie można obsługiwać przy użyciu wartości logicznych, jednokrotnego wyboru ani wartości wielokrotnego wyboru, możesz utworzyć działanie, w którym użytkownik będzie mógł określić ograniczenia i umożliwić im uruchomienie danej aktywności z poziomu ustawień ograniczeń. W odbiorniku transmisji dodaj do wyniku Bundle
dodatek EXTRA_RESTRICTIONS_INTENT
. Ten dodatek musi określać klasę Intent
wskazującą klasę Activity
do uruchomienia (użyj metody putParcelable()
, aby przekazać intencję EXTRA_RESTRICTIONS_INTENT
).
Gdy główny użytkownik przejdzie do działania, aby ustawić ograniczenia niestandardowe, musi ona zwrócić wynik zawierający wartości ograniczeń dodatkowo za pomocą klucza EXTRA_RESTRICTIONS_LIST
lub EXTRA_RESTRICTIONS_BUNDLE
w zależności od tego, czy wskażesz obiekty RestrictionEntry
czy pary klucz-wartość.
Obsługa kont w profilu z ograniczonym dostępem
Wszystkie konta dodane do użytkownika głównego są dostępne w przypadku profilu z ograniczonym dostępem, ale domyślnie konta nie są dostępne przez interfejsy API AccountManager
.
Jeśli spróbujesz dodać konto AccountManager
w profilu z ograniczeniami, zakończy się niepowodzeniem. Z powodu tych ograniczeń masz do wyboru 3 opcje:
Aby uzyskać dostęp do konta z profilu ograniczonego, musisz dodać atrybut android:restrictedAccountType
do tagu <application>:
<application ... android:restrictedAccountType="com.example.account.type" >
Uwaga: włączenie tego atrybutu daje aplikacji dostęp do kont głównego użytkownika z profili ograniczonych. Należy więc zezwolić na to tylko wtedy, gdy informacje wyświetlane przez aplikację nie zawierają informacji umożliwiających identyfikację osób, które są uznawane za poufne. Ustawienia systemowe poinformują głównego użytkownika o tym, że Twoja aplikacja udostępnia swoim kontom profile z ograniczonym dostępem, dlatego dla użytkownika powinno być jasne, że dostęp do konta jest ważny dla działania aplikacji. W miarę możliwości należy też zapewnić głównemu użytkownikowi odpowiednie ograniczenia, które określają dozwolony poziom dostępu aplikacji do konta.
Jeśli chcesz korzystać z kont, ale nie potrzebujesz ich do realizowania swoich głównych funkcji, możesz sprawdzić dostępność kont i wyłączyć funkcje, gdy nie są dostępne.
Najpierw sprawdź, czy już masz takie konto. Jeśli nie, zapytaj, czy można utworzyć nowe konto, wywołując funkcję getUserRestrictions()
, i sprawdź dodatkowo informację o DISALLOW_MODIFY_ACCOUNTS
w wyniku. Jeśli jest to true
, wyłącz wszelkie funkcje aplikacji, które wymagają dostępu do kont.
Na przykład:
Kotlin
val um = context.getSystemService(Context.USER_SERVICE) as UserManager val restrictions: Bundle = um.userRestrictions if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { // cannot add accounts, disable some functionality }
Java
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); Bundle restrictions = um.getUserRestrictions(); if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { // cannot add accounts, disable some functionality }
Uwaga: w tym przypadku nie należy deklarować nowych atrybutów w pliku manifestu.
Jeśli jednak Twoim zdaniem aplikacja nie ma być dostępna dla profili z ograniczonym dostępem, ponieważ jest uzależniona od poufnych danych osobowych na koncie (oraz ze względu na to, że profile z ograniczeniami nie mogą obecnie dodawać nowych kont), dodaj atrybut android:requiredAccountType
do tagu <application>:
<application ... android:requiredAccountType="com.example.account.type" >
Na przykład aplikacja Gmail używa tego atrybutu do wyłączania się w profilach z ograniczeniami, ponieważ osobisty adres e-mail właściciela nie powinien być dostępny w profilach z ograniczonym dostępem.
Łączność bezprzewodowa
Bluetooth Low Energy (technologia Smart)
Android obsługuje teraz Bluetooth Low Energy (LE) z nowymi interfejsami API w android.bluetooth
.
Dzięki nowym interfejsom API możesz tworzyć aplikacje na Androida, które komunikują się z urządzeniami peryferyjnymi Bluetooth Low Energy, takimi jak pulsometr czy krokomierze.
Bluetooth LE to funkcja sprzętowa, która nie jest dostępna na wszystkich urządzeniach z Androidem, więc w pliku manifestu musisz zadeklarować element <uses-feature>
dla "android.hardware.bluetooth_le"
:
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
Jeśli znasz już klasyczne interfejsy API Bluetooth na Androida, zwróć uwagę na pewne różnice w korzystaniu z interfejsów API Bluetooth LE. Przede wszystkim jest teraz klasa BluetoothManager
, której należy używać do wykonywania niektórych działań ogólnych, takich jak pozyskiwanie BluetoothAdapter
, pobieranie listy połączonych urządzeń i sprawdzanie stanu urządzenia. Na przykład aby pobrać BluetoothAdapter
w ten sposób:
Kotlin
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager bluetoothAdapter = bluetoothManager.adapter
Java
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); bluetoothAdapter = bluetoothManager.getAdapter();
Aby wykryć urządzenia peryferyjne Bluetooth LE, wywołaj metodę startLeScan()
w BluetoothAdapter
i przekaż jej implementację interfejsu BluetoothAdapter.LeScanCallback
. Gdy przejściówka Bluetooth wykryje urządzenie peryferyjne Bluetooth LE, Twoja implementacja BluetoothAdapter.LeScanCallback
otrzyma wywołanie metody onLeScan()
. Ta metoda udostępnia obiekt BluetoothDevice
reprezentujący wykryte urządzenie, wartość RSSI dla urządzenia oraz tablicę bajtów zawierającą rekord reklam urządzenia.
Jeśli chcesz skanować w poszukiwaniu tylko określonych typów urządzeń peryferyjnych, możesz zamiast tego wywołać startLeScan()
i dołączyć tablicę obiektów UUID
, które określają usługi GATT obsługiwane przez Twoją aplikację.
Uwaga: możesz skanować tylko w poszukiwaniu urządzeń Bluetooth LE lub w poszukiwaniu klasycznych urządzeń Bluetooth przy użyciu poprzednich interfejsów API. Nie można jednocześnie skanować w poszukiwaniu urządzeń LE i Classic.
Aby połączyć się z urządzeniem peryferyjnym Bluetooth LE, wywołaj connectGatt()
na odpowiednim obiekcie BluetoothDevice
i przekaż mu implementację BluetoothGattCallback
. Twoja implementacja BluetoothGattCallback
otrzymuje wywołania zwrotne dotyczące stanu połączenia z urządzeniem i innych zdarzeń. To w trakcie wywołania zwrotnego onConnectionStateChange()
możesz rozpocząć komunikację z urządzeniem, jeśli metoda przekaże STATE_CONNECTED
jako nowy stan.
Aby uzyskać dostęp do funkcji Bluetooth na urządzeniu, aplikacja musi też prosić o określone uprawnienia użytkownika Bluetooth. Więcej informacji znajdziesz w przewodniku po interfejsie API Bluetooth Low Energy.
Tryb tylko skanowania Wi-Fi
Podczas próby rozpoznania lokalizacji użytkownika Android może użyć Wi-Fi, aby uzyskać pomoc przez skanowanie pobliskich punktów dostępu. Jednak użytkownicy często wyłączają Wi-Fi, aby oszczędzać baterię, przez co dane o lokalizacji są mniej dokładne. Android oferuje teraz tryb „tylko skanowanie”, który pozwala sieci Wi-Fi na skanowanie punktów dostępu. Dzięki temu można ustalić lokalizację bez łączenia się z punktem dostępu, co znacznie zmniejsza wykorzystanie baterii.
Jeśli chcesz uzyskać lokalizację użytkownika, gdy Wi-Fi jest obecnie wyłączone, możesz poprosić użytkownika o włączenie trybu skanowania Wi-Fi, wywołując startActivity()
i wykonując ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE
.
Konfiguracja Wi-Fi
Nowe interfejsy API WifiEnterpriseConfig
pozwalają usługom dla firm zautomatyzować konfigurację Wi-Fi na urządzeniach zarządzanych.
Szybka odpowiedź na połączenia przychodzące
Od Androida 4.0 dostępna jest funkcja „Szybka odpowiedź”, która pozwala odpowiadać na połączenia przychodzące natychmiastowo SMS-ami, bez potrzeby odbierania połączenia czy odblokowywania urządzenia.
Do tej pory te krótkie wiadomości były zawsze obsługiwane przez domyślną aplikację do obsługi wiadomości. Teraz każda aplikacja może zadeklarować swoją zdolność do obsługi tych wiadomości, tworząc Service
z filtrem intencji dla ACTION_RESPOND_VIA_MESSAGE
.
Gdy użytkownik odpowie szybką odpowiedzią na połączenie przychodzące, aplikacja Telefon wysyła intencję ACTION_RESPOND_VIA_MESSAGE
z identyfikatorem URI opisującym odbiorcę (rozmówcę) i dodatkowo EXTRA_TEXT
z wiadomością, którą użytkownik chce wysłać. Gdy usługa otrzyma intencję, powinna przekazać komunikat i natychmiast się zatrzymać (aplikacja nie powinna pokazywać aktywności).
Aby otrzymać tę intencję, musisz zadeklarować uprawnienie SEND_RESPOND_VIA_MESSAGE
.
Multimedia
Ulepszenia MediaExtractor i MediaCodec
Android ułatwia teraz pisanie własnych odtwarzaczy z możliwością dynamicznego przesyłania strumieniowego przez HTTP (DASH) zgodnie ze standardem ISO/IEC 23009-1 przy użyciu istniejących interfejsów API w MediaCodec
i MediaExtractor
. Platforma stanowiąca podstawę tych interfejsów API została zaktualizowana, aby umożliwić analizowanie pofragmentowanych plików MP4, ale Twoja aplikacja nadal odpowiada za analizowanie metadanych MPD i przekazywanie poszczególnych strumieni do MediaExtractor
.
Jeśli chcesz używać DASH w przypadku zaszyfrowanych treści, zwróć uwagę na to, że metoda getSampleCryptoInfo()
zwraca metadane MediaCodec.CryptoInfo
opisujące strukturę każdej zaszyfrowanej próbki multimediów. Do usługi MediaExtractor
została też dodana metoda getPsshInfo()
, która umożliwia dostęp do metadanych PSSH dotyczących multimediów DASH.
Ta metoda zwraca mapowanie obiektów UUID
na bajty, gdzie UUID
określa schemat kryptograficzny, a bajty to dane właściwe dla tego schematu.
DRM multimediów
Nowa klasa MediaDrm
to modułowe rozwiązanie do zarządzania prawami cyfrowymi (DRM) do treści multimedialnych, dzięki czemu oddziela on problemy z zabezpieczeniami DRM od odtwarzania multimediów. Na przykład rozdzielenie interfejsów API umożliwia odtwarzanie treści zaszyfrowanych za pomocą Widevine bez konieczności używania formatu multimediów Widevine. To rozwiązanie DRM obsługuje też standard DASH Common Encryption, więc można używać różnych schematów DRM w przypadku strumieniowanych treści.
MediaDrm
umożliwia uzyskiwanie nieprzezroczystych komunikatów z żądaniem klucza i przetwarzanie wiadomości z odpowiedzią z serwera na potrzeby pozyskiwania i udostępniania licencji. Twoja aplikacja odpowiada za obsługę komunikacji sieciowej z serwerami. Klasa MediaDrm
umożliwia tylko generowanie i przetwarzanie wiadomości.
Interfejsy API MediaDrm
powinny być używane w połączeniu z interfejsami API MediaCodec
, które zostały wprowadzone w Androidzie 4.1 (poziom API 16), w tym z interfejsami MediaCodec
do kodowania i dekodowania treści, MediaCrypto
do obsługi zaszyfrowanych treści i MediaExtractor
do wyodrębniania i demuksowania treści.
Najpierw musisz utworzyć obiekty MediaExtractor
i MediaCodec
. Następnie możesz uzyskać dostęp do schematu DRM (UUID
), zwykle z poziomu metadanych w treści, i użyć go do utworzenia instancji obiektu MediaDrm
za pomocą jego konstruktora.
Kodowanie wideo z platformy
Do Androida 4.1 (poziom interfejsu API 16) dodano klasę MediaCodec
do niskopoziomowego kodowania i dekodowania treści multimedialnych. Podczas kodowania filmów Android 4.1 wymagał dostarczenia multimediów w tablicy ByteBuffer
, natomiast Android 4.3 pozwala teraz na użycie Surface
jako danych wejściowych kodera. Pozwala to na przykład zakodować dane wejściowe z istniejącego pliku wideo lub użyć klatek wygenerowanych przez OpenGL ES.
Aby użyć elementu Surface
jako danych wejściowych kodera, najpierw wywołaj configure()
dla MediaCodec
.
Następnie zadzwoń pod numer createInputSurface()
, aby otrzymać urządzenie Surface
, na którym możesz przesyłać multimedia.
Możesz na przykład użyć podanego Surface
jako okna dla kontekstu OpenGL, przekazując go do interfejsu eglCreateWindowSurface()
. Następnie podczas renderowania powierzchni wywołaj eglSwapBuffers()
, aby przekazać klatkę do elementu MediaCodec
.
Aby rozpocząć kodowanie, wywołaj start()
na urządzeniu MediaCodec
. Gdy skończysz, wywołaj signalEndOfInputStream()
, aby zakończyć kodowanie, i wywołaj metodę release()
na Surface
.
Powielanie multimediów
Nowa klasa MediaMuxer
umożliwia multipleksowanie między 1 strumieniem audio i 1 strumieniem wideo. Te interfejsy API służą jako odpowiedniki klasy MediaExtractor
dodanej w Androidzie 4.2 na potrzeby demultipleksowania multimediów.
Obsługiwane formaty wyjściowe są zdefiniowane w polu MediaMuxer.OutputFormat
. Obecnie jedynym obsługiwanym formatem wyjściowym jest MP4, a MediaMuxer
obsługuje tylko 1 strumień audio lub 1 strumień wideo naraz.
Komponent MediaMuxer
został opracowany głównie z myślą o współpracy z MediaCodec
, więc można przetwarzać filmy za pomocą MediaCodec
, a następnie zapisywać dane wyjściowe w pliku MP4 za pomocą MediaMuxer
. Możesz też używać MediaMuxer
w połączeniu z MediaExtractor
, aby edytować multimedia bez konieczności ich kodowania ani dekodowania.
Postęp odtwarzania i przewijanie dla RemoteControlClient
W Androidzie 4.0 (poziom interfejsu API 14) dodano RemoteControlClient
, aby umożliwić sterowanie odtwarzaniem multimediów z klientów zdalnych, np. elementy sterujące dostępne na ekranie blokady. Android 4.3 umożliwia teraz takim kontrolerom wyświetlanie pozycji odtwarzania i elementów sterujących do przeglądania odtwarzania. Jeśli do aplikacji multimedialnej masz włączone interfejsy API RemoteControlClient
, możesz zezwolić na przeglądanie treści przy odtwarzaniu, implementując dwa nowe interfejsy.
Najpierw musisz włączyć flagę FLAG_KEY_MEDIA_POSITION_UPDATE
, przekazując ją do setTransportControlsFlags()
.
Następnie zaimplementuj dwa nowe interfejsy:
RemoteControlClient.OnGetPlaybackPositionListener
- Obejmuje to wywołanie zwrotne
onGetPlaybackPosition()
, które żąda bieżącej pozycji multimediów, gdy pilot musi zaktualizować postęp w swoim interfejsie. RemoteControlClient.OnPlaybackPositionUpdateListener
- Obejmuje to wywołanie zwrotne
onPlaybackPositionUpdate()
, które informuje aplikację o nowym kodzie czasu multimediów, gdy użytkownik przewija odtwarzanie za pomocą interfejsu pilota.Po zmianie pozycji odtwarzania na nową pozycję wywołaj funkcję
setPlaybackState()
, aby wskazać nowy stan, pozycję i szybkość odtwarzania.
Po zdefiniowaniu tych interfejsów możesz ustawić je dla interfejsu RemoteControlClient
, wywołując odpowiednio metodę setOnGetPlaybackPositionListener()
i setPlaybackPositionUpdateListener()
.
Grafika
Obsługa OpenGL ES 3.0
Android 4.3 dodaje interfejsy Java i wbudowaną obsługę OpenGL ES 3.0. Najważniejsze nowe funkcje dostępne w OpenGL ES 3.0 to:
- Przyspieszenie rozwoju zaawansowanych efektów wizualnych
- Wysoka jakość kompresji tekstur ETC2/EAC jako funkcja standardowa
- Nowa wersja języka cieniowania GLSL ES z obsługą liczb całkowitych i 32-bitowych zmiennoprzecinkowych.
- Zaawansowane renderowanie tekstur
- Szersza standaryzacja rozmiaru tekstur i formatów bufora renderowania
Interfejs Java dla OpenGL ES 3.0 na Androidzie jest dostarczany z GLES30
.
Jeśli korzystasz z platformy OpenGL ES 3.0, zadeklaruj to w pliku manifestu za pomocą tagu <uses-feature> i atrybutu android:glEsVersion
. Na przykład:
<manifest> <uses-feature android:glEsVersion="0x00030000" /> ... </manifest>
Pamiętaj, aby określić kontekst OpenGL ES, wywołując setEGLContextClientVersion()
, przekazując 3
jako wersję.
Więcej informacji o korzystaniu z OpenGL ES, w tym o sprawdzaniu obsługiwanej wersji OpenGL ES w czasie działania urządzenia, znajdziesz w przewodniku po interfejsie API OpenGL ES.
Mipmappowanie elementów graficznych
Użycie mipmapy jako źródła bitmapy lub elementu z elementami rysunkowymi to prosty sposób na zapewnienie wysokiej jakości obrazu i różnych skal obrazów, co może być szczególnie przydatne, jeśli spodziewasz się, że obraz będzie skalowany podczas animacji.
Android 4.2 (poziom interfejsu API 17) dodał obsługę map mipmap w klasie Bitmap
– Android zamienia obrazy mip w Bitmap
, jeśli podasz źródło mipmap i włączysz funkcję setHasMipMap()
. Teraz w Androidzie 4.3 można włączyć mapy mipmaps także dla obiektu BitmapDrawable
, udostępniając zasób mipmap i ustawiając atrybut android:mipMap
w pliku zasobów bitmapy lub wywołując hasMipMap()
.
Interfejs
Wyświetl nakładki
Nowa klasa ViewOverlay
tworzy przezroczystą warstwę na elemencie View
, do której można dodawać treści wizualne. Nie ma ona wpływu na hierarchię układu. Aby uzyskać ViewOverlay
dla dowolnego elementu View
, zadzwoń pod numer getOverlay()
. Nakładka zawsze ma taki sam rozmiar i położenie jak widok hosta (widok, z którego została utworzona), dzięki czemu można dodawać treści widoczne przed widokiem hosta, ale które nie mogą wykraczać poza zakres tego widoku hosta.
Użycie właściwości ViewOverlay
jest szczególnie przydatne, gdy chcesz tworzyć animacje, np. wysuwać widok poza kontener lub przesuwać elementy po ekranie bez wpływu na hierarchię widoków. Ponieważ jednak użytkowy obszar nakładki jest ograniczony do tego samego obszaru co widok hosta, jeśli chcesz animować widok, który wykracza poza swoją pozycję w układzie, musisz użyć nakładki z widoku nadrzędnego, który ma wyznaczone granice układu.
Podczas tworzenia nakładki dla widoku widżetu, np. Button
, możesz dodać do nakładki obiekty Drawable
, wywołując add(Drawable)
. Jeśli wywołasz getOverlay()
w przypadku widoku układu, takiego jak RelativeLayout
, zwrócony obiekt to ViewGroupOverlay
. Klasa ViewGroupOverlay
jest podklasą klasy ViewOverlay
, która także umożliwia dodawanie obiektów View
przez wywołanie add(View)
.
Uwaga: wszystkie elementy, które można rysować i widoki, które dodajesz do nakładki, mają charakter wyłącznie wizualny. Nie mogą odbierać zdarzeń skupienia ani wprowadzania danych.
Na przykład poniższy kod animuje widok przesuwany w prawo przez umieszczenie go w nakładce widoku nadrzędnego, a następnie wykonanie w nim animacji przesunięcia:
Kotlin
val view: View? = findViewById(R.id.view_to_remove) val container: ViewGroup? = view?.parent as ViewGroup container?.apply { overlay.add(view) ObjectAnimator.ofFloat(view, "translationX", right.toFloat()) .start() }
Java
View view = findViewById(R.id.view_to_remove); ViewGroup container = (ViewGroup) view.getParent(); container.getOverlay().add(view); ObjectAnimator anim = ObjectAnimator.ofFloat(view, "translationX", container.getRight()); anim.start();
Układ granic optycznych
W przypadku widoków zawierających 9 poprawek obrazu tła możesz teraz określić, że powinny być one wyrównane z sąsiadującymi widokami na podstawie „optycznych” granic obrazu tła, a nie granic obrazu tła.
Na przykład rysunki 1 i 2 przedstawiają ten sam układ, ale w wersji na ilustracji 1 obowiązują granice klipu (działanie domyślne), a na ilustracji 2 – granice optyczne. Obrazy z dziewięcioma elementami używanymi w przypadku przycisku i ramki na zdjęcia zawierają dopełnienie wokół krawędzi, dlatego nie będą one wyrównane względem siebie ani tekstu podczas korzystania z granic klipu.
Uwaga: na zrzucie ekranu na rysunkach 1 i 2 włączone jest ustawienie programisty „Pokaż granice układu”. Czerwone linie oznaczają granice optyczne, niebieskie linie – granice klipu, a różowe – marginesy.
Aby wyrównać widoki na podstawie ich granic optycznych, ustaw wartość atrybutu android:layoutMode
na "opticalBounds"
w jednym z układów nadrzędnych. Na przykład:
<LinearLayout android:layoutMode="opticalBounds" ... >
Aby tak się stało, obrazy dziewięciu punktów zastosowane do tła widoków muszą określać granice optyczne za pomocą czerwonych linii wzdłuż dolnej i prawej strony pliku z dziewięcioma poprawkami (jak pokazano na ilustracji 3). Czerwone linie wskazują obszar, który powinien zostać odjęty od granic klipu, pozostawiając w ten sposób optyczne granice obrazu.
Gdy włączysz progi optyczne dla elementu ViewGroup
w układzie, wszystkie widoki podrzędne będą dziedziczyć tryb układu granic optycznych, chyba że zastąpisz go dla grupy, ustawiając android:layoutMode
na "clipBounds"
. Wszystkie elementy układu również uwzględniają optyczne granice widoków danych dziecka, dostosowując własne granice na podstawie optycznych granic znajdujących się w nich widoków. Jednak elementy układu (podklasy ViewGroup
) obecnie nie obsługują granic optycznych dla obrazów z dziewięcioma poprawkami zastosowanymi na własnym tle.
Jeśli utworzysz widok niestandardowy przez podklasyfikację View
, ViewGroup
lub ich dowolnej podklasy, widok odziedziczy te optyczne powiązania.
Uwaga: wszystkie widżety obsługiwane przez motyw Holo zostały zaktualizowane o granice optyczne, między innymi Button
, Spinner
i EditText
. Jeśli Twoja aplikacja stosuje motyw Holo (Theme.Holo
, Theme.Holo.Light
itp.), ustaw wartość atrybutu android:layoutMode
na "opticalBounds"
, aby od razu odnieść korzyści.
Aby określić progi optyczne dla własnych dziewięciu punktów na zdjęciach za pomocą narzędzia Rysuj 9-patch, klikaj przyciski obramowania, przytrzymując klawisz Ctrl.
Animacja wartości prostokątnych
Dzięki nowej funkcji RectEvaluator
możesz teraz animować pomiędzy 2 wartościami parametru Rect
. Ta nowa klasa to implementacja TypeEvaluator
, którą możesz przekazać do zajęć ValueAnimator.setEvaluator()
.
Dołączaj okna i ustawiaj ostrość
Wcześniej, aby nasłuchiwać, kiedy widok został dołączony lub odłączony od okna lub gdy jego zaznaczenie uległo zmianie, trzeba było zastąpić klasę View
, aby zaimplementować odpowiednio onAttachedToWindow()
i onDetachedFromWindow()
lub onWindowFocusChanged()
.
Aby odbierać zdarzenia dołączania i odłączania, możesz zamiast tego zaimplementować ViewTreeObserver.OnWindowAttachListener
i ustawić go w widoku danych za pomocą addOnWindowAttachListener()
.
Aby otrzymywać zdarzenia skupienia, możesz wdrożyć funkcję ViewTreeObserver.OnWindowFocusChangeListener
i ustawić ją w widoku danych za pomocą addOnWindowFocusChangeListener()
.
Obsługa nadmiarowego skanowania sygnału telewizyjnego
Aby mieć pewność, że aplikacja wypełnia cały ekran każdego telewizora, możesz włączyć nadmiarowość obrazu w układzie aplikacji. Tryb nadmiarowego skanowania jest określany za pomocą flagi FLAG_LAYOUT_IN_OVERSCAN
, którą można włączyć za pomocą motywów platformy, takich jak Theme_DeviceDefault_NoActionBar_Overscan
, lub stylu windowOverscan
w motywie niestandardowym.
Orientacja ekranu
Atrybut screenOrientation
w tagu <activity>
obsługuje teraz dodatkowe wartości zgodne z preferencją użytkownika dotyczącą automatycznej rotacji:
"userLandscape"
- Działa tak samo jak
"sensorLandscape"
, chyba że użytkownik wyłączy autoobracanie, zablokuje się w normalnej orientacji poziomej i nie odwraca. "userPortrait"
- Działa tak samo jak
"sensorPortrait"
, ale jeśli użytkownik wyłączy autoobracanie, obraz zostanie zablokowany w normalnej orientacji pionowej i nie będzie odwracany. "fullUser"
- Działa tak samo jak
"fullSensor"
i umożliwia obrót we wszystkich 4 kierunkach, chyba że użytkownik wyłączy autoobracanie, ekran zostanie zablokowany w preferowanej orientacji użytkownika.
Oprócz tego możesz też zadeklarować, że "locked"
blokuje orientację ekranu w aplikacji.
Animacje obrotu
Nowe pole rotationAnimation
w WindowManager
umożliwia wybór jednej z 3 animacji, które mają być używane, gdy system zmieni orientację ekranu. Te 3 animacje to:
Uwaga: te animacje są dostępne tylko wtedy, gdy dla aktywności ustawisz tryb pełnoekranowy, który można włączyć przy użyciu motywów, takich jak Theme.Holo.NoActionBar.Fullscreen
.
Animację „przenikanie” można włączyć na przykład w ten sposób:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val params: WindowManager.LayoutParams = window.attributes params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE window.attributes = params ... }
Java
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); WindowManager.LayoutParams params = getWindow().getAttributes(); params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE; getWindow().setAttributes(params); ... }
Dane wejściowe użytkownika
Nowe typy czujników
Nowy czujnik TYPE_GAME_ROTATION_VECTOR
umożliwia wykrywanie obrotów urządzenia bez obaw o zakłócenia magnetyczne. W przeciwieństwie do czujnika TYPE_ROTATION_VECTOR
wskazówka TYPE_GAME_ROTATION_VECTOR
nie jest kierowana na północ magnetyczną.
Nowe czujniki TYPE_GYROSCOPE_UNCALIBRATED
i TYPE_MAGNETIC_FIELD_UNCALIBRATED
dostarczają nieprzetworzone dane z czujnika bez uwzględniania szacowanego odchylenia. Oznacza to, że istniejące czujniki TYPE_GYROSCOPE
i TYPE_MAGNETIC_FIELD
dostarczają dane z czujników, które uwzględniają szacowane odchylenie pochodzące odpowiednio z dryfu żyroskopu i twardego żelaza. Nowe „nieskalibrowane” wersje tych czujników dostarczają natomiast nieprzetworzone dane z czujników i osobno przedstawiają szacowane wartości odchylenia. Czujniki te umożliwiają Ci własną, niestandardową kalibrację danych z czujników przez wzmacnianie szacowanego odchylenia za pomocą danych zewnętrznych.
Odbiornik powiadomień
Android 4.3 dodaje nową klasę usługi NotificationListenerService
, która umożliwia aplikacji otrzymywanie informacji o nowych powiadomieniach publikowanych przez system.
Jeśli Twoja aplikacja korzysta obecnie z interfejsów API usługi ułatwień dostępu do uzyskiwania dostępu do powiadomień systemowych, zaktualizuj ją tak, aby używała tych interfejsów API.
dostawca kontaktów
Zapytanie o „kontakty”
Nowe zapytanie dotyczące dostawcy kontaktów (Contactables.CONTENT_URI
) pozwala skutecznie uzyskać dane Cursor
zawierające wszystkie adresy e-mail i numery telefonów należące do wszystkich kontaktów pasujących do podanego zapytania.
Zapytanie o delta kontaktów
Do dostawcy kontaktów dodano nowe interfejsy API, które umożliwiają sprawne wykonywanie zapytań dotyczących ostatnich zmian w danych kontaktów. Wcześniej aplikacja mogła otrzymywać powiadomienia o zmianach w danych kontaktów, ale nie wiadomo było, co dokładnie się zmieniło. Aby wykryć zmiany, konieczne było pobranie wszystkich kontaktów, a następnie ich przejrzenie.
Aby śledzić zmiany dotyczące wstawek i aktualizacji, możesz teraz uwzględnić w wyborze parametr CONTACT_LAST_UPDATED_TIMESTAMP
, aby wysyłać zapytania tylko o kontakty, które zmieniły się od czasu ostatniego zapytania o dostawcę.
Aby śledzić usunięte kontakty, nowa tabela ContactsContract.DeletedContacts
zawiera dziennik usuniętych kontaktów (ale przez ograniczony czas każdy usunięty kontakt jest przechowywany w tej tabeli). Podobnie jak w przypadku CONTACT_LAST_UPDATED_TIMESTAMP
możesz użyć nowego parametru wyboru (CONTACT_DELETED_TIMESTAMP
), aby sprawdzić, które kontakty zostały usunięte od czasu ostatniego zapytania o dostawcę. Tabela zawiera też stałą DAYS_KEPT_MILLISECONDS
, która określa liczbę dni (w milisekundach), przez które dziennik ma być przechowywany.
Dodatkowo dostawca kontaktów rozpowszechnia teraz działanie CONTACTS_DATABASE_CREATED
, gdy użytkownik wyczyści pamięć kontaktów w menu ustawień systemu, co skutecznie odtworzy bazę danych dostawcy kontaktów. Ma na celu sygnalizowanie aplikacjom, że muszą usunąć wszystkie zapisane informacje kontaktowe i załadować je ponownie za pomocą nowego zapytania.
Przykładowy kod korzystający z tych interfejsów API do sprawdzania zmian w kontaktach znajdziesz w przykładzie interfejsu API, który znajdziesz w pobranym pliku SDK Sample.
Tłumaczenie
Ulepszona obsługa tekstu dwukierunkowego
Poprzednie wersje Androida obsługują języki i układy tekstu od prawej do lewej, ale czasem nie obsługują poprawnie tekstu w różnych kierunkach. Dlatego w Androidzie 4.3 do Androida 4.3 dodane są interfejsy API BidiFormatter
, które ułatwiają prawidłowe formatowanie tekstu z treściami w odwrotnym kierunku bez zniekształcania żadnych jego elementów.
Jeśli na przykład chcesz utworzyć zdanie ze zmienną w postaci ciągu znaków, np. „Czy chodziło Ci o 15 Bay Street, Laurel, CA?”, zwykle przekazujesz zasób zlokalizowanego ciągu znaków i zmienną do String.format()
:
Kotlin
val suggestion = String.format(resources.getString(R.string.did_you_mean), address)
Java
Resources res = getResources(); String suggestion = String.format(res.getString(R.string.did_you_mean), address);
Jeśli jednak język to hebrajski, sformatowany ciąg znaków będzie wyglądać tak:
PLACEHOLDER PLACEHOLDER 電כויlar ל 15 Bay Street, Laurel, Kalifornia?
To nie jest dobra odpowiedź, ponieważ cyfra „15” powinna być na lewo od „Bay Street”. Rozwiązaniem jest użycie metody BidiFormatter
i jej metody unicodeWrap()
. Na przykład powyższy kod stanie się taki:
Kotlin
val bidiFormatter = BidiFormatter.getInstance() val suggestion = String.format( resources.getString(R.string.did_you_mean), bidiFormatter.unicodeWrap(address) )
Java
Resources res = getResources(); BidiFormatter bidiFormatter = BidiFormatter.getInstance(); String suggestion = String.format(res.getString(R.string.did_you_mean), bidiFormatter.unicodeWrap(address));
Domyślnie unicodeWrap()
używa heurystyki szacowania pierwszej wartości kierunkowej, która może powodować błędy, jeśli pierwszy sygnał kierunku tekstu nie odzwierciedla właściwego kierunku dla całej treści.
Jeśli to konieczne, możesz określić inną metodę heurystyczną, przekazując jedną ze stałych TextDirectionHeuristic
z parametru TextDirectionHeuristics
do unicodeWrap()
.
Uwaga: te nowe interfejsy API są też dostępne dla poprzednich wersji Androida za pomocą biblioteki pomocy Androida wraz z klasą BidiFormatter
i powiązanymi interfejsami API.
Usługi ułatwień dostępu
Obsługa kluczowych zdarzeń
AccessibilityService
może teraz za pomocą metody onKeyEvent()
odbierać wywołanie zwrotne dla kluczowych zdarzeń wejściowych. Dzięki temu usługa ułatwień dostępu może obsługiwać wprowadzanie danych z urządzeń wejściowych obsługujących klawisze, takich jak klawiatura, i przekładać te zdarzenia na działania specjalne, które wcześniej były możliwe tylko przy użyciu dotyku lub pada kierunkowego urządzenia.
Zaznaczanie tekstu i kopiowanie/wklejanie
AccessibilityNodeInfo
udostępnia teraz interfejsy API, które pozwalają AccessibilityService
na wybieranie, wycinanie, kopiowanie i wklejanie tekstu w węźle.
Aby określić wybór tekstu do wycięcia lub skopiowania, usługa ułatwień dostępu może użyć nowego działania (ACTION_SET_SELECTION
), przekazując wraz z nim pozycję początkową i końcową zaznaczenia za pomocą elementów ACTION_ARGUMENT_SELECTION_START_INT
i ACTION_ARGUMENT_SELECTION_END_INT
.
Tekst możesz też zaznaczyć, zmieniając pozycję kursora za pomocą dotychczasowej czynności ACTION_NEXT_AT_MOVEMENT_GRANULARITY
(wcześniej tylko w celu przesuwania kursora) i dodając argument ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
.
Następnie możesz wyciąć lub skopiować tekst za pomocą ACTION_CUT
, ACTION_COPY
, a później wkleić za pomocą ACTION_PASTE
.
Uwaga: te nowe interfejsy API są też dostępne dla poprzednich wersji Androida za pomocą biblioteki pomocy Androida z klasą AccessibilityNodeInfoCompat
.
Deklarowanie ułatwień dostępu
Począwszy od Androida 4.3, usługa ułatwień dostępu musi zadeklarować funkcje ułatwień dostępu w swoim pliku metadanych, aby można było używać określonych ułatwień dostępu. Jeśli plik metadanych nie wymaga takiej możliwości, funkcja nie będzie działać. Aby zadeklarować ułatwienia dostępu w swojej usłudze, musisz użyć atrybutów XML, które odpowiadają różnym stałym „możliwości” w klasie AccessibilityServiceInfo
.
Jeśli na przykład usługa nie żąda możliwości flagRequestFilterKeyEvents
, nie otrzyma kluczowych zdarzeń.
Testowanie i debugowanie
Automatyczne testowanie interfejsu
Nowa klasa UiAutomation
udostępnia interfejsy API umożliwiające symulowanie działań użytkowników na potrzeby automatyzacji testów. Dzięki interfejsom API AccessibilityService
na platformie interfejsy API UiAutomation
umożliwiają sprawdzanie zawartości ekranu i wstrzykiwanie dowolnych zdarzeń dotyku i klawiatury.
Aby pobrać wystąpienie typu UiAutomation
, wywołaj Instrumentation.getUiAutomation()
. Aby to zadziałało, musisz podać opcję -w
w poleceniu instrument
podczas uruchamiania InstrumentationTestCase
z adb shell
.
W instancji UiAutomation
możesz uruchamiać dowolne zdarzenia do przetestowania, wywołując metodę executeAndWaitForEvent()
, przekazując jej żądanie Runnable
, czas oczekiwania na operację i implementację interfejsu UiAutomation.AccessibilityEventFilter
. W ramach implementacji UiAutomation.AccessibilityEventFilter
otrzymasz wywołanie umożliwiające filtrowanie interesujących Cię zdarzeń i określenie powodzenia lub niepowodzenia danego przypadku testowego.
Aby obserwować wszystkie zdarzenia podczas testu, utwórz implementację UiAutomation.OnAccessibilityEventListener
i przekaż ją do interfejsu setOnAccessibilityEventListener()
.
Za każdym razem, gdy wystąpi zdarzenie, interfejs detektora otrzymuje wywołanie onAccessibilityEvent()
i otrzymuje obiekt AccessibilityEvent
, który opisuje zdarzenie.
Interfejsy UiAutomation
API udostępniają wiele innych operacji na bardzo niskim poziomie, aby zachęcić do opracowania narzędzi testowych UI, takich jak uiautomator. UiAutomation
może też na przykład:
- Wstrzyknij zdarzenia wejściowe
- Zmień orientację ekranu
- wykonać zrzut ekranu,
Co najważniejsze w przypadku narzędzi do testowania interfejsu użytkownika interfejsy API UiAutomation
działają poza granice aplikacji, w przeciwieństwie do tych w Instrumentation
.
Zdarzenia Systrace w aplikacjach
Android 4.3 dodaje klasę Trace
z 2 metodami statycznymi: beginSection()
i endSection()
, które umożliwiają definiowanie bloków kodu, które mają być dołączane do raportu systrace. Tworząc w aplikacji sekcje kodu możliwego do śledzenia, logi systrace dostarczają znacznie bardziej szczegółowej analizy miejsc, w których następuje spowolnienie w aplikacji.
Więcej informacji o korzystaniu z narzędzia Systrace znajdziesz w artykule Analizowanie wyświetlania i skuteczności w Systrace.
Zabezpieczenia
Magazyn kluczy Android na potrzeby kluczy prywatnych aplikacji
Android oferuje teraz w usłudze KeyStore
niestandardowy dostawca zabezpieczeń Java o nazwie Android Key Store. Umożliwia on generowanie i zapisywanie kluczy prywatnych, które mogą być widoczne i używane tylko przez Twoją aplikację. Aby wczytać magazyn kluczy Android, przekaż polecenie "AndroidKeyStore"
na adres KeyStore.getInstance()
.
Aby zarządzać prywatnymi danymi logowania do aplikacji w magazynie kluczy Android, wygeneruj nowy klucz za pomocą funkcji KeyPairGenerator
i KeyPairGeneratorSpec
. Najpierw pobierz instancję KeyPairGenerator
, wywołując getInstance()
. Następnie wywołaj polecenie initialize()
, przekazując mu wystąpienie KeyPairGeneratorSpec
, które możesz uzyskać, używając polecenia KeyPairGeneratorSpec.Builder
.
Wreszcie możesz odebrać KeyPair
, dzwoniąc pod numer generateKeyPair()
.
Magazyn danych logowania do sprzętu
Android obsługuje teraz także sprzętowe przechowywanie danych logowania w KeyChain
, co zwiększa bezpieczeństwo, ponieważ uniemożliwia wyodrębnianie kluczy. Oznacza to, że jeśli klucze znajdują się w sprzętowym magazynie kluczy (Secure Element, TPM lub TrustZone), można ich używać do operacji kryptograficznych, ale nie można eksportować materiału klucza prywatnego. Nawet jądro systemu operacyjnego
nie ma dostępu do tego materiału klucza. Chociaż nie wszystkie urządzenia z Androidem obsługują pamięć masową, możesz w czasie działania sprawdzić, czy pamięć sterowana sprzętowo jest dostępna, wywołując stronę KeyChain.IsBoundKeyAlgorithm()
.
Deklaracje w pliku manifestu
Wymagane funkcje, które można zadeklarować
Poniższe wartości są teraz obsługiwane w elemencie <uses-feature>
, dzięki czemu możesz mieć pewność, że aplikacja będzie instalowana tylko na urządzeniach, które obsługują funkcje, których potrzebuje.
FEATURE_APP_WIDGETS
- Deklaruje, że aplikacja zawiera widżet aplikacji i powinna być zainstalowana tylko na urządzeniach z ekranem głównym lub w podobnym miejscu, w którym użytkownicy mogą umieszczać widżety aplikacji.
Przykład:
<uses-feature android:name="android.software.app_widgets" android:required="true" />
FEATURE_HOME_SCREEN
- Deklaruje, że aplikacja działa jako zamiennik ekranu głównego i powinna być instalowana tylko na urządzeniach, które obsługują aplikacje na ekranie głównym innych firm.
Przykład:
<uses-feature android:name="android.software.home_screen" android:required="true" />
FEATURE_INPUT_METHODS
- Deklaruje, że aplikacja udostępnia niestandardową metodę wprowadzania (klawiaturę wbudowaną w
InputMethodService
) i powinna być zainstalowana wyłącznie na urządzeniach, które obsługują metody wprowadzania innych firm. Przykład:<uses-feature android:name="android.software.input_methods" android:required="true" />
FEATURE_BLUETOOTH_LE
- Deklaruje, że aplikacja korzysta z interfejsów API Bluetooth Low Energy i powinna być instalowana tylko na urządzeniach, które mogą komunikować się z innymi urządzeniami przez Bluetooth Low Energy.
Przykład:
<uses-feature android:name="android.software.bluetooth_le" android:required="true" />
Uprawnienia użytkownika
Poniższe wartości są teraz obsługiwane w <uses-permission>
w celu zadeklarowania uprawnień wymaganych przez aplikację do uzyskania dostępu do określonych interfejsów API.
BIND_NOTIFICATION_LISTENER_SERVICE
- Wymagane do korzystania z nowych interfejsów API
NotificationListenerService
. SEND_RESPOND_VIA_MESSAGE
- Wymagane do uzyskania intencji
ACTION_RESPOND_VIA_MESSAGE
.
Szczegółowy widok wszystkich zmian w interfejsach API w Androidzie 4.3 znajdziesz w raporcie Różnice w interfejsie API.