Maintenant que la technologie NFC et l’émulation de cartes par HCE n’ont plus de secrets pour vous, il est temps de passer à la pratique en développant notre première application NFC – HCE sur mobile Android.

Dans ce tutoriel, nous allons nous concentrer sur les aspects NFC et HCE de l’application mobile. Il se peut donc que nous passions un peu vite sur certaines notions généralistes relatives au développement d’applications mobiles Android. Si vous êtes un parfait néophyte en la matière, de nombreuses ressources sont disponibles sur le net pour vous aider à démarrer.

L’objectif est de développer une application HCE qui retournera un identifiant lorsque le téléphone sera interrogé par un lecteur NFC, à la manière d’une carte sans contact de contrôle d’accès.

La mise en place

Pour commencer, il nous faut un environnement de développement – IDE – pour coder notre application Android. Il en existe plusieurs ; nous utiliserons ici Android Studio.

Afin de tester votre application, vous devez avoir un Smartphone Android – NFC bien entendu – avec une version d’OS compatible avec la technologie HCE. En effet, la technologie HCE n’est disponible qu’à partir de la version KitKat (4.4) d’Android. Il faudra donc choisir cette version comme version minimale dans la liste « Minimum SDK » lors de la création d’un nouveau projet.

Choix de la version minimale d'Android
Choix de la version minimale d’Android

Une fois la première phase de configuration passée, des applications par défaut vous sont proposées ; je vous conseille de choisir « Empty Activity » qui correspond à l’interface graphique la plus sommaire.

Choix de l'activité principale de l'application
Choix de l’activité principale de l’application

Il est à noter que le cœur de l’application HCE repose sur un « service » qui fonctionne en arrière-plan sans interface graphique. C’est-à-dire qu’une fois notre application installée, le service fonctionnera continuellement sans besoin d’ouvrir cette dernière.

Les mains dans le code

Une fois le projet créé, vous disposez d’une arborescence avec plusieurs dossiers et fichiers. Vous devriez avoir au moins les trois dossiers suivants :

  • le dossier manifests qui contient le fichier AndroidManifest.xml, qui est le fichier contenant les paramètres principaux de l’application ;
  • le dossier java dans lequel vous retrouvez le code source Java de vos activités. A ce stade, seule l’activité principale est créée, nommée par défaut MainActivity (si vous n’avez pas modifié le nom à la création du projet) ;
  • et enfin le dossier res dans lequel se trouvent, entre autres, les images, les fichiers de design graphique de vos activités (dans le sous-dossier layout), les références aux chaines de caractères de l’application, etc.

Pour le moment, l’application est somme toute assez basique et rien n’indique les fonctionnalités NFC et HCE que nous souhaitons lui ajouter. Trois actions principales sont à réaliser pour le développement de notre application HCE.

La première consiste à développer le service HCE. En effet, comme je l’évoquais précédemment, l’application repose sur un service qui tourne en tâche de fond. Pour ce faire, nous créons une activité (dans le dossier java) que nous nommons HceService.

Le service HCE

Pour créer le service sous Android Studio, faites un clic droit sur le dossier java dans lequel se trouve l’activité MainActivity puis choisissez New -> Java Class et nommez votre classe (qui n’est pas encore un service) HceService.  Ci-dessous, ce que vous devriez obtenir à ce stade.

package com.frugalprototype.ali.frugalhce;

/**
 * Created by Ali on 21/05/2016.
 */
public class HceService {
}

Pour information, il est possible de créer directement un service sous Android Studio ( New -> Service -> Service ) mais par souci de simplification, nous le faisons via la création d’une classe.

Voilà, donc cette classe fraichement créée, que nous allons transformer en service. Pour cela nous allons la faire hériter de HostApduService, ce qui va permettre à notre classe de devenir un service HCE en bénéficiant des propriétés et des méthodes de ce type de service. Nous allons également déclarer les fonctions nécessaires au bon fonctionnement de cette dernière comme le montre ci-dessous l’exemple fourni par Android.

public class HceService extends HostApduService {

    @Override
    public byte[] processCommandApdu(byte[] apdu, Bundle extras) {
      // à compléter avec votre code
    }
    @Override
    public void onDeactivated(int reason) {
     // à compléter avec votre code
    }

}

Cela devrait révéler quelques erreurs. C’est normal car il manque des bibliothèques pour que Android Studio comprenne le code. Pour ajouter automatiquement les bibliothèques manquantes, appuyer sur Alt + Entrée (opération à répéter dès que ce type d’erreurs se présente).

Il s’agit maintenant de compléter les fonctions. Particulièrement la première, nommée processCommandApdu, dans laquelle nous définissons les échanges entre un lecteur et notre application.

En effet, un lecteur sans contact scrute fréquemment son environnement proche (quelques centimètres) dans l’attente d’un support sans contact à lire. Lorsque ce dernier se présente, commence alors un échange de commandes entre les deux. Ce sont ces échanges que nous allons définir dans la fonction processCommandApdu. Comme le nom de la fonction l’indique, ces commandes sont au format APDU – Application Protocol Data Unit.

APDU et  AID

Les commandes APDU sont des commandes « haut niveau » à destination de la carte sans contact ou du mobile sans contact en ce qui nous concerne. Ainsi, on observe toujours le schéma de communication suivant entre une carte (ou un mobile) et un terminal : une commande APDU suivie d’une réponse APDU.

Je vous laisse approfondir la structure de ces commandes par vous-même. Gardez simplement à l’esprit que ce format est normalisé et que des commandes standard permettent une interopérabilité mondiale entre les lecteurs et les supports sans contact d’une même application.

Ainsi, une carte avec une application bancaire MasterCard (ou Visa ou American Express), sera lue partout dans le monde où les lecteurs respectent le format de commandes défini dans la norme ISO 7816-4.

Le lecteur identifie l’application contenu dans la carte sans contact (ou autre type de support sans contact) grâce à un identifiant d’application, appelé AID – Application Identifier. Ainsi, les lecteurs bancaires compatibles Visa et MasterCard interrogent tour à tour les cartes qui se présentent en tentant de sélectionner l’identifiant de l’application Visa ou celle de l’application MasterCard. C’est le même principe pour votre carte de transport, que le valideur interroge en sélectionnant l’application par son identifiant. Ceci implique, que si vous présentez une carte ne contenant pas l’application de transport de votre réseau de transport, vous n’irez pas plus loin…

Ce petit aparté, pour que vous ayez bien en tête le process entre le lecteur et notre application HCE : nous devons attribuer un identifiant à notre application, ce fameux AID ; le lecteur doit connaître cet identifiant pour interroger notre mobile NFC avec une commande SELECT AID qui comme son nom l’indique sélectionnera notre application par son AID. Rien de tel qu’une illustration pour clarifier tout cela.

Schéma simplifié d'un système de contrôle d'accès avec un mobile NFC-HCE
Schéma simplifié d’un système de contrôle d’accès avec un mobile NFC-HCE

Revenons donc à notre service. Nous allons lui demander de retourner un code d’accès (ou un identifiant) lorsqu’il reçoit une commande SELECT AID avec un AID correspondant à celui de notre application. Nous choisirons comme AID : F0 46 52 55 47 41 4c.

Notre AID commence par F0 comme le préconise Android, pour ne pas interférer avec les autres applications (je vous rappelle qu’il est préférable que votre application ait un identifiant unique). Ensuite 46 52 55 47 41 4c correspond simplement à la conversion de « FRUGAL » en hexadécimal.

Ci-dessous le résultat en code Java.

package com.frugalprototype.ali.frugalhce;

/**
 * Created by Ali on 16/05/2016.
 */
/** Import des bibliothèques utiles dans cette activité */

import android.nfc.cardemulation.HostApduService;
import android.os.Bundle;
import java.util.Arrays;

/* Notre activité hérite de HostApduService ; c'est cette heritage qui définit l'activité comme un service HCE */
public class HceService extends HostApduService {

    /*  Il s’agit en réalité ici de la commande SELECT AID + la taille en octet de l’AID + l’AID.
    Dans une application en production, il est préférable de déclarer la commande
    SELECT AID = {0x00, (byte) 0xA4, 0x04,0x00}
    et de déclarer l’AID séparément : AID = {0xF0, 0x46, 0x52, 0x55, 0x47, 0x41, 0x4c}.
    Sans oublier d’ajouter la taille de l’AID à la commande SELECT AID*/
    private static final byte[] SELECT_AID = {0x00, (byte) 0xA4, 0x04,0x00,0x07,(byte) 0xF0, 0x46, 0x52, 0x55, 0x47, 0x41, 0x4C};

    /* L'identifiant que nous allons retourner suivi d'un code qui
    indique le bon déroulé de l'échange (selon la norme ISO 7816-4). */
    private static final byte[] MY_UID = {0x01, 0x02, 0x03, 0x04, (byte) 0x90, 0x00};

    /* code d'erreur si l'échange n'est pas conforme*/
    private static final byte[] MY_ERROR = {0x6F, 0x00};
    @Override
    public byte[] processCommandApdu(byte[] apdu, Bundle extras) {

       /* Si le message reçu est égal à ce que nous attendons*/
        if (Arrays.equals(SELECT_AID, apdu))
        {
            /* Nous retournons un identifiant pour permettre l'accès à un bâtiment par exemple */
            return MY_UID;

        }

        /* Si le message n'est pas celui escompté, alors on retourne un code d’erreur */
        else return MY_ERROR;


    }
    @Override
    public void onDeactivated(int reason) {

 // Ne rien faire dans notre cas. Le prévoir pour une application professionnelle

    }
}

Le manifeste de l’application

Second étape : nous devons déclarer dans le fichier AndroidManifest.xml, notre service. Toujours dans ce même fichier, nous devons également indiquer que l’application utilise le NFC (pour avoir la permission de l’utilisateur).

Enfin, et ce sera la troisième et dernière étape, nous devons déclarer l’AID pour que le service s’active à la réception de la commande SELECT AID (seulement lorsque c’est le bon AID, j’insiste !).

Ci-dessous, le fichier AndroidManifest.xml après ajout de ces éléments.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.frugalprototype.ali.frugalhce">

<!-- Demander la permission à l'utilisateur pour l'utilisation du NFC -->
    <uses-permission android:name="android.permission.NFC" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- Déclaration de notre service HceService -->
        <service
            android:name=".HceService"
            android:exported="true"
            android:permission="android.permission.BIND_NFC_SERVICE" >
            <intent-filter>
                <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" />
            </intent-filter>
            <!-- Fichier dans lequel est déclaré l’AID. Nous devons créer un dossier xml dans le dossier values
            et créer un fichier apduservice.xml dans lequel nous allons déclarer l’AID de notre application   -->
            <meta-data
                android:name="android.nfc.cardemulation.host_apdu_service"
                android:resource="@xml/apduservice" />
        </service>

    </application>

</manifest>

La ligne de code android:resource= »@xml/apduservice » contenue dans la déclaration du service provoque une erreur car nous n’avons pas encore créé le dossier xml ni le fichier apduservice.xml dans lequel nous allons déclarer le ou les AIDs correspondant(s) à notre application.

Pour créer le dossier xml sur Android Studio, faites un clic droit sur le dossier app puis choisissez New -> Android Resource Directory et enfin choisissez xml dans le menu déroulant Resource type

Déclaration de l’AID

Une fois le dossier xml créé, vous pouvez alors créer le fichier apduservice.xml : faites un clic droit sur le dossier xml puis choisissez New -> XML resource file. Enfin, il ne reste plus qu’à le nommer comme indiqué dans le fichier AndroidManifest.xml, à savoir apduservice.

Ci-dessous, le contenu du fichier apduservice.xml avec la déclaration de notre AID.

<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:requireDeviceUnlock="false">
    <aid-group
        android:category="other">
        <aid-filter android:name="F046525547414c"/>
    </aid-group>
</host-apdu-service>

C’est tout en ce qui concerne l’application, vous pouvez la lancer en cliquant sur Run ou l’exporter au format apk pour la partager.

Test de l’application

Pour tester votre application, vous avez besoin d’un lecteur et d’un script (un bout de code). Cela fera probablement l’objet d’un autre tutoriel si le besoin s’en fait sentir. Toutefois pour ceux qui souhaitent se lancer dans l’aventure, je vous rappelle que ce lecteur doit envoyer un SELECT AID correspondant à celui attendu par notre application soit « 00 A4 04 00 07 F0 46 52 55 47 41 4C« .

Rassurez-vous, je ne vais pas vous laisser sans ressources : en ce qui concerne le lecteur, vous pouvez vous en procurer en cliquant sur ce lien.

Ensuite pour le programme, je vous propose deux exemples (un en Java et un autre en Python) ; je ne les détaillerai pas dans cet article. Cependant, n’hésitez pas à nous laisser vos questions ou commentaires.

Petite précision tout de même : pour utiliser l’exemple en Java, l’environnement Java doit être installé sur votre système ; même principe pour l’exemple en Python si ce n’est que vous devez également installer le module pyscard.

En résumé

En résumé, nous avons développé un service dans lequel nous avons défini les échanges entre le lecteur et notre application ; nous avons complété le fichier de configuration de notre application pour la prise en compte du service et de l’utilisation de la technologie NFC ; et enfin nous avons créé un fichier dans lequel nous avons déclaré notre AID.

Vous pouvez retrouver les sources de l’application sur GitHub ou directement télécharger l’application au format apk en cliquant sur ce lien.

Comme d’habitude, si des erreurs se sont glissées dans l’article, n’hésitez pas à nous en faire part.

Merci, et à très bientôt sur Frugal Prototype


Ali Benfattoum

Intrapreneur, Tech Enthusiast, IoT Expert, Smart City Specialist…
Suivez moi sur @alifrugal

All author posts
Related Posts

Privacy Preference Center