Principes de base de la technologie NFC

Ce document décrit les tâches NFC de base que vous effectuez sous Android. Il explique comment envoyer et recevoir des données NFC sous la forme de messages NDEF et décrit les API du framework Android compatibles avec ces fonctionnalités. Pour des sujets plus avancés, y compris une discussion sur l'utilisation de données non-NDEF, consultez la section Technologie NFC avancée.

Il existe deux cas d'utilisation principaux avec des données NDEF et Android:

  • Lire des données NDEF à partir d'un tag NFC
  • Diffusion de messages NDEF d'un appareil à un autre avec Android BeamTM

La lecture des données NDEF d'un tag NFC est gérée par le système de distribution des tags, qui analyse les tags NFC détectés, classe les données de manière appropriée et lance une application intéressée par les données catégorisées. Une application qui souhaite gérer le tag NFC analysé peut déclarer un filtre d'intent et demander à traiter les données.

La fonctionnalité Android BeamTM permet à un appareil de transmettre un message NDEF à un autre appareil en appuyant physiquement les uns sur les autres. Cette interaction est un moyen plus facile d'envoyer des données que d'autres technologies sans fil comme le Bluetooth, car avec le NFC, aucune découverte manuelle de l'appareil ni aucun association ne sont nécessaires. La connexion démarre automatiquement lorsque deux appareils se trouvent à portée. Android Beam est disponible via un ensemble d'API NFC, de sorte que toute application peut transmettre des informations entre les appareils. Par exemple, les applications Contacts, Navigateur et YouTube utilisent Android Beam pour partager des contacts, des pages Web et des vidéos avec d'autres appareils.

Le système de distribution des balises

Les appareils Android recherchent généralement des tags NFC lorsque l'écran est déverrouillé, sauf si la fonctionnalité NFC est désactivée dans le menu "Paramètres" de l'appareil. Lorsqu'un appareil Android détecte un tag NFC, le comportement souhaité est que l'activité la plus appropriée gère l'intent sans demander à l'utilisateur quelle application utiliser. Étant donné que les appareils scannent les tags NFC à une portée très courte, il est probable que si les utilisateurs sélectionnent manuellement une activité, ils soient obligés d'éloigner l'appareil du tag et interrompent la connexion. Vous devez développer votre activité de sorte qu'elle ne gère que les tags NFC dont elle a besoin afin d'empêcher l'affichage du sélecteur d'activité.

Pour vous aider à atteindre cet objectif, Android propose un système spécial de distribution de tags qui analyse les tags NFC scannés, les analyse, puis tente de localiser les applications intéressées par les données analysées. Pour ce faire, il procède comme suit:

  1. Analyser le tag NFC, et déterminer le type MIME ou un URI qui identifie la charge utile de données dans le tag.
  2. Encapsuler le type ou l'URI MIME et la charge utile dans un intent. Ces deux premières étapes sont décrites dans la section Comment les tags NFC sont-ils mappés avec les types MIME et les URI ?.
  3. Démarre une activité basée sur l'intent. Pour en savoir plus, consultez la section Comment les tags NFC sont-ils distribués aux applications.

Comment les tags NFC sont-ils mappés avec les types MIME et les URI ?

Avant de commencer à écrire vos applications NFC, il est important de comprendre les différents types de tags NFC, la façon dont le système de distribution des tags les analyse, ainsi que le travail spécial effectué par le système de distribution des tags lorsqu'il détecte un message NDEF. Les tags NFC sont compatibles avec un large éventail de technologies. Des données peuvent également y être écrites de différentes manières. Android est l'appareil le plus compatible avec la norme NDEF, qui est définie par le forum NFC.

Les données NDEF sont encapsulées dans un message (NdefMessage) contenant un ou plusieurs enregistrements (NdefRecord). Chaque enregistrement NDEF doit être correctement formé conformément à la spécification du type d'enregistrement que vous souhaitez créer. Android accepte également d'autres types de tags ne contenant pas de données NDEF. Vous pouvez les utiliser à l'aide des classes du package android.nfc.tech. Pour en savoir plus sur ces technologies, consultez la rubrique Fonctionnalités NFC avancées. L'utilisation de ces autres types de tags implique d'écrire votre propre pile de protocoles pour communiquer avec les tags. Nous vous recommandons donc d'utiliser NDEF dans la mesure du possible pour faciliter le développement et assurer une compatibilité maximale avec les appareils Android.

Remarque:Pour télécharger les spécifications NDEF complètes, accédez au site Spécifications du forum et documents d'application sur le NFC et consultez la section Créer des types courants d'enregistrements NDEF pour obtenir des exemples de création d'enregistrements NDEF.

Maintenant que vous en savez un peu plus sur les tags NFC, les sections suivantes décrivent plus en détail comment Android gère les tags au format NDEF. Lorsqu'un appareil Android analyse un tag NFC contenant des données au format NDEF, il analyse le message et tente de déterminer le type MIME des données ou l'URI d'identification. Pour ce faire, le système lit le premier NdefRecord dans NdefMessage pour déterminer comment interpréter l'intégralité du message NDEF (un message NDEF peut comporter plusieurs enregistrements NDEF). Dans un message NDEF correctement formé, le premier élément NdefRecord contient les champs suivants:

TNF 3 bits (Type Name Format)
Indique comment interpréter le champ de type de longueur variable. Les valeurs valides sont décrites dans le tableau 1.
Type de longueur variable
Décrit le type d'enregistrement. Si vous utilisez TNF_WELL_KNOWN, utilisez ce champ pour spécifier la définition du type d'enregistrement (RTD). Les valeurs RTD valides sont décrites dans le Tableau 2.
ID de longueur variable
Identifiant unique de l'enregistrement. Ce champ n'est pas souvent utilisé, mais si vous devez identifier une balise de manière unique, vous pouvez créer un ID pour celle-ci.
Charge utile de longueur variable
Charge utile de données réelle que vous souhaitez lire ou écrire. Un message NDEF peut contenir plusieurs enregistrements NDEF. Par conséquent, ne partez pas du principe que la charge utile complète se trouve dans le premier enregistrement NDEF du message NDEF.

Le système de distribution des tags utilise les champs TNF et de type pour essayer de mapper un type ou un URI MIME au message NDEF. En cas de succès, il encapsule ces informations dans un intent ACTION_NDEF_DISCOVERED avec la charge utile réelle. Toutefois, il arrive que le système de distribution des balises ne puisse pas déterminer le type de données en fonction du premier enregistrement NDEF. Cela se produit lorsque les données NDEF ne peuvent pas être mappées avec un type ou un URI MIME, ou lorsque le tag NFC ne contient pas de données NDEF pour commencer. Dans ce cas, un objet Tag contenant des informations sur les technologies de la balise et la charge utile est encapsulé dans un intent ACTION_TECH_DISCOVERED.

Le Tableau 1 explique comment le système de distribution des balises mappe les champs TNF et de type aux types ou URI MIME. Il décrit également les TNF qui ne peuvent pas être mappés avec un type ou un URI MIME. Dans ce cas, le système de distribution des balises utilise ACTION_TECH_DISCOVERED.

Par exemple, si le système de distribution des balises rencontre un enregistrement de type TNF_ABSOLUTE_URI, il mappe le champ de type de longueur variable de cet enregistrement dans un URI. Le système de distribution des balises encapsule cet URI dans le champ de données d'un intent ACTION_NDEF_DISCOVERED ainsi que d'autres informations sur la balise, telles que la charge utile. En revanche, s'il rencontre un enregistrement de type TNF_UNKNOWN, il crée un intent qui encapsule les technologies de la balise.

Tableau 1. TNF compatibles et leurs mappages

Format du nom de type (TNF) Mappage
TNF_ABSOLUTE_URI URI basé sur le champ de type.
TNF_EMPTY revient à ACTION_TECH_DISCOVERED.
TNF_EXTERNAL_TYPE URI basé sur l'URI dans le champ de type. L'URI est encodé dans le champ de type NDEF sous une forme abrégée: <domain_name>:<service_name>. Android le mappe avec un URI au format suivant : vnd.android.nfc://ext/<domain_name>:<service_name>.
TNF_MIME_MEDIA Type MIME en fonction du champ de type.
TNF_UNCHANGED Le premier enregistrement n'est pas valide. La valeur ACTION_TECH_DISCOVERED est donc utilisée.
TNF_UNKNOWN revient à ACTION_TECH_DISCOVERED.
TNF_WELL_KNOWN Type ou URI MIME en fonction de la définition du type d'enregistrement (RTD, Record Type Definition) que vous définissez dans le champ "Type". Consultez le Tableau 2 pour en savoir plus sur les indications de ce type et leurs mises en correspondance.

Tableau 2. RTD compatibles pour TNF_WELL_KNOWN et leurs mappages

Définition du type d'enregistrement (DAR) Mappage
RTD_ALTERNATIVE_CARRIER revient à ACTION_TECH_DISCOVERED.
RTD_HANDOVER_CARRIER revient à ACTION_TECH_DISCOVERED.
RTD_HANDOVER_REQUEST revient à ACTION_TECH_DISCOVERED.
RTD_HANDOVER_SELECT revient à ACTION_TECH_DISCOVERED.
RTD_SMART_POSTER URI basé sur l'analyse de la charge utile.
RTD_TEXT Type MIME de text/plain.
RTD_URI URI basé sur la charge utile.

Distribution des tags NFC aux applications

Une fois que le système de distribution des balises a créé un intent qui encapsule le tag NFC et ses informations d'identification, il envoie l'intent à une application intéressée qui filtre l'intent. Si plusieurs applications peuvent gérer l'intent, le sélecteur d'activité est présenté afin que l'utilisateur puisse sélectionner l'activité. Le système de distribution des balises définit trois intents, qui sont répertoriés de la priorité la plus haute à la plus basse:

  1. ACTION_NDEF_DISCOVERED: cet intent permet de démarrer une activité lorsqu'une balise contenant une charge utile NDEF est analysée et d'un type reconnu. Il s'agit de l'intent ayant la priorité la plus élevée. Le système de distribution des balises tente de démarrer une activité avec cet intent avant tout autre intent, dans la mesure du possible.
  2. ACTION_TECH_DISCOVERED: si aucune activité n'est enregistrée pour gérer l'intent ACTION_NDEF_DISCOVERED, le système de distribution des balises tente de démarrer une application avec cet intent. Cet intent est également démarré directement (sans démarrer ACTION_NDEF_DISCOVERED au préalable) si la balise analysée contient des données NDEF qui ne peuvent pas être mappées avec un type ou un URI MIME, ou si la balise ne contient pas de données NDEF, mais utilise une technologie de balise connue.
  3. ACTION_TAG_DISCOVERED: cet intent est démarré si aucune activité ne gère les intents ACTION_NDEF_DISCOVERED ou ACTION_TECH_DISCOVERED.

Le fonctionnement de base du système de distribution des balises est le suivant:

  1. Essayez de démarrer une activité avec l'intent créé par le système de distribution des tags lors de l'analyse du tag NFC (ACTION_NDEF_DISCOVERED ou ACTION_TECH_DISCOVERED).
  2. Si aucune activité ne filtre cet intent, essayez de démarrer une activité avec l'intent de priorité suivant (ACTION_TECH_DISCOVERED ou ACTION_TAG_DISCOVERED) jusqu'à ce qu'une application filtre l'intent ou que le système de distribution des balises essaie tous les intents possibles.
  3. Si aucune application ne filtre les intents, ne faites rien.
Figure 1 Système de distribution des balises

Dans la mesure du possible, utilisez des messages NDEF et l'intent ACTION_NDEF_DISCOVERED, car il s'agit du plus spécifique des trois. Cet intent vous permet de démarrer votre application à un moment plus approprié que les deux autres intents, offrant ainsi une meilleure expérience à l'utilisateur.

Demander l'accès NFC dans le fichier manifeste Android

Pour pouvoir accéder au matériel NFC d'un appareil et gérer correctement les intents NFC, déclarez les éléments suivants dans le fichier AndroidManifest.xml:

  • L'élément NFC <uses-permission> pour accéder au matériel NFC :
    <uses-permission android:name="android.permission.NFC" />
    
  • Version minimale du SDK que votre application peut prendre en charge. Le niveau d'API 9 n'accepte que la distribution limitée des balises via ACTION_TAG_DISCOVERED et ne donne accès aux messages NDEF que via l'extra EXTRA_NDEF_MESSAGES. Aucune autre propriété de tag ou opération d'E/S n'est accessible. Le niveau d'API 10 inclut une prise en charge complète des lecteurs/rédacteurs ainsi que le transfert NDEF au premier plan. Le niveau d'API 14 facilite le transfert de messages NDEF vers d'autres appareils avec Android Beam et des méthodes pratiques pour créer des enregistrements NDEF.
    <uses-sdk android:minSdkVersion="10"/>
    
  • L'élément uses-feature pour que votre application n'apparaisse dans Google Play que pour les appareils équipés de la technologie NFC :
    <uses-feature android:name="android.hardware.nfc" android:required="true" />
    

    Si votre application utilise la fonctionnalité NFC, mais qu'elle n'est pas essentielle, vous pouvez omettre l'élément uses-feature et vérifier la disponibilité de la technologie NFC au moment de l'exécution en vérifiant si getDefaultAdapter() est null.

Filtrer les intents NFC

Pour démarrer votre application lorsqu'un tag NFC que vous souhaitez gérer est analysé, votre application peut filtrer un, deux ou les trois intents NFC dans le fichier manifeste Android. Toutefois, vous souhaitez généralement filtrer l'intent ACTION_NDEF_DISCOVERED pour mieux contrôler le moment où votre application démarre. L'intent ACTION_TECH_DISCOVERED est une solution de secours pour ACTION_NDEF_DISCOVERED lorsqu'aucune application ne filtre ACTION_NDEF_DISCOVERED ou lorsque la charge utile n'est pas NDEF. Le filtrage sur ACTION_TAG_DISCOVERED est généralement trop général pour une catégorie à filtrer. De nombreuses applications filtrent ACTION_NDEF_DISCOVERED ou ACTION_TECH_DISCOVERED avant ACTION_TAG_DISCOVERED. Il est donc faible que votre application se lance. ACTION_TAG_DISCOVERED n'est disponible qu'en dernier recours pour les applications à filtrer dans les cas où aucune autre application n'est installée pour gérer l'intent ACTION_NDEF_DISCOVERED ou ACTION_TECH_DISCOVERED.

Étant donné que les déploiements de tags NFC varient et que vous ne pouvez pas toujours le contrôler, ce n'est pas toujours possible. C'est pourquoi vous pouvez utiliser les deux autres intents si nécessaire. Lorsque vous contrôlez les types de balises et les données écrites, nous vous recommandons d'utiliser le format NDEF pour mettre en forme vos balises. Les sections suivantes décrivent comment filtrer chaque type d'intent.

ACTION_NDEF_DISCOVERED

Pour filtrer les intents ACTION_NDEF_DISCOVERED, déclarez le filtre d'intent ainsi que le type de données que vous souhaitez filtrer. L'exemple suivant filtre les intents ACTION_NDEF_DISCOVERED dont le type MIME est 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>

L'exemple suivant filtre un URI au format 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_DÉCOUVERTE

Si votre activité filtre l'intent ACTION_TECH_DISCOVERED, vous devez créer un fichier de ressources XML spécifiant les technologies compatibles avec votre activité dans un ensemble tech-list. Votre activité est considérée comme une correspondance si un ensemble tech-list est un sous-ensemble des technologies compatibles avec la balise. Vous pouvez l'obtenir en appelant getTechList().

Par exemple, si le tag analysé est compatible avec MifareClassic, NdefFormatable et NfcA, votre ensemble tech-list doit spécifier ces trois, deux ou l'une de ces technologies (et rien d'autre) pour que votre activité soit mise en correspondance.

L'exemple suivant définit toutes les technologies. Vous devez supprimer ceux qui ne sont pas compatibles avec votre tag NFC. Enregistrez ce fichier (vous pouvez le nommer comme vous le souhaitez) dans le dossier <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>

Vous pouvez également spécifier plusieurs ensembles tech-list. Chacun des ensembles tech-list est considéré comme indépendant, et votre activité est considérée comme une correspondance si un ensemble tech-list unique est un sous-ensemble des technologies renvoyées par getTechList(). Fournit la sémantique AND et OR pour les technologies de correspondance. L'exemple suivant correspond aux tags compatibles avec les technologies NfcA et Ndef, ou avec les technologies NfcB et 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>

Dans votre fichier AndroidManifest.xml, spécifiez le fichier de ressources que vous venez de créer dans l'élément <meta-data> de l'élément <activity>, comme dans l'exemple suivant:

<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>

Pour en savoir plus sur l'utilisation des technologies de balise et de l'intent ACTION_TECH_DISCOVERED, consultez la section Utiliser des technologies de balise compatibles dans le document "NFC avancé".

ACTION_TAG_DÉCOUVERTE

Pour filtrer sur ACTION_TAG_DISCOVERED, utilisez le filtre d'intent suivant:

<intent-filter>
    <action android:name="android.nfc.action.TAG_DISCOVERED"/>
</intent-filter>

Obtenir des informations à partir d'intents

Si une activité démarre en raison d'un intent NFC, vous pouvez obtenir des informations sur le tag NFC scanné à partir de l'intent. Les intents peuvent contenir les extras suivants en fonction de la balise analysée:

Pour obtenir ces extras, vérifiez si votre activité a été lancée avec l'un des intents NFC pour vous assurer qu'un tag a été scanné, puis récupérez les extras de l'intent. L'exemple suivant recherche l'intent ACTION_NDEF_DISCOVERED et obtient les messages NDEF d'un extra d'intent.

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.
            ...
        }
    }
}

Vous pouvez également obtenir un objet Tag à partir de l'intent, qui contiendra la charge utile et vous permettra d'énumérer les technologies de la balise:

Kotlin

val tag: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)

Java

Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);

Créer des types courants d'enregistrements NDEF

Cette section explique comment créer des types courants d'enregistrements NDEF pour vous aider lors de l'écriture dans des tags NFC ou de l'envoi de données avec Android Beam. À partir d'Android 4.0 (niveau d'API 14), la méthode createUri() est disponible pour vous aider à créer automatiquement des enregistrements d'URI. À partir d'Android 4.1 (niveau d'API 16), createExternal() et createMime() sont disponibles pour vous aider à créer des enregistrements NDEF de type externe et MIME. Dans la mesure du possible, utilisez ces méthodes d'assistance pour éviter les erreurs lors de la création manuelle d'enregistrements NDEF.

Cette section explique également comment créer le filtre d'intent correspondant à l'enregistrement. Tous ces exemples d'enregistrements NDEF doivent figurer dans le premier enregistrement NDEF du message NDEF que vous écrivez dans un tag ou un Beaming.

TNF_ABSOLUTE_URI (URI ABSOLUTE)

Remarque:Nous vous recommandons d'utiliser le type RTD_URI au lieu de TNF_ABSOLUTE_URI, car il est plus efficace.

Vous pouvez créer un enregistrement NDEF TNF_ABSOLUTE_URI de la manière suivante :

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]);

Le filtre d'intent de l'enregistrement NDEF précédent se présente comme suit:

<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

Vous pouvez créer un enregistrement NDEF TNF_MIME_MEDIA de différentes manières:

En utilisant la méthode 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")));

Créez le NdefRecord manuellement:

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")));

Le filtre d'intent de l'enregistrement NDEF précédent se présente comme suit:

<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 avec RTD_TEXT

Vous pouvez créer un enregistrement NDEF TNF_WELL_KNOWN de la manière suivante:

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;
}

Le filtre d'intent de l'enregistrement NDEF précédent se présente comme suit:

<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 avec RTD_URI

Vous pouvez créer un enregistrement NDEF TNF_WELL_KNOWN de différentes manières:

En utilisant la méthode createUri(String):

Kotlin

val rtdUriRecord1 = NdefRecord.createUri("https://example.com")

Java

NdefRecord rtdUriRecord1 = NdefRecord.createUri("https://example.com");

En utilisant la méthode 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);

Créez le NdefRecord manuellement:

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);

Le filtre d'intent de l'enregistrement NDEF précédent se présente comme suit:

<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>

TYPE_EXTERNE_TNF

Vous pouvez créer un enregistrement NDEF TNF_EXTERNAL_TYPE de différentes manières:

En utilisant la méthode 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);

Créez le NdefRecord manuellement:

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);

Le filtre d'intent de l'enregistrement NDEF précédent se présente comme suit:

<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>

Utilisez TNF_EXTERNAL_TYPE pour déployer des tags NFC plus génériques afin de mieux prendre en charge les appareils Android et non Android.

Remarque : Les URN pour TNF_EXTERNAL_TYPE utilisent le format canonique urn:nfc:ext:example.com:externalType. Toutefois, la spécification NFC Forum RTD déclare que la partie urn:nfc:ext: de l'URI doit être omise de l'enregistrement NDEF. Il vous suffit donc de fournir le domaine (example.com dans l'exemple) et le type (externalType dans l'exemple), séparés par le signe deux-points. Lors de la distribution de TNF_EXTERNAL_TYPE, Android convertit l'URI de urn:nfc:ext:example.com:externalType en URI vnd.android.nfc://ext/example.com:externalType, qui est déclaré par le filtre d'intent de l'exemple.

Enregistrements d'applications Android

Introduit dans Android 4.0 (niveau d'API 14), un enregistrement d'application Android (AAR) offre une plus grande certitude que votre application est démarrée lorsqu'un tag NFC est scanné. Une AAR contient le nom de package d'une application intégrée dans un enregistrement NDEF. Vous pouvez ajouter un AAR à n'importe quel enregistrement NDEF de votre message NDEF, car Android recherche des AAR dans l'ensemble du message NDEF. S'il trouve un AAR, il démarre l'application en fonction du nom du package dans l'AAR. Si l'application n'est pas présente sur l'appareil, Google Play est lancé pour télécharger l'application.

Les AAR sont utiles si vous souhaitez empêcher d'autres applications de filtrer le même intent et de gérer potentiellement des balises spécifiques que vous avez déployées. Les AAR ne sont compatibles qu'au niveau de l'application, en raison de la contrainte de nom de package, et non au niveau de l'activité, comme avec le filtrage des intents. Si vous souhaitez gérer un intent au niveau de l'activité, utilisez des filtres d'intent.

Si une balise contient un fichier AAR, le système de distribution des balises est distribué de la manière suivante:

  1. Essayez de démarrer une activité à l'aide d'un filtre d'intent comme vous le faites habituellement. Si l'activité qui correspond à l'intent correspond également à l'AAR, démarrez-la.
  2. Si l'activité qui filtre l'intent ne correspond pas à l'AAR, si plusieurs activités peuvent gérer l'intent ou si aucune activité ne gère l'intent, démarrez l'application spécifiée par l'AAR.
  3. Si aucune application ne peut commencer avec l'AAR, accédez à Google Play pour télécharger l'application basée sur l'AAR.

Remarque:Vous pouvez remplacer les AAR et le système de distribution des intents avec le système de distribution de premier plan, ce qui permet à une activité de premier plan d'être prioritaire lorsqu'un tag NFC est détecté. Avec cette méthode, l'activité doit être au premier plan pour remplacer les AAR et le système de distribution des intents.

Si vous souhaitez toujours filtrer les balises analysées qui ne contiennent pas d'AAR, vous pouvez déclarer des filtres d'intent comme d'habitude. Cela est utile si votre application est intéressée par d'autres balises ne contenant pas d'AAR. Par exemple, vous souhaitez peut-être vous assurer que votre application gère les balises propriétaires que vous déployez, ainsi que les balises générales déployées par des tiers. N'oubliez pas que les AAR sont spécifiques aux appareils Android 4.0 ou version ultérieure. Par conséquent, lorsque vous déployez des balises, vous souhaiterez probablement utiliser une combinaison d'AAR et de types/URI MIME pour prendre en charge le plus large éventail d'appareils. En outre, lorsque vous déployez des tags NFC, réfléchissez à la manière dont vous souhaitez écrire vos tags NFC pour permettre la prise en charge de la plupart des appareils (Android et autres). Pour ce faire, vous pouvez définir un type ou un URI MIME relativement unique afin de permettre aux applications de les distinguer plus facilement.

Android fournit une API simple pour créer un fichier AAR, createApplicationRecord(). Il vous suffit d'intégrer l'AAR n'importe où dans votre NdefMessage. Vous ne souhaitez pas utiliser le premier enregistrement de votre NdefMessage, sauf si l'AAR est le seul enregistrement dans NdefMessage. En effet, le système Android vérifie le premier enregistrement d'un NdefMessage pour déterminer le type MIME ou l'URI de la balise, qui est utilisé pour créer un intent à filtrer par les applications. Le code suivant vous montre comment créer une 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")}
        );
)

Transférer des messages NDEF vers d'autres appareils

Android Beam permet un échange de données peer-to-peer simple entre deux appareils Android. L'application qui souhaite partager des données vers un autre appareil doit être au premier plan, et l'appareil recevant les données ne doit pas être verrouillé. Lorsque l'appareil de partage est suffisamment proche du récepteur, il affiche l'interface utilisateur "Appuyer pour partager". L'utilisateur peut ensuite choisir de partager ou non le message avec l'appareil récepteur.

Remarque:Le transfert NDEF de premier plan était disponible au niveau d'API 10, qui offre des fonctionnalités semblables à celles d'Android Beam. Ces API sont depuis obsolètes, mais sont disponibles pour prendre en charge les appareils plus anciens. Pour en savoir plus, consultez les enableForegroundNdefPush().

Vous pouvez activer Android Beam pour votre application en appelant l'une des deux méthodes suivantes:

  • setNdefPushMessage(): accepte un NdefMessage à définir comme message à partager. Le message est automatiquement diffusé lorsque deux appareils sont suffisamment proches l'un de l'autre.
  • setNdefPushMessageCallback() : accepte un rappel contenant un createNdefMessage() qui est appelé lorsqu'un appareil est à portée pour partager des données. Le rappel vous permet de créer le message NDEF uniquement si nécessaire.

Une activité ne peut transmettre qu'un seul message NDEF à la fois. setNdefPushMessageCallback() est donc prioritaire sur setNdefPushMessage() si les deux sont définis. Pour utiliser Android Beam, les consignes générales suivantes doivent être respectées:

  • L'activité qui transmet les données doit se trouver au premier plan. Les écrans des deux appareils doivent être déverrouillés.
  • Vous devez encapsuler les données que vous partagez dans un objet NdefMessage.
  • L'appareil NFC qui reçoit les données transmises doit être compatible avec le protocole push NDEF com.android.npp ou le protocole SNEP (Simple NDEF Exchange Protocol) du forum NFC. Le protocole com.android.npp est requis pour les appareils équipés du niveau d'API 9 (Android 2.3) à niveau d'API 13 (Android 3.2). com.android.npp et SNEP sont tous deux requis à partir du niveau d'API 14 (Android 4.0).

Remarque:Si votre activité active Android Beam et qu'elle est exécutée au premier plan, le système de distribution des intents standard est désactivé. Toutefois, si votre activité active également la distribution de premier plan, elle peut toujours analyser les balises correspondant aux filtres d'intent définis dans la distribution de premier plan.

Pour activer Android Beam:

  1. Créez un NdefMessage contenant les NdefRecord que vous souhaitez transférer sur l'autre appareil.
  2. Appelez setNdefPushMessage() avec un NdefMessage ou appelez setNdefPushMessageCallback en transmettant un objet NfcAdapter.CreateNdefMessageCallback dans la méthode onCreate() de votre activité. Ces méthodes nécessitent au moins une activité que vous souhaitez activer avec Android Beam, ainsi qu'une liste facultative d'autres activités à activer.

    En général, vous utilisez normalement setNdefPushMessage() si votre activité a uniquement besoin de transmettre le même message NDEF en permanence, lorsque deux appareils sont à portée pour communiquer. Vous utilisez setNdefPushMessageCallback lorsque votre application se soucie du contexte actuel et souhaite transmettre un message NDEF en fonction de ce que l'utilisateur fait dans l'application.

L'exemple suivant montre comment une activité simple appelle NfcAdapter.CreateNdefMessageCallback dans la méthode onCreate() d'une activité (consultez AndroidBeamDemo pour l'exemple complet). Cet exemple comporte également des méthodes pour vous aider à créer un enregistrement 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()));
    }
}

Notez que ce code commente un AAR que vous pouvez supprimer. Si vous activez l'AAR, l'application spécifiée dans l'AAR reçoit toujours le message Android Beam. Si l'application n'est pas présente, Google Play lance le téléchargement. Par conséquent, le filtre d'intent suivant n'est pas techniquement nécessaire pour les appareils Android 4.0 ou version ultérieure si l'AAR est utilisée:

<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>

Avec ce filtre d'intent, l'application com.example.android.beam peut désormais être lancée lorsqu'elle analyse un tag NFC ou reçoit un Android Beam avec un AAR de type com.example.android.beam, ou lorsqu'un message au format NDEF contient un enregistrement MIME de type application/vnd.com.example.android.beam.

Même si les AAR garantissent le démarrage ou le téléchargement d'une application, les filtres d'intent sont recommandés, car ils vous permettent de démarrer une activité de votre choix dans votre application au lieu de toujours démarrer l'activité principale dans le package spécifié par une AAR. Les AAR n'ont pas de précision au niveau de l'activité. En outre, étant donné que certains appareils Android ne sont pas compatibles avec les AAR, vous devez également intégrer des informations d'identification dans le premier enregistrement NDEF de vos messages NDEF et les filtrer, au cas où. Pour en savoir plus sur la création d'enregistrements, consultez la page Créer des types courants d'enregistrements NDEF.