Présentation de la technologie NFC avancée

Ce document aborde des sujets relatifs à la technologie NFC avancés, tels que l'utilisation de différentes technologies de tag, l'écriture dans des tags NFC et la distribution au premier plan, qui permet à une application au premier plan gérer les intents même lorsque d'autres applications filtrent les mêmes.

Utiliser les technologies de tag acceptées

Lorsque vous travaillez avec des tags NFC et des appareils Android, le format principal que vous utilisez pour lire et écrire des données sur des tags est NDEF. Lorsqu'un appareil analyse un tag contenant des données NDEF, Android fournit une assistance lors de l'analyse du message et de sa distribution dans une NdefMessage possible. Toutefois, dans certains cas, lorsque vous analysez un tag qui ne contient pas Données NDEF ou lorsque les données NDEF n'ont pas pu être mappées avec un type MIME ou un URI Dans ce cas, vous devez ouvrir la communication directement avec le tag, et y lire et y écrire avec votre propre protocole (en octets bruts). Android fournit une prise en charge générique pour ces cas d'utilisation avec le le package android.nfc.tech, décrit dans le tableau 1. Vous pouvez utiliser la méthode getTechList() pour déterminer les technologies acceptée par la balise et crée l'élément TagTechnology correspondant objet avec l'une des classes fournies par android.nfc.tech

Tableau 1. Technologies de tag acceptées

Classe Description
TagTechnology Interface que toutes les classes de technologie de balise doivent implémenter.
NfcA Permet d'accéder aux propriétés NFC-A (ISO 14443-3A) et aux opérations d'E/S.
NfcB Permet d'accéder aux propriétés NFC-B (ISO 14443-3B) et aux opérations d'E/S.
NfcF Permet d'accéder aux propriétés NFC-F (JIS 6319-4) et aux opérations d'E/S.
NfcV Permet d'accéder aux propriétés NFC-V (ISO 15693) et aux opérations d'E/S.
IsoDep Permet d'accéder aux propriétés ISO-DEP (ISO 14443-4) et aux opérations d'E/S.
Ndef Fournit l'accès aux données et opérations NDEF sur des tags NFC mis en forme en tant que NDEF.
NdefFormatable Fournit des opérations de mise en forme pour les tags pouvant être formatables NDEF.

Les technologies de tag suivantes ne doivent pas nécessairement être compatibles avec les appareils Android.

Tableau 2. Technologies de balises compatibles facultatives

Classe Description
MifareClassic Fournit l'accès aux propriétés MIFARE Classic et aux opérations d'E/S, si cet appareil Android est compatible avec MIFARE.
MifareUltralight Fournit l'accès aux propriétés MIFARE Ultralight et aux opérations d'E/S, si cet appareil Android est compatible avec MIFARE.

Utiliser les technologies de tag et l'intent ACTION_TECH_DISCOVERED

Lorsqu'un appareil analyse un tag qui contient des données NDEF, mais qui n'a pas pu être mappé sur un MIME ou un URI, le système de distribution des tags tente de démarrer une activité avec l'ACTION_TECH_DISCOVERED. l'intention. Le ACTION_TECH_DISCOVERED est également utilisé lorsqu'un tag avec des données non-NDEF. Cette création de remplacement vous permet de travailler avec les données de la balise directement si le système de distribution des balises ne parvient pas à l'analyser. Les étapes de base lorsque vous travaillez avec de tags sont les suivantes:

  1. Filtrez les résultats pour un intent ACTION_TECH_DISCOVERED spécifiant le de balises que vous souhaitez gérer. Consultez la section Filtrage NFC intents pour en savoir plus. En général, le système de distribution des tags tente de démarrer un intent ACTION_TECH_DISCOVERED lorsqu'un message NDEF ne peut pas être mappé sur un type MIME ni avec un URI, ou si le tag analysé ne contient pas de données NDEF. Pour Pour en savoir plus sur la façon dont cela est déterminé, consultez la page sur Tag Dispatch System.
  2. Lorsque votre application reçoit l'intent, obtenez l'objet Tag à partir de l'intent:

    Kotlin

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

    Java

    Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    
  3. Obtenez une instance de TagTechnology en appelant l'une des Méthodes de fabrique get des classes du package android.nfc.tech. Vous pouvez énumérer les technologies compatibles avec la balise en appelant getTechList() avant d'appeler une méthode de fabrique get. Par exemple, pour obtenir une instance de MifareUltralight à partir d'un Tag, procédez comme suit:

    Kotlin

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

    Java

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

Lire et écrire dans les tags

La lecture et l'écriture dans un tag NFC impliquent d'obtenir le tag à partir de l'intent et d’ouverture de la communication avec la balise. Vous devez définir votre propre pile de protocoles pour lire et écrire des données au tag. Gardez toutefois à l'esprit que vous pouvez toujours lire et écrire des données NDEF lorsque vous travaillez directement à l'aide d'un tag. C'est à vous de décider comment vous voulez structurer les choses. La L'exemple suivant montre comment utiliser 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;
    }
}

Utiliser le système de répartition au premier plan

Le système de répartition au premier plan permet à une activité d'intercepter un intent et une demande ont la priorité sur les autres activités qui gèrent le même intent. L'utilisation de ce système implique construire quelques structures de données pour que le système Android puisse envoyer les des intents à votre application. Pour activer le système de répartition au premier plan:

  1. Ajoutez le code suivant dans la méthode onCreate() de votre activité: <ph type="x-smartling-placeholder">
      </ph>
    1. Créez un objet PendingIntent modifiable afin que le système Android puisse le remplir. avec les détails de la balise lors de son analyse.

      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. Déclarez des filtres d'intent pour gérer les intents que vous souhaitez intercepter. Le premier plan le système de distribution vérifie les filtres d'intent spécifiés avec l'intent reçu lorsque l'appareil scanne un tag. S'il correspond, votre application gère l'intent. Si c'est le cas ne correspondent pas, le système de répartition au premier plan se rabat sur le système de répartition des intents. Lorsque vous spécifiez un ensemble null de filtres d'intent et de filtres technologiques, que vous voulez filtrer pour toutes les balises de remplacement de TAG_DISCOVERED l'intention. L'extrait de code ci-dessous gère tous les types MIME pour NDEF_DISCOVERED. Toi ne doit gérer que celles dont vous avez besoin.

      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. Configurez un ensemble de technologies de balises que votre application doit gérer. Appelez la méthode Object.class.getName() pour obtenir la classe de technologie que vous que vous souhaitez soutenir.

      Kotlin

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

      Java

      techListsArray = new String[][] { new String[] { NfcF.class.getName() } };
      
  2. Remplacez les rappels de cycle de vie d'activité suivants et ajoutez une logique pour activer et désactiver le distribution au premier plan lorsque l'activité perd (onPause()) et récupère la mise au point (onResume()). enableForegroundDispatch() doit être appelé depuis le thread principal et uniquement lorsque l'activité est au premier plan (l'appel dans onResume() le garantit). Vous devez également implémenter le rappel onNewIntent pour traiter les données issues de la technologie NFC scannée. .
  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
    }