[JAVA] Lisez et voyez les informations sur la carte FeliCa (WAON)

Chose que tu veux faire

Il existe de nombreux échantillons pour lire IDm, qui est l'identifiant unique de la carte FeliCa, mais il n'y a pas beaucoup d'échantillons pour lire des informations sur diverses monnaies électroniques, donc je vais lire les informations sur la carte WAON que j'avais (numéro WAON pour le moment).

Les cartes WAON sont vendues aux mini-arrêts pour 300 yens.

supposition

spécification

Cela ressemble à ce qui suit.

Cela ressemble à ce qui suit.

スクリーンショット 2019-05-31 9.07.07.png

Flux de processus

Le déroulement général de la reconnaissance d'une carte à sa lecture est le suivant.

Préparation

Pour utiliser la fonction NFC, ajoutez ce qui suit à AndroidManifext.xml.

<uses-permission android:name="android.permission.NFC" />

En premier lieu, il est également nécessaire d'activer la fonction Reader / Writer du terminal lui-même.

la mise en oeuvre

J'essaierai de l'appliquer grossièrement.

MainActivity.java

Cette fois, j'utilise le mode lecteur parce que je veux activer / désactiver la fonction de lecture avec un bouton. L'activation / désactivation est contrôlée par le bouton de démarrage et le bouton d'arrêt, respectivement.

Lorsque la carte (Tag) est reconnue, onTagDiscovered () de la classe Callback est appelée, alors effectuez le traitement nécessaire. Utilisez transcive () pour exécuter la commande FeliCa. Cette fois, j'exécute un sondage et une lecture sans chiffrement.

l'interrogation est indispensable pour identifier l'ID de carte (IDm) de la destination de communication. Dans readWithoutEncryption, vous devez spécifier l '«emplacement» à lire dans le code de service. Cette fois, je veux lire le numéro WAON (numéro de carte), donc je spécifie 0x68 et 0x4f.

Le code de service n'a pas été publié, mais est inspecté par des bénévoles.

Si vous souhaitez utiliser d'autres services WAON (comme le solde) ou des informations sur d'autres cartes, obtenez le code de service et le format.

De plus, FeliCa dispose d'une zone à clé et d'une zone sans clé, et la zone telle que la charge est tenue dans la "zone à clé", de sorte qu'elle ne peut pas être exploitée par un tiers. Juste pour être sûr.

MainActivity.java


package jp.bluecode.waon_java;

import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.NfcF;
import android.os.Handler;
import android.os.Looper;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Formatter;

public class MainActivity extends AppCompatActivity {

    //Déclaration de widget
    TextView txt_idm;
    TextView txt_pmm;
    TextView txt_waonno;
    Button btn_start;
    Button btn_stop;

    //Déclaration de NfcAdapter
    NfcAdapter nfcAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Initialisation du widget
        txt_idm = findViewById(R.id.txt_idm);
        txt_pmm = findViewById(R.id.txt_pmm);
        txt_waonno = findViewById(R.id.txt_waonno);
        btn_start = findViewById(R.id.btn_start);
        btn_stop = findViewById(R.id.btn_stop);

        //Réglage initial (bascule)
        btn_stop.setEnabled(false);

        //Initialisation de NfcAdapter
        nfcAdapter = NfcAdapter.getDefaultAdapter(this);

        //définition de l'événement onClick
        btn_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                //Basculer les paramètres
                btn_start.setEnabled(false);
                btn_stop.setEnabled(true);

                //Initialisation de TextView
                txt_idm.setText("");
                txt_pmm.setText("");
                txt_waonno.setText("");

                //ReaderMode On
                nfcAdapter.enableReaderMode(MainActivity.this,new MyReaderCallback(),NfcAdapter.FLAG_READER_NFC_F,null);

            }
        });

        btn_stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                //Basculer les paramètres
                btn_start.setEnabled(true);
                btn_stop.setEnabled(false);

                //ReaderMode Off
                nfcAdapter.disableReaderMode(MainActivity.this);

            }
        });

    }

    //Description de la classe interne pour le rappel
    private class MyReaderCallback implements NfcAdapter.ReaderCallback{
        @Override
        public void onTagDiscovered(Tag tag){

            //Si l'étiquette est trouvée, enregistrez la sortie pour le moment
            Log.d("Hoge","Tag Discovered!");

            //Initialisez NfcF pour communiquer avec FeliCa
            NfcF nfc = NfcF.get(tag);

            try{

                nfc.connect();

                //Pour le moment, il est contrôlé par diverses commandes brutes FeliCa. tag pour idm.getId()Tu peux l'avoir.

                //commande d'interrogation (commande brute FeliCa) Spécifiez le code système 0xFE 0x00 de la zone commune.
                byte[] polling_request = {(byte)0x06,(byte)0x00,(byte)0xFE,(byte)0x00,(byte)0x00,(byte)0x00};
                //tableau d'octets pour recevoir la réponse

                //Envoyer / recevoir des commandes
                byte[] polling_response = nfc.transceive(polling_request);

                //Extraction d'idm
                byte[] idm = Arrays.copyOfRange(polling_response,2,10);
                //Sortir pmm (en plus)
                byte[] pmm = Arrays.copyOfRange(polling_response,11,19);

                //Convertir une chaîne d'octets en chaîne de caractères
                final String idmString = bytesToHexString(idm);
                final String pmmString = bytesToHexString(pmm);

                //traitement waonno

                //waonnno request
                //Assemblez la commande de requête à l'aide d'une fonction personnalisée
                byte[] waonno_request = readWithoutEncryption(idm,2);
                //Envoyer / recevoir des commandes
                byte[] wannno_response = nfc.transceive(waonno_request);

                //Découpez la partie du numéro WAON
                byte[] waonno = Arrays.copyOfRange(wannno_response,13,21);

                //Conversion de chaîne
                final String waonnoString = bytesToHexString(waonno);

                //Mise à jour de l'interface utilisateur du thread parent
                Handler mainHandler = new Handler(Looper.getMainLooper());
                mainHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        txt_idm.setText(idmString);
                        txt_pmm.setText(pmmString);
                        txt_waonno.setText(waonnoString);
                    }
                });

                nfc.close();

            }catch(Exception e){
                Log.e("Hoge",e.getMessage());
            }
        }
    }

    //Commande de lecture de zone non chiffrée (spécialisation de zone de numéro WAON)
    private byte[] readWithoutEncryption(byte[] idm, int blocksize) throws IOException {

        ByteArrayOutputStream bout = new ByteArrayOutputStream(100); //Pour le moment

        //Assemblage de la commande readWithoutEncryption
        bout.write(0); //Longueur de la commande (entrer plus tard)
        bout.write(0x06); //0x06 signifie lecture sans chiffrement
        bout.write(idm); //8byte:idm
        bout.write(1); //Nombre de services
        bout.write(0x4f); //Liste des codes de service Le numéro de la carte WAON est 684F
        bout.write(0x68); //Liste des codes de service
        bout.write(blocksize); //Nombre de blocs

        for(int i=0; i<blocksize; i++){
            bout.write(0x80); //Liste de blocage
            bout.write(i);
        }

        byte[] msg = bout.toByteArray();
        msg[0] = (byte)msg.length;

        return msg;
    }

    //Fonction de conversion d'octets en chaîne hexadécimale
    private String bytesToHexString(byte[] bytes){
        StringBuilder sb = new StringBuilder();
        Formatter formatter = new Formatter(sb);
        for(byte b: bytes){
            formatter.format("%02x",b);
        }
        //Retour au capital (il suffit d'ajuster l'apparence)
        return sb.toString().toUpperCase();
    }
}

c'est tout.

activity_main.xml

Activity_main.xml est également inclus pour référence, mais vous devez le disposer comme vous le souhaitez.

activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/lbl_top"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="Visionneuse de numéro WAON"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/lbl_idm"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="68dp"
        android:layout_marginTop="32dp"
        android:text="IDm:"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/lbl_top" />

    <TextView
        android:id="@+id/txt_idm"
        android:layout_width="180dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="32dp"
        android:background="#E8EAF6"
        app:layout_constraintStart_toEndOf="@+id/lbl_idm"
        app:layout_constraintTop_toBottomOf="@+id/lbl_top" />

    <TextView
        android:id="@+id/lbl_pmm"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="60dp"
        android:layout_marginTop="24dp"
        android:text="PMm:"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/lbl_idm" />

    <TextView
        android:id="@+id/txt_pmm"
        android:layout_width="180dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="24dp"
        android:background="#E8EAF6"
        app:layout_constraintStart_toEndOf="@+id/lbl_pmm"
        app:layout_constraintTop_toBottomOf="@+id/txt_idm" />

    <TextView
        android:id="@+id/lbl_wanno"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="24dp"
        android:layout_marginTop="24dp"
        android:text="Numéro WAON:"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/lbl_pmm" />

    <TextView
        android:id="@+id/txt_waonno"
        android:layout_width="180dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="24dp"
        android:background="#F3E5F5"
        app:layout_constraintStart_toEndOf="@+id/lbl_wanno"
        app:layout_constraintTop_toBottomOf="@+id/txt_pmm" />

    <Button
        android:id="@+id/btn_start"
        android:layout_width="160dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="Start Polling"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/txt_waonno" />

    <Button
        android:id="@+id/btn_stop"
        android:layout_width="160dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:text="Stop Polling"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_start" />
</android.support.constraint.ConstraintLayout>

AndroidManifest.xml

Ceci est également pour référence seulement. Je ne modifie que les autorisations NFC mentionnées au début.

AndroidManifest.xml


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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        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>
    </application>

    <uses-permission android:name="android.permission.NFC" />

</manifest>

Recommended Posts

Lisez et voyez les informations sur la carte FeliCa (WAON)
Lisez le solde IC de votre carte d'étudiant (Felica) sur Android
Compilez et exécutez Java sur la ligne de commande