Panoramica avanzata di NFC

Questo documento descrive gli argomenti NFC avanzati, ad esempio l'utilizzo di varie tecnologie di tag, la scrittura nei tag NFC e l'invio in primo piano, consentendo a un'applicazione in primo piano di gestire gli intent anche quando altre applicazioni filtrano in base agli stessi criteri.

Utilizzare le tecnologie di tag supportate

Quando lavori con tag NFC e dispositivi Android, il formato principale utilizzato per leggere e scrivere dati sui tag è NDEF. Quando un dispositivo scansiona un tag con dati NDEF, Android fornisce assistenza. durante l'analisi del messaggio e la sua consegna in un NdefMessage quando possibile. Esistono casi, tuttavia, che quando esegui la scansione di un tag che non contiene Dati NDEF o quando non è stato possibile mappare i dati NDEF a un tipo o a un URI MIME. In questi casi, devi aprire la comunicazione direttamente con il tag, leggere e scrivere utilizzando il tuo protocollo (in byte non elaborati). Android fornisce assistenza generica per questi casi d'uso con android.nfc.tech, come descritto nella Tabella 1. Puoi usano il metodo getTechList() per determinare le tecnologie supportato dal tag e crea il valore TagTechnology corrispondente con una delle classi fornite da android.nfc.tech

Tabella 1. Tecnologie di tag supportate

Classe Descrizione
TagTechnology L'interfaccia che tutte le classi di tecnologia dei tag devono implementare.
NfcA Fornisce l'accesso alle proprietà NFC-A (ISO 14443-3A) e alle operazioni di I/O.
NfcB Fornisce l'accesso alle proprietà NFC-B (ISO 14443-3B) e alle operazioni di I/O.
NfcF Fornisce l'accesso alle proprietà NFC-F (JIS 6319-4) e alle operazioni di I/O.
NfcV Fornisce l'accesso alle proprietà NFC-V (ISO 15693) e alle operazioni di I/O.
IsoDep Fornisce l'accesso alle proprietà ISO-DEP (ISO 14443-4) e alle operazioni di I/O.
Ndef Fornisce l'accesso ai dati e alle operazioni NDEF sui tag NFC che sono stati formattati come NDEF.
NdefFormatable Fornisce operazioni di formattazione per i tag che possono essere formattabili NDEF.

Le seguenti tecnologie di tag non devono essere supportate dai dispositivi Android.

Tabella 2. Tecnologie di tag supportate facoltative

Classe Descrizione
MifareClassic Fornisce l'accesso alle proprietà MIFARE Classic e alle operazioni di I/O, se questo dispositivo Android supporta MIFARE.
MifareUltralight Fornisce l'accesso alle proprietà MIFARE Ultralight e alle operazioni di I/O, se questo Android supporta MIFARE.

Utilizzare le tecnologie di tag e l'intent ACTION_TECH_DISCOVERED

Quando un dispositivo analizza un tag che contiene dati NDEF, ma che non è stato possibile mappare a un MIME o un URI, il sistema di invio dei tag prova ad avviare un'attività con ACTION_TECH_DISCOVERED l'intento. ACTION_TECH_DISCOVERED viene utilizzato anche quando un tag con dati non NDEF. Questa opzione di riserva ti consente di lavorare con i dati sul tag direttamente se il sistema di invio dei tag non è riuscito ad analizzarli. I passaggi di base quando si utilizza tecnologie di tag sono le seguenti:

  1. Filtra in base a un intent ACTION_TECH_DISCOVERED che specifica le tecnologie di tag che vuoi gestire. Consulta la sezione Filtri per NFC intent per ulteriori informazioni. In generale, il sistema di invio dei tag prova ad avviare un intent ACTION_TECH_DISCOVERED quando un messaggio NDEF non può essere mappato a un URI o un tipo MIME oppure se il tag analizzato non conteneva dati NDEF. Per Per ulteriori informazioni su come determinare questo comportamento, consulta la sezione The Tag Dispatch System.
  2. Quando l'applicazione riceve l'intent, ottieni l'oggetto Tag da l'intento:

    Kotlin

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

    Java

    Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    
  3. Recupera l'istanza di un TagTechnology, chiamando uno dei get metodi di fabbrica delle classi nel pacchetto android.nfc.tech. Puoi enumera le tecnologie supportate del tag chiamando getTechList() prima di chiamare un metodo di fabbrica get. Ad esempio, per ottenere un'istanza di MifareUltralight da un Tag:

    Kotlin

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

    Java

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

Lettura e scrittura nei tag

La lettura e la scrittura in un tag NFC implicano il recupero del tag dall'intent e la comunicazione con il tag. Devi definire il tuo stack di protocollo per leggere e scrivere dati al tag. Tieni presente, tuttavia, che puoi comunque leggere e scrivere dati NDEF quando lavori direttamente con un tag. Sta a te decidere come strutturare le cose. La nell'esempio seguente viene illustrato come utilizzare un tag 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;
    }
}

Utilizzare il sistema di invio in primo piano

Il sistema di invio in primo piano consente a un'attività di intercettare un intento e una rivendicazione la priorità su altre attività che gestiscono lo stesso intento. L'utilizzo di questo sistema comporta creando alcune strutture di dati affinché il sistema Android sia in grado di inviare intent alla tua applicazione. Per attivare il sistema di invio in primo piano:

  1. Aggiungi il seguente codice nel metodo onCreate() della tua attività:
    1. Crea un oggetto PendingIntent modificabile in modo che il sistema Android possa compilarlo con i dettagli del tag quando viene scansionato.

      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. Dichiara i filtri di intent per gestire gli intent da intercettare. In primo piano il sistema di invio controlla i filtri per intent specificati con l'intent che viene ricevuto quando il dispositivo scansiona un tag. Se corrisponde, la tua applicazione gestisce l'intent. In caso affermativo non corrisponde, il sistema di invio in primo piano utilizza il sistema di invio per intent. Se specifichi un array null di filtri per intent e filtri di tecnologia, che vuoi filtrare in base a tutti i tag di riserva TAG_DISCOVERED l'intento. Lo snippet di codice riportato di seguito gestisce tutti i tipi MIME per NDEF_DISCOVERED. Tu gestire solo quelli di cui hai bisogno.

      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. Configura una serie di tecnologie di tag che la tua applicazione vuole gestire. Chiama il Object.class.getName() per ottenere la classe della tecnologia con cui che vuoi sostenere.

      Kotlin

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

      Java

      techListsArray = new String[][] { new String[] { NfcF.class.getName() } };
      
  2. Esegui l'override dei seguenti callback del ciclo di vita delle attività e aggiungi la logica per abilitare e disabilitare invio in primo piano quando l'attività perde (onPause()) e recupera (onResume()) l'attenzione. enableForegroundDispatch() deve essere chiamato da nel thread principale e solo quando l'attività è in primo piano (la chiamata in onResume() lo garantisce). Devi anche implementare il callback onNewIntent per elaborare i dati dell'NFC scansionato del tag.
  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
    }