W tym dokumencie opisano podstawowe zadania związane z NFC, które wykonuje się na Androidzie. Wyjaśniono w nim, jak wysyłać i odbierać dane NFC w postaci wiadomości NDEF, oraz opisujemy interfejsy Android Framework API, które obsługują te funkcje. Bardziej zaawansowane tematy, w tym omówienie pracy z danymi innymi niż NDEF, znajdziesz w sekcji Zaawansowane opcje NFC.
Są 2 główne przypadki użycia danych NDEF i Androida:
- Odczytywanie danych NDEF z tagu NFC
- Przesyłanie wiadomości NDEF z jednego urządzenia do drugiego za pomocą Android BeamTM
Odczytywanie danych NDEF z tagu NFC jest obsługiwane przez system wysyłania tagów, który analizuje wykryte tagi NFC, odpowiednio je kategoryzuje i uruchamia aplikację, która jest zainteresowana odpowiednimi danymi. Aplikacja, która chce obsługiwać zeskanowany tag NFC, może zadeklarować filtr intencji i poprosić o obsługę danych.
Funkcja Android BeamTM pozwala urządzeniu przekazać wiadomość NDEF na inne urządzenie przez fizyczne złączenie ich ze sobą. Taka interakcja ułatwia wysyłanie danych niż przy użyciu innych technologii bezprzewodowych, takich jak Bluetooth, ponieważ przy użyciu NFC nie trzeba ręcznie wykrywać ani parowania urządzeń. Połączenie rozpoczyna się automatycznie, gdy dwa urządzenia znajdują się w zasięgu. Funkcja Android Beam jest dostępna przez zestaw interfejsów API NFC, więc każda aplikacja może przesyłać informacje między urządzeniami. Na przykład aplikacje Kontakty, Przeglądarka i YouTube korzystają z Android Beam do udostępniania kontaktów, stron internetowych i filmów innym urządzeniom.
System wysyłania tagów
Urządzenia z Androidem szukają tagów NFC, gdy ekran jest odblokowany, chyba że komunikacja NFC jest wyłączona w menu ustawień. Gdy urządzenie z Androidem wykryje tag NFC, pożądane zachowanie polega na tym, aby najbardziej odpowiednia aktywność obsługiwała intencję, bez pytania użytkownika o to, jakiej aplikacji ma użyć. Urządzenia skanują tagi NFC z bardzo małego zakresu, więc zachęcenie użytkowników do ręcznego wybrania aktywności może zmusić użytkownika do odsunięcia urządzenia od tagu i zerwania połączenia. Rozwiń aktywność w taki sposób, aby obsługiwała tylko te tagi NFC, które są istotne dla Twojej aktywności, tak aby selektor aktywności nie był wyświetlany.
Aby Ci w tym pomóc, Android udostępnia specjalny system wysyłania tagów, który analizuje zeskanowane tagi NFC, analizuje je i próbuje znaleźć aplikacje zainteresowane zeskanowanymi danymi. Realizuje to:
- Analiza tagu NFC i określenie typu MIME lub identyfikatora URI identyfikującego ładunek danych w tagu.
- Umieszczanie w intencji typu MIME lub identyfikatora URI oraz ładunku. Te 2 pierwsze kroki opisaliśmy w sekcji Jak tagi NFC są mapowane na typy MIME i identyfikatory URI.
- Uruchamia działanie na podstawie intencji. Zostało to opisane w artykule Jak tagi NFC są wysyłane do aplikacji.
Jak tagi NFC są mapowane na typy MIME i identyfikatory URI
Zanim zaczniesz pisać aplikacje do NFC, zapoznaj się z różnymi rodzajami tagów NFC, sposobem analizowania tych tagów przez system wysyłania tagów i specjalną pracą, jaką system wysyłania tagów wykonuje w przypadku wykrycia komunikatu NDEF. Tagi NFC mają szeroką gamę technologii i można w nich zapisywać dane na wiele różnych sposobów. Android zapewnia największą obsługę standardu NDEF zdefiniowanego na Forum NFC.
Dane NDEF są zawarte w wiadomości (NdefMessage
) zawierającej co najmniej 1 rekord (NdefRecord
). Każdy rekord NDEF musi być poprawnie sformatowany zgodnie ze specyfikacją typu rekordu, który chcesz utworzyć. Android obsługuje też inne typy tagów niezawierające danych NDEF, z którymi możesz pracować, używając klas w pakiecie android.nfc.tech
. Więcej informacji o tych technologiach znajdziesz w sekcji Zaawansowane komunikację NFC. Praca z tymi innymi typami tagów wymaga napisania własnego stosu protokołów do komunikacji z tagami, dlatego zalecamy używanie NDEF, jeśli to możliwe, aby łatwiej je programować i zapewnić maksymalną obsługę urządzeń z Androidem.
Uwaga: aby pobrać pełne specyfikacje NDEF, wejdź na stronę NFC Forum Specifications & Application Documents i przeczytaj artykuł Tworzenie popularnych typów rekordów NDEF, aby zapoznać się z przykładami tworzenia rekordów NDEF.
Gdy już wiesz, jak działają tagi NFC, przeczytaj bardziej szczegółowe informacje w sekcjach poniżej, które szczegółowo opisują sposób, w jaki Android obsługuje tagi w formacie NDEF. Kiedy urządzenie z Androidem skanuje tag NFC zawierający dane w formacie NDEF, analizuje wiadomość i próbuje określić typ MIME danych lub identyfikator URI danych. W tym celu system odczytuje pierwsze NdefRecord
w obrębie NdefMessage
, aby określić, jak interpretować cały komunikat NDEF (wiadomość NDEF może mieć wiele rekordów NDEF). Prawidłowo skonstruowana wiadomość NDEF zawiera pierwsze NdefRecord
z tymi polami:
- 3-bitowy TNF (format nazwy typu)
- Wskazuje sposób interpretacji pola typu zmiennej długości. Prawidłowe wartości są opisane w tabeli 1.
- Rodzaj zmiennej długości
- Opisuje typ rekordu. Jeśli używasz
TNF_WELL_KNOWN
, wpisz w tym polu definicję typu rekordu (RTD). Prawidłowe wartości RTD zostały opisane w tabeli 2. - Identyfikator zmiennej długości
- Unikalny identyfikator rekordu. To pole jest rzadko używane, ale jeśli chcesz jednoznacznie zidentyfikować tag, możesz utworzyć dla niego identyfikator.
- Ładunek o zmiennej długości
- Rzeczywisty ładunek danych, który chcesz odczytać lub zapisać. Wiadomość NDEF może zawierać wiele rekordów NDEF, dlatego nie zakładaj, że cały ładunek znajduje się w pierwszym rekordzie wiadomości NDEF.
System wysyłania tagów korzysta z pól TNF i typów, aby zmapować typ MIME lub identyfikator URI na wiadomość NDEF. Jeśli operacja się uda, umieszcza te informacje w intencji ACTION_NDEF_DISCOVERED
wraz z rzeczywistym ładunkiem. Są jednak sytuacje, w których system wysyłania tagów nie może określić typu danych na podstawie pierwszego rekordu NDEF. Dzieje się tak, gdy danych NDEF nie można zmapować na typ MIME lub identyfikator URI albo gdy tag NFC nie zawiera na początku danych NDEF. W takich przypadkach obiekt Tag
z informacjami o technologiach tagu i ładunku jest umieszczany w intencji ACTION_TECH_DISCOVERED
.
Tabela 1 zawiera informacje o tym, jak system wysyłania tagów mapuje pola TNF i typów na typy MIME lub identyfikatory URI. Opisuje też, których plików TNF nie można zmapować na typ MIME lub identyfikator URI.
W takich przypadkach system wysyłania tagów może wrócić do ACTION_TECH_DISCOVERED
.
Jeśli na przykład system wysyłania tagów napotka rekord typu TNF_ABSOLUTE_URI
, zmapuje pole typu zmiennej długości tego rekordu na identyfikator URI. System wysyłania tagów umieszcza ten identyfikator URI w polu danych intencji ACTION_NDEF_DISCOVERED
wraz z innymi informacjami o tagu, takimi jak ładunek. Z drugiej strony, jeśli trafi na rekord typu TNF_UNKNOWN
, tworzy intencję, która obejmuje zamiast tego technologie tagu.
Format nazwy typu (TNF) | Mapowanie |
---|---|
TNF_ABSOLUTE_URI |
Identyfikator URI zależnie od pola typu. |
TNF_EMPTY |
Zmniejsza się do ACTION_TECH_DISCOVERED . |
TNF_EXTERNAL_TYPE |
Identyfikator URI oparty na identyfikatorze URN w polu typu. Identyfikator URN jest kodowany w polu typu NDEF w skróconej formie: <domain_name>:<service_name> .
Android mapuje to na identyfikator URI w formularzu: vnd.android.nfc://ext/<domain_name>:<service_name> . |
TNF_MIME_MEDIA |
Typ MIME w zależności od pola typu. |
TNF_UNCHANGED |
Nieprawidłowy w pierwszym rekordzie, dlatego korzysta z ACTION_TECH_DISCOVERED . |
TNF_UNKNOWN |
Zmniejsza się do ACTION_TECH_DISCOVERED . |
TNF_WELL_KNOWN |
Typ MIME lub identyfikator URI zależą od definicji typu rekordu (RTD) ustawionej w polu typu. Więcej informacji o dostępnych komunikatach RTD i ich mapowaniach znajdziesz w tabeli 2. |
Definicja typu rekordu (RTD) | Mapowanie |
---|---|
RTD_ALTERNATIVE_CARRIER |
Zmniejsza się do ACTION_TECH_DISCOVERED . |
RTD_HANDOVER_CARRIER |
Zmniejsza się do ACTION_TECH_DISCOVERED . |
RTD_HANDOVER_REQUEST |
Zmniejsza się do ACTION_TECH_DISCOVERED . |
RTD_HANDOVER_SELECT |
Zmniejsza się do ACTION_TECH_DISCOVERED . |
RTD_SMART_POSTER |
Identyfikator URI na podstawie analizy ładunku. |
RTD_TEXT |
Typ MIME pliku text/plain . |
RTD_URI |
Identyfikator URI oparty na ładunku. |
Jak tagi NFC są wysyłane do aplikacji
Gdy system wysyłania tagów utworzy intencję obejmującą tag NFC i jego informacje identyfikujące, wysyła intencję do zainteresowanej aplikacji, która filtruje intencję. Jeśli więcej niż 1 aplikacja może obsłużyć intencję, wyświetlany jest selektor aktywności, aby użytkownik mógł wybrać aktywność. System wysyłania tagów definiuje 3 intencje, które są wymienione w kolejności od najwyższego do najniższego priorytetu:
-
ACTION_NDEF_DISCOVERED
: ta intencja służy do uruchamiania działania, gdy tag zawierający ładunek NDEF jest skanowany i ma rozpoznawany typ. Jest to intencja o najwyższym priorytecie, a system wysyłania tagów próbuje uruchamiać działanie z tą intencją w miarę możliwości przed jakąkolwiek inną intencją. ACTION_TECH_DISCOVERED
: jeśli nie są rejestrowane żadne działania obsługujące intencjęACTION_NDEF_DISCOVERED
, system wysyłania tagów próbuje uruchomić aplikację z tą intencją. Intencje są też uruchamiane bezpośrednio (nie zaczynając odACTION_NDEF_DISCOVERED
), jeśli skanowany tag zawiera dane NDEF, których nie można zmapować na typ MIME ani identyfikator URI, lub jeśli tag nie zawiera danych NDEF, ale korzysta ze znanej technologii tagów.ACTION_TAG_DISCOVERED
: ta intencja jest uruchamiana, jeśli żadna aktywność nie obsługuje intencjiACTION_NDEF_DISCOVERED
lubACTION_TECH_DISCOVERED
.
Podstawowy sposób działania systemu wysyłania tagów wygląda tak:
- Spróbuj rozpocząć działanie z intencją utworzoną przez system wysyłania tagów podczas analizowania tagu NFC (
ACTION_NDEF_DISCOVERED
lubACTION_TECH_DISCOVERED
). - Jeśli żadne aktywności nie są filtrowane pod kątem tej intencji, spróbuj uruchomić działanie o kolejnej intencji o najniższym priorytecie (
ACTION_TECH_DISCOVERED
lubACTION_TAG_DISCOVERED
), dopóki aplikacja nie przefiltruje intencji lub dopóki system wysyłania tagów nie wypróbuje wszystkich możliwych intencji. - Jeśli żadna aplikacja nie filtruje żadnej intencji, nie rób nic.
W miarę możliwości korzystaj z wiadomości NDEF i intencji ACTION_NDEF_DISCOVERED
, ponieważ jest to najbardziej precyzyjna z tych 3 komunikacji. Dzięki temu możesz uruchomić aplikację w odpowiednim momencie niż pozostałe 2 zamiary, co zapewni użytkownikowi lepsze wrażenia.
Poproś o dostęp do NFC w pliku manifestu Androida
Aby uzyskać dostęp do modułu NFC urządzenia i prawidłowo obsługiwać intencje NFC, w pliku AndroidManifest.xml
zadeklaruj te elementy:
- Element NFC
<uses-permission>
umożliwiający dostęp do sprzętu NFC:<uses-permission android:name="android.permission.NFC" />
- Minimalna wersja pakietu SDK, którą może obsługiwać Twoja aplikacja. Poziom API 9 obsługuje tylko ograniczone wysyłanie tagów przez
ACTION_TAG_DISCOVERED
i daje dostęp do wiadomości NDEF tylko za pomocą dodatkuEXTRA_NDEF_MESSAGES
. Nie są dostępne żadne inne właściwości tagów ani operacje wejścia-wyjścia. Poziom 10 interfejsu API obejmuje kompleksową obsługę czytnika i zapisu, a także przekazywanie na pierwszym planie funkcji push NDEF. Poziom 14 interfejsu API zapewnia łatwiejszy sposób przesyłania komunikatów NDEF na inne urządzenia za pomocą Android Beam oraz dodatkowe wygodne metody tworzenia rekordów NDEF.<uses-sdk android:minSdkVersion="10"/>
- Element
uses-feature
, dzięki któremu aplikacja pojawia się w Google Play tylko na urządzeniach wyposażonych w sprzęt NFC:<uses-feature android:name="android.hardware.nfc" android:required="true" />
Jeśli Twoja aplikacja korzysta z komunikacji NFC, ale jej działanie nie jest niezbędne, możesz pominąć element
uses-feature
i sprawdzić dostępność NFC w czasie działania, sprawdzając, czygetDefaultAdapter()
ma wartośćnull
.
Filtruj według intencji NFC
Aby uruchomić aplikację po zeskanowaniu tagu NFC, który ma być obsługiwany, może ona filtrować jedną, dwie lub wszystkie trzy intencje NFC w pliku manifestu Androida. Zwykle jednak warto odfiltrować intencję ACTION_NDEF_DISCOVERED
, aby uzyskać największą kontrolę nad czasem uruchamiania aplikacji. Intencja ACTION_TECH_DISCOVERED
jest zastępczą intencją ACTION_NDEF_DISCOVERED
, gdy nie ma filtra aplikacji dla ACTION_NDEF_DISCOVERED
lub gdy ładunek nie jest typu NDEF. Filtrowanie według kategorii ACTION_TAG_DISCOVERED
jest zwykle zbyt ogólne, aby można było filtrować według niego kategorię. Przed ACTION_TAG_DISCOVERED
wiele aplikacji filtruje dane pod kątem ACTION_NDEF_DISCOVERED
lub ACTION_TECH_DISCOVERED
, więc prawdopodobieństwo uruchomienia aplikacji jest niskie. Funkcja ACTION_TAG_DISCOVERED
jest dostępna w ostateczności tylko wtedy, gdy nie są zainstalowane żadne inne aplikacje obsługujące intencję ACTION_NDEF_DISCOVERED
ani ACTION_TECH_DISCOVERED
.
Nie zawsze jest to możliwe, dlatego w razie potrzeby możesz skorzystać z dwóch innych intencji, ponieważ wdrożenia tagów NFC są różne i często nie masz nad nimi kontroli. Jeśli masz kontrolę nad typami zapisywanych tagów i danych, zalecamy ich formatowanie za pomocą NDEF. W sekcjach poniżej dowiesz się, jak filtrować według poszczególnych typów intencji.
ACTION_NDEF_DISCOVERED
Aby filtrować intencje ACTION_NDEF_DISCOVERED
, zadeklaruj filtr intencji wraz z typem danych, według których chcesz filtrować. Oto przykładowe filtry dla intencji ACTION_NDEF_DISCOVERED
z typem MIME text/plain
:
<intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain" /> </intent-filter>
Poniżej znajduje się przykład filtra identyfikatora URI w postaci https://developer.android.com/index.html
.
<intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED"/> <category android:name="android.intent.category.DEFAULT"/> <data android:scheme="https" android:host="developer.android.com" android:pathPrefix="/index.html" /> </intent-filter>
ACTION_TECH_DISCOVERED
Jeśli Twoja aktywność filtruje intencję ACTION_TECH_DISCOVERED
, musisz utworzyć plik zasobów XML określający technologie obsługiwane przez Twoją aktywność w zestawie tech-list
. Twoja aktywność jest uznawana za dopasowanie, jeśli zbiór tech-list
należy do podzbioru technologii obsługiwanych przez tag, które można uzyskać, wywołując metodę getTechList()
.
Jeśli na przykład skanowany tag obsługuje MifareClassic, NdefFormatable i NfcA, zbiór tech-list
musi określać wszystkie 3, 2 lub jedną z nich (i niczego więcej), aby aktywność była dopasowywana.
Poniższy przykład zawiera wszystkie technologie. Musisz usunąć te, które nie są obsługiwane przez Twój tag NFC. Zapisz ten plik (możesz mu nadać dowolną nazwę) w folderze <project-root>/res/xml
.
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <tech-list> <tech>android.nfc.tech.IsoDep</tech> <tech>android.nfc.tech.NfcA</tech> <tech>android.nfc.tech.NfcB</tech> <tech>android.nfc.tech.NfcF</tech> <tech>android.nfc.tech.NfcV</tech> <tech>android.nfc.tech.Ndef</tech> <tech>android.nfc.tech.NdefFormatable</tech> <tech>android.nfc.tech.MifareClassic</tech> <tech>android.nfc.tech.MifareUltralight</tech> </tech-list> </resources>
Możesz też określić wiele zestawów tech-list
. Każdy zbiór tech-list
jest rozpatrywany niezależnie, a Twoja aktywność jest uznawana za pasującą, jeśli dowolny zbiór tech-list
jest podzbiorem technologii zwracanych przez funkcję getTechList()
. Zapewnia to semantykę AND
i OR
technologii dopasowywania. Poniższy przykład pasuje do tagów, które obsługują technologie NfcA i Ndef lub mogące obsługiwać technologie NfcB i Ndef:
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <tech-list> <tech>android.nfc.tech.NfcA</tech> <tech>android.nfc.tech.Ndef</tech> </tech-list> <tech-list> <tech>android.nfc.tech.NfcB</tech> <tech>android.nfc.tech.Ndef</tech> </tech-list> </resources>
W pliku AndroidManifest.xml
wskaż utworzony przed chwilą plik zasobów w elemencie <meta-data>
w elemencie <activity>
, jak w tym przykładzie:
<activity> ... <intent-filter> <action android:name="android.nfc.action.TECH_DISCOVERED"/> </intent-filter> <meta-data android:name="android.nfc.action.TECH_DISCOVERED" android:resource="@xml/nfc_tech_filter" /> ... </activity>
Więcej informacji o korzystaniu z technologii tagów i intencji ACTION_TECH_DISCOVERED
znajdziesz w sekcji Praca z obsługiwanymi technologiami tagów w dokumencie Zaawansowane NFC.
ACTION_TAG_DISCOVERED
Aby filtrować według kryterium ACTION_TAG_DISCOVERED
, użyj tego filtra intencji:
<intent-filter> <action android:name="android.nfc.action.TAG_DISCOVERED"/> </intent-filter>
Uzyskiwanie informacji z intencji
Jeśli działanie jest związane z intencją NFC, możesz uzyskać z niej informacje o zeskanowanym tagu NFC. W zależności od zeskanowanego tagu intencje mogą zawierać te dodatki:
EXTRA_TAG
(wymagany): obiektTag
reprezentujący zeskanowany tag.EXTRA_NDEF_MESSAGES
(opcjonalnie): tablica komunikatów NDEF wyodrębnionych z tagu. Ten dodatek jest wymagany w przypadku intencjiACTION_NDEF_DISCOVERED
.EXTRA_ID
(opcjonalnie): identyfikator niskiego poziomu tagu.
Aby uzyskać te dodatki, sprawdź, czy Twoja aktywność została uruchomiona za pomocą jednej z intencji NFC i czy tag został zeskanowany, a następnie pobierz dodatkowe elementy z intencji. W tym przykładzie sprawdzamy intencję ACTION_NDEF_DISCOVERED
i pobieramy komunikaty NDEF z dodatkowego intencji.
Kotlin
override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) ... if (NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action) { intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)?.also { rawMessages -> val messages: List<NdefMessage> = rawMessages.map { it as NdefMessage } // Process the messages array. ... } } }
Java
@Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); ... if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) { Parcelable[] rawMessages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); if (rawMessages != null) { NdefMessage[] messages = new NdefMessage[rawMessages.length]; for (int i = 0; i < rawMessages.length; i++) { messages[i] = (NdefMessage) rawMessages[i]; } // Process the messages array. ... } } }
Możesz też uzyskać z intencji obiekt Tag
, który będzie zawierać ładunek i umożliwi wyliczenie technologii tagu:
Kotlin
val tag: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
Java
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
Tworzenie popularnych typów rekordów NDEF
W tej sekcji opisujemy, jak tworzyć typowe typy rekordów NDEF, które pomogą Ci podczas zapisywania do tagów NFC lub wysyłania danych za pomocą Android Beam. Od Androida 4.0 (poziom interfejsu API 14) dostępna jest metoda createUri()
, która pomaga automatycznie tworzyć rekordy URI. Od Androida 4.1 (poziom interfejsu API 16) createExternal()
i createMime()
ułatwiają tworzenie rekordów MIME i typów zewnętrznych NDEF. W miarę możliwości używaj tych metod pomocniczych, aby uniknąć błędów podczas ręcznego tworzenia rekordów NDEF.
W tej sekcji opisujemy też, jak utworzyć odpowiedni filtr intencji dla rekordu. Wszystkie te przykłady rekordów NDEF powinny znajdować się w pierwszym rekordzie NDEF wiadomości NDEF, którą piszesz do tagu lub przesyłania.
TNF_ABSOLUTE_Identyfikator URI
Uwaga: zalecamy używanie typu RTD_URI
zamiast TNF_ABSOLUTE_URI
, ponieważ jest on skuteczniejszy.
Rekord NDEF TNF_ABSOLUTE_URI
możesz utworzyć w ten sposób:
Kotlin
val uriRecord = ByteArray(0).let { emptyByteArray -> NdefRecord( TNF_ABSOLUTE_URI, "https://developer.android.com/index.html".toByteArray(Charset.forName("US-ASCII")), emptyByteArray, emptyByteArray ) }
Java
NdefRecord uriRecord = new NdefRecord( NdefRecord.TNF_ABSOLUTE_URI , "https://developer.android.com/index.html".getBytes(Charset.forName("US-ASCII")), new byte[0], new byte[0]);
Filtr intencji dla poprzedniego rekordu NDEF wyglądałby tak:
<intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="https" android:host="developer.android.com" android:pathPrefix="/index.html" /> </intent-filter>
TNF_MIME_MEDIA
Rekord NDEF TNF_MIME_MEDIA
możesz utworzyć na te sposoby:
Przy użyciu metody createMime()
:
Kotlin
val mimeRecord = NdefRecord.createMime( "application/vnd.com.example.android.beam", "Beam me up, Android".toByteArray(Charset.forName("US-ASCII")) )
Java
NdefRecord mimeRecord = NdefRecord.createMime("application/vnd.com.example.android.beam", "Beam me up, Android".getBytes(Charset.forName("US-ASCII")));
Ręczne utworzenie NdefRecord
:
Kotlin
val mimeRecord = Charset.forName("US-ASCII").let { usAscii -> NdefRecord( NdefRecord.TNF_MIME_MEDIA, "application/vnd.com.example.android.beam".toByteArray(usAscii), ByteArray(0), "Beam me up, Android!".toByteArray(usAscii) ) }
Java
NdefRecord mimeRecord = new NdefRecord( NdefRecord.TNF_MIME_MEDIA , "application/vnd.com.example.android.beam".getBytes(Charset.forName("US-ASCII")), new byte[0], "Beam me up, Android!".getBytes(Charset.forName("US-ASCII")));
Filtr intencji dla poprzedniego rekordu NDEF wyglądałby tak:
<intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="application/vnd.com.example.android.beam" /> </intent-filter>
TNF_WELL_KNOWN z RTD_TEXT
Rekord NDEF TNF_WELL_KNOWN
możesz utworzyć w ten sposób:
Kotlin
fun createTextRecord(payload: String, locale: Locale, encodeInUtf8: Boolean): NdefRecord { val langBytes = locale.language.toByteArray(Charset.forName("US-ASCII")) val utfEncoding = if (encodeInUtf8) Charset.forName("UTF-8") else Charset.forName("UTF-16") val textBytes = payload.toByteArray(utfEncoding) val utfBit: Int = if (encodeInUtf8) 0 else 1 shl 7 val status = (utfBit + langBytes.size).toChar() val data = ByteArray(1 + langBytes.size + textBytes.size) data[0] = status.toByte() System.arraycopy(langBytes, 0, data, 1, langBytes.size) System.arraycopy(textBytes, 0, data, 1 + langBytes.size, textBytes.size) return NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, ByteArray(0), data) }
Java
public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) { byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII")); Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16"); byte[] textBytes = payload.getBytes(utfEncoding); int utfBit = encodeInUtf8 ? 0 : (1 << 7); char status = (char) (utfBit + langBytes.length); byte[] data = new byte[1 + langBytes.length + textBytes.length]; data[0] = (byte) status; System.arraycopy(langBytes, 0, data, 1, langBytes.length); System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length); NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], data); return record; }
Filtr intencji dla poprzedniego rekordu NDEF wyglądałby tak:
<intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> </intent-filter>
TNF_WELL_KNOWN z RTD_uri
Rekord NDEF TNF_WELL_KNOWN
możesz utworzyć na te sposoby:
Przy użyciu metody createUri(String)
:
Kotlin
val rtdUriRecord1 = NdefRecord.createUri("https://example.com")
Java
NdefRecord rtdUriRecord1 = NdefRecord.createUri("https://example.com");
Przy użyciu metody createUri(Uri)
:
Kotlin
val rtdUriRecord2 = Uri.parse("https://example.com").let { uri -> NdefRecord.createUri(uri) }
Java
Uri uri = Uri.parse("https://example.com"); NdefRecord rtdUriRecord2 = NdefRecord.createUri(uri);
Ręczne utworzenie NdefRecord
:
Kotlin
val uriField = "example.com".toByteArray(Charset.forName("US-ASCII")) val payload = ByteArray(uriField.size + 1) //add 1 for the URI Prefix payload [0] = 0x01 //prefixes https://www. to the URI System.arraycopy(uriField, 0, payload, 1, uriField.size) //appends URI to payload val rtdUriRecord = NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, ByteArray(0), payload)
Java
byte[] uriField = "example.com".getBytes(Charset.forName("US-ASCII")); byte[] payload = new byte[uriField.length + 1]; //add 1 for the URI Prefix payload[0] = 0x01; //prefixes https://www. to the URI System.arraycopy(uriField, 0, payload, 1, uriField.length); //appends URI to payload NdefRecord rtdUriRecord = new NdefRecord( NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], payload);
Filtr intencji dla poprzedniego rekordu NDEF wyglądałby tak:
<intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="https" android:host="example.com" android:pathPrefix="" /> </intent-filter>
TNF_EXTERNAL_TYPE;
Rekord NDEF TNF_EXTERNAL_TYPE
możesz utworzyć w następujący sposób:
Przy użyciu metody createExternal()
:
Kotlin
var payload: ByteArray //assign to your data val domain = "com.example" //usually your app's package name val type = "externalType" val extRecord = NdefRecord.createExternal(domain, type, payload)
Java
byte[] payload; //assign to your data String domain = "com.example"; //usually your app's package name String type = "externalType"; NdefRecord extRecord = NdefRecord.createExternal(domain, type, payload);
Ręczne utworzenie NdefRecord
:
Kotlin
var payload: ByteArray ... val extRecord = NdefRecord( NdefRecord.TNF_EXTERNAL_TYPE, "com.example:externalType".toByteArray(Charset.forName("US-ASCII")), ByteArray(0), payload )
Java
byte[] payload; ... NdefRecord extRecord = new NdefRecord( NdefRecord.TNF_EXTERNAL_TYPE, "com.example:externalType".getBytes(Charset.forName("US-ASCII")), new byte[0], payload);
Filtr intencji dla poprzedniego rekordu NDEF wyglądałby tak:
<intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="vnd.android.nfc" android:host="ext" android:pathPrefix="/com.example:externalType"/> </intent-filter>
W przypadku bardziej ogólnych wdrożeń tagów NFC użyj TNF_EXTERNAL_TYPE
. Pozwoli to lepiej obsługiwać urządzenia z Androidem i urządzenia z systemem innym niż Android.
Uwaga: identyfikatory URN dla TNF_EXTERNAL_TYPE
mają kanoniczny format: urn:nfc:ext:example.com:externalType
, ale specyfikacja RTD Forum NFC wskazuje, że w rekordzie NDEF należy pominąć część urn:nfc:ext:
numeru URN. Wystarczy więc podać domenę (w tym przykładzie example.com
) i jej typ (w przykładzie externalType
) oddzielone dwukropkiem.
Podczas wysyłania TNF_EXTERNAL_TYPE
Android konwertuje identyfikator URN urn:nfc:ext:example.com:externalType
na identyfikator URI vnd.android.nfc://ext/example.com:externalType
, który deklaruje filtr intencji w przykładzie.
Rekordy aplikacji na Androida
Wprowadzenie w Androidzie 4.0 (poziom interfejsu API 14) funkcji Android Application Record (AAR) zapewnia większą pewność, że aplikacja jest uruchamiana podczas skanowania tagu NFC. W AAR nazwa pakietu aplikacji umieszczona w rekordzie NDEF. Możesz dodać AAR do dowolnego rekordu NDEF wiadomości NDEF, ponieważ Android przeszukuje całą wiadomość NDEF pod kątem AAR. Gdy znajdzie narzędzie AAR, uruchomi aplikację na podstawie nazwy pakietu zawartej w nim. Jeśli na urządzeniu nie ma aplikacji, uruchamia się Google Play, by ją pobrać.
AAR przydają się, gdy chcesz uniemożliwić innym aplikacjom filtrowanie na podstawie tej samej intencji i potencjalną obsługę konkretnych wdrożonych tagów. AAR są obsługiwane tylko na poziomie aplikacji ze względu na ograniczenie nazwy pakietu, a nie na poziomie aktywności, jak w przypadku filtrowania intencji. Jeśli chcesz obsługiwać intencję na poziomie działania, użyj filtrów intencji.
Jeśli tag zawiera AAR, system jego wysyłania wysyła je w ten sposób:
- Spróbuj w normalny sposób uruchomić działanie, używając filtra intencji. Jeśli aktywność pasująca do intencji odpowiada też AAR, rozpocznij działanie.
- Jeśli aktywność filtrująca intencję nie pasuje do AAR, jeżeli wiele działań może obsłużyć intencję lub jeśli żadna aktywność nie obsługuje intencji, uruchom aplikację określoną przez AAR.
- Jeśli żadna aplikacja nie może skorzystać z AAR, przejdź do Google Play, aby ją pobrać.
Uwaga: możesz zastąpić AAR i system wysyłania intencji za pomocą systemu wysyłania na pierwszym planie, który sprawia, że działania na pierwszym planie mają priorytet po wykryciu tagu NFC. W przypadku tej metody działanie musi być na pierwszym planie, aby zastąpić AAR i system wysyłania intencji.
Jeśli nadal chcesz filtrować zeskanowane tagi, które nie zawierają AAR, możesz w zwykły sposób zadeklarować filtry intencji. Jest to przydatne, gdy Twoja aplikacja jest zainteresowana innymi tagami, które nie zawierają AAR. Możesz na przykład zagwarantować, że aplikacja będzie obsługiwać zarówno zastrzeżone przez Ciebie tagi, jak i tagi ogólne wdrożone przez firmy zewnętrzne. Pamiętaj, że AAR odnoszą się tylko do urządzeń z Androidem 4.0 lub nowszym, więc podczas wdrażania tagów warto użyć kombinacji typów AAR i typów MIME oraz identyfikatorów URI, aby zapewnić obsługę najszerszej gamy urządzeń. Poza tym wdrażając tagi NFC, zastanów się, jak chcesz je zapisywać, aby umożliwić obsługę większości urządzeń (z Androidem i innych). Możesz to zrobić, definiując względnie unikalny typ MIME lub identyfikator URI, aby ułatwić aplikacjom rozróżnianie.
Android udostępnia prosty interfejs API do tworzenia AAR: createApplicationRecord()
. Wystarczy, że umieścisz AAR w dowolnym miejscu w pliku NdefMessage
. Nie chcesz używać pierwszego rekordu NdefMessage
, chyba że AAR jest jedynym rekordem w NdefMessage
. Dzieje się tak, ponieważ system Android sprawdza pierwszy rekord NdefMessage
, aby określić typ MIME lub identyfikator URI tagu, który służy do tworzenia intencji dla aplikacji do filtrowania. Poniższy kod pokazuje, jak utworzyć AAR:
Kotlin
val msg = NdefMessage( arrayOf( ..., NdefRecord.createApplicationRecord("com.example.android.beam") ) )
Java
NdefMessage msg = new NdefMessage( new NdefRecord[] { ..., NdefRecord.createApplicationRecord("com.example.android.beam")} ); )
Przesyłaj wiadomości NDEF do innych urządzeń
Android Beam umożliwia prostą wymianę danych typu peer-to-peer między dwoma urządzeniami z systemem Android. Aplikacja, która chce przesyłać dane do innego urządzenia, musi działać na pierwszym planie, a urządzenie odbierające dane nie może być zablokowane. Gdy urządzenie wysyłające obraz znajdzie się wystarczająco blisko urządzenia odbierającego, wyświetli się interfejs „Dotknij, by przesłać”. Użytkownik może następnie zdecydować, czy wysłać wiadomość na urządzenie odbierające.
Uwaga: przekazywanie NDEF na pierwszym planie było dostępne na poziomie API 10, który zapewnia podobne funkcje co Android Beam. Te interfejsy API zostały wycofane, ale
obsługują starsze urządzenia. Aby dowiedzieć się więcej, przeczytaj enableForegroundNdefPush()
.
Możesz włączyć Android Beam dla swojej aplikacji, wywołując jedną z dwóch metod:
setNdefPushMessage()
: akceptujeNdefMessage
, które można ustawić jako wiadomość do przesłania. Automatycznie przesyła wiadomość zbliżeniową, gdy dwa urządzenia znajdują się wystarczająco blisko.setNdefPushMessageCallback()
: przyjmuje wywołanie zwrotne zawierające parametrcreateNdefMessage()
, które jest wywoływane, gdy urządzenie znajduje się w zasięgu, na które ma przesłać dane. Wywołanie zwrotne umożliwia utworzenie wiadomości NDEF tylko wtedy, gdy jest to konieczne.
Aktywność może przekazać tylko 1 wiadomość NDEF naraz, więc setNdefPushMessageCallback()
ma pierwszeństwo przed setNdefPushMessage()
, jeśli obie są skonfigurowane. Aby korzystać z Android Beam, trzeba przestrzegać tych ogólnych wskazówek:
- Działanie, które przesyła dane, musi być na pierwszym planie. Oba urządzenia muszą mieć odblokowane ekrany.
- Dane, które przesyłasz, musisz opakować w obiekcie
NdefMessage
. - Urządzenie NFC, które odbiera przesyłane dane, musi obsługiwać
com.android.npp
protokół NDEF push lub protokół SNEP (Simple NDEF Exchange Protocol) Forum NFC. Protokółcom.android.npp
jest wymagany na urządzeniach korzystających z interfejsów API na poziomie 9 (Android 2.3) i API 13 (Android 3.2).com.android.npp
i SNEP są wymagane w przypadku interfejsu API na poziomie 14 (Android 4.0) i nowszych.
Uwaga: jeśli Twoja aktywność włącza Android Beam i działa na pierwszym planie, standardowy system wysyłania intencji jest wyłączony. Jeśli jednak Twoja aktywność umożliwia też wysyłanie na pierwszym planie, może nadal skanować tagi zgodne z filtrami intencji ustawionymi w wysyłaniu na pierwszym planie.
Aby włączyć Android Beam:
- Utwórz
NdefMessage
zawierający elementyNdefRecord
, które chcesz przekazać na drugie urządzenie. - Wywołaj
setNdefPushMessage()
zNdefMessage
lub wywołajsetNdefPushMessageCallback
, przekazując obiektNfcAdapter.CreateNdefMessageCallback
w metodzieonCreate()
Twojej aktywności. Te metody wymagają co najmniej jednej aktywności, którą chcesz włączyć za pomocą Android Beam, oraz opcjonalnej listy innych działań, które chcesz włączyć.Zazwyczaj używasz
setNdefPushMessage()
, jeśli Twoja aktywność musi przez cały czas przekazywać tylko ten sam komunikat NDEF, gdy 2 urządzenia są w zasięgu, aby się komunikować. UżywaszsetNdefPushMessageCallback
, gdy aplikacja dba o bieżący kontekst aplikacji i chce przekazać komunikat NDEF w zależności od tego, co użytkownik robi w aplikacji.
Poniższy przykład pokazuje, jak prosta aktywność wywołuje NfcAdapter.CreateNdefMessageCallback
w metodzie onCreate()
aktywności (pełny przykład znajdziesz na AndroidBeamDemo). W tym przykładzie znajdziesz też metody tworzenia rekordu MIME:
Kotlin
package com.example.android.beam import android.app.Activity import android.content.Intent import android.nfc.NdefMessage import android.nfc.NdefRecord import android.nfc.NfcAdapter import android.nfc.NfcAdapter.CreateNdefMessageCallback import android.nfc.NfcEvent import android.os.Bundle import android.os.Parcelable import android.widget.TextView import android.widget.Toast import java.nio.charset.Charset class Beam : Activity(), NfcAdapter.CreateNdefMessageCallback { private var nfcAdapter: NfcAdapter? = null private lateinit var textView: TextView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main) textView = findViewById(R.id.textView) // Check for available NFC Adapter nfcAdapter = NfcAdapter.getDefaultAdapter(this) if (nfcAdapter == null) { Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show() finish() return } // Register callback nfcAdapter?.setNdefPushMessageCallback(this, this) } override fun createNdefMessage(event: NfcEvent): NdefMessage { val text = "Beam me up, Android!\n\n" + "Beam Time: " + System.currentTimeMillis() return NdefMessage( arrayOf( createMime("application/vnd.com.example.android.beam", text.toByteArray()) ) /** * The Android Application Record (AAR) is commented out. When a device * receives a push with an AAR in it, the application specified in the AAR * is guaranteed to run. The AAR overrides the tag dispatch system. * You can add it back in to guarantee that this * activity starts when receiving a beamed message. For now, this code * uses the tag dispatch system. *///,NdefRecord.createApplicationRecord("com.example.android.beam") ) } override fun onResume() { super.onResume() // Check to see that the Activity started due to an Android Beam if (NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action) { processIntent(intent) } } override fun onNewIntent(intent: Intent) { // onResume gets called after this to handle the intent setIntent(intent) } /** * Parses the NDEF Message from the intent and prints to the TextView */ private fun processIntent(intent: Intent) { textView = findViewById(R.id.textView) // only one message sent during the beam intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)?.also { rawMsgs -> (rawMsgs[0] as NdefMessage).apply { // record 0 contains the MIME type, record 1 is the AAR, if present textView.text = String(records[0].payload) } } } }
Java
package com.example.android.beam; import android.app.Activity; import android.content.Intent; import android.nfc.NdefMessage; import android.nfc.NdefRecord; import android.nfc.NfcAdapter; import android.nfc.NfcAdapter.CreateNdefMessageCallback; import android.nfc.NfcEvent; import android.os.Bundle; import android.os.Parcelable; import android.widget.TextView; import android.widget.Toast; import java.nio.charset.Charset; public class Beam extends Activity implements CreateNdefMessageCallback { NfcAdapter nfcAdapter; TextView textView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView textView = (TextView) findViewById(R.id.textView); // Check for available NFC Adapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); if (nfcAdapter == null) { Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show(); finish(); return; } // Register callback nfcAdapter.setNdefPushMessageCallback(this, this); } @Override public NdefMessage createNdefMessage(NfcEvent event) { String text = ("Beam me up, Android!\n\n" + "Beam Time: " + System.currentTimeMillis()); NdefMessage msg = new NdefMessage( new NdefRecord[] { createMime( "application/vnd.com.example.android.beam", text.getBytes()) /** * The Android Application Record (AAR) is commented out. When a device * receives a push with an AAR in it, the application specified in the AAR * is guaranteed to run. The AAR overrides the tag dispatch system. * You can add it back in to guarantee that this * activity starts when receiving a beamed message. For now, this code * uses the tag dispatch system. */ //,NdefRecord.createApplicationRecord("com.example.android.beam") }); return msg; } @Override public void onResume() { super.onResume(); // Check to see that the Activity started due to an Android Beam if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { processIntent(getIntent()); } } @Override public void onNewIntent(Intent intent) { // onResume gets called after this to handle the intent setIntent(intent); } /** * Parses the NDEF Message from the intent and prints to the TextView */ void processIntent(Intent intent) { textView = (TextView) findViewById(R.id.textView); Parcelable[] rawMsgs = intent.getParcelableArrayExtra( NfcAdapter.EXTRA_NDEF_MESSAGES); // only one message sent during the beam NdefMessage msg = (NdefMessage) rawMsgs[0]; // record 0 contains the MIME type, record 1 is the AAR, if present textView.setText(new String(msg.getRecords()[0].getPayload())); } }
Pamiętaj, że ten kod komentuje AAR, którą możesz usunąć. Jeśli włączysz AAR, aplikacja określona w nim zawsze będzie otrzymywać wiadomość Android Beam. Gdy aplikacja nie jest widoczna, Google Play zaczyna ją pobierać. Dlatego w przypadku urządzeń z Androidem 4.0 lub nowszym, jeśli używasz AAR, technicznie nie musisz używać tego filtra intencji:
<intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="application/vnd.com.example.android.beam"/> </intent-filter>
Dzięki temu filtrowi intencji aplikację com.example.android.beam
można teraz uruchamiać, gdy skanuje tag NFC lub odbiera Android Beam z AAR typu com.example.android.beam
albo gdy wiadomość w formacie NDEF zawiera rekord MIME typu application/vnd.com.example.android.beam
.
Mimo że AAR gwarantuje uruchomienie lub pobranie aplikacji, filtry intencji są zalecane, ponieważ pozwalają uruchamiać wybrane działanie w aplikacji, zamiast uruchamiać główne działanie w pakiecie określonym przez AAR. AAR nie mają szczegółowości na poziomie aktywności. Poza tym niektóre urządzenia z Androidem nie obsługują AAR, dlatego na wszelki wypadek umieść informacje identyfikacyjne w pierwszym rekordzie NDEF wiadomości NDEF i odpowiednio ustaw filtr. Więcej informacji o tworzeniu rekordów znajdziesz w artykule Tworzenie popularnych typów rekordów NDEF.