Omówienie zaawansowanych funkcji NFC

W tym dokumencie opisujemy zaawansowane zagadnienia dotyczące NFC, takie jak praca z różnymi technologiami tagów, zapisywanie danych do tagów NFC oraz wysyłanie działającej na pierwszym planie, które umożliwia aplikacji na pierwszym planie obsługuje intencje nawet wtedy, gdy inne aplikacje filtrują te same intencje.

Korzystanie z obsługiwanych technologii tagów

W przypadku pracy z tagami NFC i urządzeniami z systemem Android jest to główny format używany do odczytu a dane zapisu w tagach to NDEF. Gdy urządzenie skanuje tag z danymi NDEF, Android zapewnia pomoc podczas analizowania wiadomości i dostarczania jej w metodzie NdefMessage, gdy jak to tylko możliwe. Istnieją jednak przypadki, gdy skanuje się tag, który nie zawiera dane NDEF lub gdy danych NDEF nie można zmapować na typ MIME albo identyfikator URI. W takich przypadkach należy nawiązać bezpośrednią komunikację z tagiem i odczytać go oraz zapisać za pomocą (w nieprzetworzonych bajtach). Android zapewnia ogólną pomoc w tych przypadkach użycia dzięki android.nfc.tech, który został opisany w tabeli 1. Dostępne opcje użyj metody getTechList() do określania technologii obsługiwane przez tag i utwórz odpowiednią wartość TagTechnology obiekt z jedną z klas udostępnionych przez android.nfc.tech

Tabela 1. Obsługiwane technologie tagów

Kategoria Opis
TagTechnology Interfejs, z którego muszą korzystać wszystkie klasy technologii tagów.
NfcA Zapewnia dostęp do właściwości NFC-A (ISO 14443-3A) oraz operacji wejścia-wyjścia.
NfcB Zapewnia dostęp do właściwości NFC-B (ISO 14443-3B) oraz operacji wejścia-wyjścia.
NfcF Zapewnia dostęp do właściwości NFC-F (JIS 6319-4) oraz operacji wejścia-wyjścia.
NfcV Zapewnia dostęp do właściwości NFC-V (ISO 15693) oraz operacji wejścia-wyjścia.
IsoDep Zapewnia dostęp do właściwości ISO-DEP (ISO 14443-4) oraz operacji wejścia-wyjścia.
Ndef Zapewnia dostęp do danych NDEF i operacji na tagach NFC, które zostały sformatowane jako NDEF.
NdefFormatable Udostępnia operacje formatowania tagów, które mogą być formatowane przez NDEF.

Następujące technologie tagów nie muszą być obsługiwane przez urządzenia z systemem Android.

Tabela 2. Opcjonalne obsługiwane technologie tagów

Kategoria Opis
MifareClassic Zapewnia dostęp do właściwości MIFARE Classic oraz operacji wejścia-wyjścia, jeśli to urządzenie z Androidem obsługuje MIFARE.
MifareUltralight Zapewnia dostęp do właściwości Ultralight MIFARE oraz operacji wejścia-wyjścia, jeśli to urządzenie z Androidem urządzenie obsługuje MIFARE.

Praca z technologiami tagów i intencją ACTION_TECH_DISCOVERED

Jeśli urządzenie skanuje tag, który zawiera dane NDEF, ale nie udało się zamapować go na MIME lub identyfikator URI system wysyłania tagów próbuje rozpocząć aktywność z użyciem tagu ACTION_TECH_DISCOVERED intencji. ACTION_TECH_DISCOVERED jest też używany, gdy tag z danymi w formacie innym niż NDEF. Dzięki temu możesz pracować z danymi w tagu. bezpośrednio, jeśli system wysyłania tagów nie mógł ich przeanalizować. Podstawowe kroki podczas pracy z technologie tagów są następujące:

  1. Filtruj intencję ACTION_TECH_DISCOVERED określającą technologie tagów, które chcesz obsługiwać. Patrz Filtrowanie pod kątem komunikacji NFC . Ogólnie rzecz biorąc, system wysyłania tagów próbuje uruchomić intencję ACTION_TECH_DISCOVERED, gdy komunikat NDEF. nie można zmapować na typ MIME lub identyfikator URI albo jeśli zeskanowany tag nie zawiera danych NDEF. Dla: (więcej informacji o sposobie jego wyliczania znajdziesz w artykule System wysyłki tagów).
  2. Gdy aplikacja otrzyma intencję, pobierz obiekt Tag z: intencja:

    Kotlin

    var tagFromIntent: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
    

    Java

    Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    
  3. Uzyskaj instancję TagTechnology, wywołując jeden z get metody fabryczne klas w pakiecie android.nfc.tech. Dostępne opcje wylicza obsługiwane technologie tagu, wywołując metodę getTechList() przed wywołaniem metody fabrycznej get. Aby na przykład uzyskać instancję MifareUltralight z Tag, wykonaj te czynności:

    Kotlin

    MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG))
    

    Java

    MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG));
    

Odczyt i zapis w tagach

Odczyt i zapis do tagu NFC polega na uzyskaniu go z intencji rozpoczęcie komunikacji z tagiem. Aby odczytywać i zapisywać dane, musisz zdefiniować własny stos protokołów do tagu. Pamiętaj jednak, że nadal możesz odczytywać i zapisywać dane NDEF podczas pracy bezpośrednio za pomocą tagu. To od Ciebie zależy, jak nadasz im strukturę. Poniższy przykład pokazuje, jak korzystać z tagu MIFARE Ultralight.

Kotlin

package com.example.android.nfc
import android.nfc.Tag
import android.nfc.tech.MifareUltralight
import java.io.IOException
import java.nio.charset.Charset

class MifareUltralightTagTester {

    fun writeTag(tag: Tag, tagText: String) {
        MifareUltralight.get(tag)?.use { ultralight ->
            ultralight.connect()
            Charset.forName("US-ASCII").also { usAscii ->
                ultralight.writePage(4, "abcd".toByteArray(usAscii))
                ultralight.writePage(5, "efgh".toByteArray(usAscii))
                ultralight.writePage(6, "ijkl".toByteArray(usAscii))
                ultralight.writePage(7, "mnop".toByteArray(usAscii))
            }
        }
    }

    fun readTag(tag: Tag): String? {
        return MifareUltralight.get(tag)?.use { mifare ->
            mifare.connect()
            val payload = mifare.readPages(4)
            String(payload, Charset.forName("US-ASCII"))
        }
    }
}

Java

package com.example.android.nfc;

import android.nfc.Tag;
import android.nfc.tech.MifareUltralight;
import android.util.Log;
import java.io.IOException;
import java.nio.charset.Charset;

public class MifareUltralightTagTester {

    private static final String TAG = MifareUltralightTagTester.class.getSimpleName();

    public void writeTag(Tag tag, String tagText) {
        MifareUltralight ultralight = MifareUltralight.get(tag);
        try {
            ultralight.connect();
            ultralight.writePage(4, "abcd".getBytes(Charset.forName("US-ASCII")));
            ultralight.writePage(5, "efgh".getBytes(Charset.forName("US-ASCII")));
            ultralight.writePage(6, "ijkl".getBytes(Charset.forName("US-ASCII")));
            ultralight.writePage(7, "mnop".getBytes(Charset.forName("US-ASCII")));
        } catch (IOException e) {
            Log.e(TAG, "IOException while writing MifareUltralight...", e);
        } finally {
            try {
                ultralight.close();
            } catch (IOException e) {
                Log.e(TAG, "IOException while closing MifareUltralight...", e);
            }
        }
    }

    public String readTag(Tag tag) {
        MifareUltralight mifare = MifareUltralight.get(tag);
        try {
            mifare.connect();
            byte[] payload = mifare.readPages(4);
            return new String(payload, Charset.forName("US-ASCII"));
        } catch (IOException e) {
            Log.e(TAG, "IOException while reading MifareUltralight message...", e);
        } finally {
            if (mifare != null) {
               try {
                   mifare.close();
               }
               catch (IOException e) {
                   Log.e(TAG, "Error closing tag...", e);
               }
            }
        }
        return null;
    }
}

Użyj systemu dyspozytorskiego na pierwszym planie

System dyspozytorów na pierwszym planie umożliwia aktywności przechwytywanie intencji i roszczenia mają wyższy priorytet niż inne działania, które obsługują tę samą intencję. Korzystanie z tego systemu wiąże się i tworzą struktury danych, dzięki którym system Android będzie wysyłać odpowiednie do aplikacji. Aby włączyć system wysyłania na pierwszym planie:

  1. Dodaj ten kod w metodzie onCreate() w Twojej aktywności:
    1. Utwórz zmienny obiekt PendingIntent, aby system Android mógł go wypełnić ze szczegółami tagu w momencie jego skanowania.

      Kotlin

      val intent = Intent(this, javaClass).apply {
          addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
      }
      var pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent,
              PendingIntent.FLAG_MUTABLE)
      

      Java

      PendingIntent pendingIntent = PendingIntent.getActivity(
          this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
          PendingIntent.FLAG_MUTABLE);
      
    2. Zadeklaruj filtry intencji do obsługi intencji, które chcesz przechwytywać. Na pierwszym planie system wysyłania sprawdza określone filtry intencji z intencją, która jest odbierana, urządzenie skanuje tag. Jeśli będzie pasować, aplikacja obsługuje intencję. Jeśli tak, nie pasuje, system dyspozytorów na pierwszym planie powraca do systemu wysyłania intencji. Określenie tablicy null filtrów intencji i filtrów technicznych, określa który chcesz odfiltrować pod kątem wszystkich tagów kreacji zastępczych TAG_DISCOVERED intencji. Poniższy fragment kodu obsługuje wszystkie typy MIME w domenie NDEF_DISCOVERED. Ty powinien obsługiwać tylko te, których potrzebujesz.

      Kotlin

      val ndef = IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED).apply {
          try {
              addDataType("*/*")    /* Handles all MIME based dispatches.
                                       You should specify only the ones that you need. */
          } catch (e: IntentFilter.MalformedMimeTypeException) {
              throw RuntimeException("fail", e)
          }
      }
      
      intentFiltersArray = arrayOf(ndef)
      

      Java

      IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
          try {
              ndef.addDataType("*/*");    /* Handles all MIME based dispatches.
                                             You should specify only the ones that you need. */
          }
          catch (MalformedMimeTypeException e) {
              throw new RuntimeException("fail", e);
          }
         intentFiltersArray = new IntentFilter[] {ndef, };
      
    3. Skonfiguruj tablicę technologii tagów, które aplikacja ma obsługiwać. Wywołaj funkcję Object.class.getName(), by uzyskać klasę technologii które chcesz wspierać.

      Kotlin

      techListsArray = arrayOf(arrayOf<String>(NfcF::class.java.name))
      

      Java

      techListsArray = new String[][] { new String[] { NfcF.class.getName() } };
      
  2. Zastąp poniższe wywołania zwrotne cyklu życia aktywności i dodaj funkcje logiczne, aby włączyć lub wyłączyć wysyłanie pierwszego planu po utracie aktywności (onPause()) i odzyskuje (onResume()) skupienie. Należy wywołać funkcję enableForegroundDispatch() z w wątku głównym i tylko wtedy, gdy aktywność jest na pierwszym planie (gwarantuje to wywołania w narzędziu onResume()). Musisz też zaimplementować wywołanie zwrotne onNewIntent, aby przetwarzać dane ze zeskanowanej komunikacji NFC. .
  3. Kotlin

    public override fun onPause() {
        super.onPause()
        adapter.disableForegroundDispatch(this)
    }
    
    public override fun onResume() {
        super.onResume()
        adapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray)
    }
    
    public override fun onNewIntent(intent: Intent) {
        val tagFromIntent: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
        // do something with tagFromIntent
    }
    

    Java

    public void onPause() {
        super.onPause();
        adapter.disableForegroundDispatch(this);
    }
    
    public void onResume() {
        super.onResume();
        adapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray);
    }
    
    public void onNewIntent(Intent intent) {
        Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        // do something with tagFromIntent
    }