Ce document décrit des sujets avancés liés à la technologie NFC, tels que l'utilisation de différentes technologies de taggage, l'écriture sur des tags NFC et la distribution de premier plan, qui permet à une application exécutée au premier plan de gérer les intents même lorsque d'autres applications filtrent les mêmes.
Utiliser les technologies de balises compatibles
Lorsque vous utilisez des tags NFC et des appareils Android, le principal format que vous utilisez pour lire et écrire des données sur des tags est le format NDEF. Lorsqu'un appareil analyse un tag avec des données NDEF, Android permet d'analyser le message et de le transmettre dans un NdefMessage
lorsque cela est possible. Toutefois, il peut arriver que vous analysiez un tag qui ne contient pas de données NDEF ou que les données NDEF n'ont pas pu être mappées avec un type ou un URI MIME.
Dans ce cas, vous devez établir la communication directement avec la balise, puis la lire et y écrire avec votre propre protocole (en octets bruts). Android fournit une compatibilité générique pour ces cas d'utilisation avec le package android.nfc.tech
, comme décrit dans le Tableau 1. Vous pouvez utiliser la méthode getTechList()
pour déterminer les technologies compatibles avec la balise et créer l'objet TagTechnology
correspondant avec l'une des classes fournies par android.nfc.tech
.
Classe | Description |
---|---|
TagTechnology |
Interface devant être implémentée par toutes les classes de technologie de balises. |
NfcA |
Fournit l'accès aux propriétés NFC-A (ISO 14443-3A) et aux opérations d'E/S. |
NfcB |
Fournit l'accès aux propriétés NFC-B (ISO 14443-3B) et aux opérations d'E/S. |
NfcF |
Fournit l'accès aux propriétés NFC-F (JIS 6319-4) et aux opérations d'E/S. |
NfcV |
Fournit l'accès aux propriétés NFC-V (ISO 15693) et aux opérations d'E/S. |
IsoDep |
Fournit l'accès 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 les tags NFC mis en forme au format NDEF. |
NdefFormatable |
Fournit des opérations de format pour les tags pouvant être formatables NDEF. |
Les technologies de tag suivantes ne doivent pas nécessairement être compatibles avec les appareils Android.
Classe | Description |
---|---|
MifareClassic |
Fournit l'accès aux propriétés et opérations d'E/S de la version classique de MIFARE, si cet appareil Android est compatible avec MIFARE. |
MifareUltralight |
Fournit l'accès aux propriétés Ultralight et aux opérations d'E/S de MIFARE, si cet appareil Android est compatible avec MIFARE. |
Utiliser les technologies de balise et l'intent ACTION_TECH_DISCOVERED
Lorsqu'un appareil analyse une balise contenant des données NDEF, mais qui n'a pas pu être mappée avec un URI ou MIME, le système de distribution des balises tente de démarrer une activité avec l'intent ACTION_TECH_DISCOVERED
. ACTION_TECH_DISCOVERED
est également utilisé lorsqu'un tag contenant des données non-NDEF est analysé. Cet outil de remplacement vous permet d'utiliser directement les données de la balise si le système de distribution des balises n'a pas pu les analyser pour vous. Voici les principales étapes à suivre pour utiliser des technologies de balises:
- Filtrez les données en fonction d'un intent
ACTION_TECH_DISCOVERED
spécifiant les technologies de balises que vous souhaitez gérer. Pour en savoir plus, consultez la section Filtrer les intents NFC. En général, le système de distribution des tags tente de démarrer un intentACTION_TECH_DISCOVERED
lorsqu'un message NDEF ne peut pas être mappé sur un type ou un URI MIME, ou si le tag analysé ne contient pas de données NDEF. Pour en savoir plus sur la façon dont cela est déterminé, consultez la page consacrée au système de distribution des balises. - 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);
- Obtenez une instance de
TagTechnology
en appelant l'une des méthodes de fabriqueget
des classes du packageandroid.nfc.tech
. Vous pouvez énumérer les technologies compatibles du tag en appelantgetTechList()
avant d'appeler une méthode de fabriqueget
. Par exemple, pour obtenir une instance deMifareUltralight
à partir d'unTag
, procédez comme suit:Kotlin
MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG))
Java
MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG));
Lire et écrire dans des tags
La lecture et l'écriture dans un tag NFC impliquent de l'obtenir à partir de l'intent et d'ouvrir la communication avec le tag. Vous devez définir votre propre pile de protocoles pour lire et écrire des données dans la balise. Toutefois, n'oubliez pas que vous pouvez toujours lire et écrire des données NDEF lorsque vous travaillez directement avec une balise. C’est à vous de décider comment vous voulez structurer les choses. 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 de premier plan
Le système de distribution de premier plan permet à une activité d'intercepter un intent et de revendiquer la priorité sur d'autres activités qui gèrent le même intent. L'utilisation de ce système implique de construire quelques structures de données pour qu'Android puisse envoyer les intents appropriés à votre application. Pour activer le système de répartition de premier plan:
- Ajoutez le code suivant dans la méthode
onCreate()
de votre activité :- Créez un objet
PendingIntent
modifiable afin que le système Android puisse y insérer les détails de la balise lorsqu'elle est analysée.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);
- Déclarez des filtres d'intent pour gérer les intents que vous souhaitez intercepter. Le système de distribution au premier plan vérifie les filtres d'intent spécifiés avec l'intent reçu lorsque l'appareil analyse une balise. Si tel est le cas, votre application gère l'intent. Si la correspondance n'est pas établie, le système de distribution de premier plan se rabat sur le système de distribution des intents.
La spécification d'un tableau
null
de filtres d'intent et de filtres technologiques indique que vous souhaitez filtrer toutes les balises de remplacement à l'intentTAG_DISCOVERED
. L'extrait de code ci-dessous gère tous les types MIME pourNDEF_DISCOVERED
. Vous ne devez 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, };
- Configurez un ensemble de technologies de tag que votre application souhaite gérer. Appelez la méthode
Object.class.getName()
pour obtenir la classe de la technologie que vous souhaitez utiliser.Kotlin
techListsArray = arrayOf(arrayOf<String>(NfcF::class.java.name))
Java
techListsArray = new String[][] { new String[] { NfcF.class.getName() } };
- Créez un objet
- Ignorez les rappels de cycle de vie de l'activité suivants, et ajoutez une logique pour activer et désactiver la distribution au premier plan lorsque l'activité perd (
onPause()
) et récupère (onResume()
) le focus.enableForegroundDispatch()
doit être appelé à partir du thread principal et uniquement lorsque l'activité est au premier plan (l'appel deonResume()
le garantit). Vous devez également implémenter le rappelonNewIntent
pour traiter les données du tag NFC scanné.
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 }