[JAVA] Lesen und sehen Sie die Informationen auf der FeliCa (WAON) -Karte

Was du machen willst

Es gibt viele Beispiele zum Lesen von IDm, der eindeutigen ID der FeliCa-Karte, aber es gibt nicht viele Beispiele zum Lesen von Informationen über verschiedene elektronische Gelder. Daher werde ich die Informationen auf der WAON-Karte lesen, die ich hatte (WAON-Nummer vorerst).

WAON-Karten werden an kleinen Haltestellen für 300 Yen verkauft.

Annahme

Spezifikation

Es sieht wie folgt aus.

Es sieht wie folgt aus.

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

Prozessablauf

Der allgemeine Ablauf vom Erkennen einer Karte zum Lesen ist wie folgt.

Vorbereitung

Fügen Sie zur Verwendung der NFC-Funktion Folgendes zu AndroidManifext.xml hinzu.

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

Zunächst muss auch die Reader / Writer-Funktion des Terminals selbst aktiviert werden.

Implementierung

Ich werde versuchen, es grob umzusetzen.

MainActivity.java

Dieses Mal verwende ich den Lesemodus, weil ich die Lesefunktion mit einer Taste ein- und ausschalten möchte. Das Aktivieren / Deaktivieren wird über die Starttaste bzw. die Stopptaste gesteuert.

Wenn die Karte (Tag) erkannt wird, wird onTagDiscovered () der Callback-Klasse aufgerufen. Führen Sie daher die erforderliche Verarbeitung durch. Verwenden Sie transcive (), um den FeliCa-Befehl auszuführen. Dieses Mal führe ich Polling und readWithoutEncryption aus.

Abfragen sind unabdingbar, um die Karten-ID (IDm) des Kommunikationsziels zu identifizieren. In readWithoutEncryption müssen Sie den "Speicherort" angeben, an dem der Servicecode eingelesen werden soll. Dieses Mal möchte ich die WAON-Nummer (Kartennummer) lesen, also gebe ich 0x68 und 0x4f an.

Der Servicecode wurde nicht veröffentlicht, wird jedoch von Freiwilligen überprüft.

Wenn Sie andere WAON-Dienste (z. B. Guthaben) oder Informationen auf anderen Karten verwenden möchten, erhalten Sie den Dienstcode und das Format.

Darüber hinaus verfügt FeliCa über einen Schlüsselbereich und einen schlüssellosen Bereich, und der Bereich wie die Ladung befindet sich im "Schlüsselbereich", sodass er nicht von Dritten betrieben werden kann. Nur um sicher zu gehen.

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 {

    //Widget-Deklaration
    TextView txt_idm;
    TextView txt_pmm;
    TextView txt_waonno;
    Button btn_start;
    Button btn_stop;

    //Erklärung von NfcAdapter
    NfcAdapter nfcAdapter;

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

        //Widget-Initialisierung
        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);

        //Grundeinstellung (umschalten)
        btn_stop.setEnabled(false);

        //Initialisierung von NfcAdapter
        nfcAdapter = NfcAdapter.getDefaultAdapter(this);

        //Festlegen des onClick-Ereignisses
        btn_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                //Einstellungen umschalten
                btn_start.setEnabled(false);
                btn_stop.setEnabled(true);

                //TextView-Initialisierung
                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) {

                //Einstellungen umschalten
                btn_start.setEnabled(true);
                btn_stop.setEnabled(false);

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

            }
        });

    }

    //Beschreibung der inneren Klasse für Callback
    private class MyReaderCallback implements NfcAdapter.ReaderCallback{
        @Override
        public void onTagDiscovered(Tag tag){

            //Wenn das Tag gefunden wird, protokollieren Sie die Ausgabe vorerst
            Log.d("Hoge","Tag Discovered!");

            //Initialisieren Sie NfcF, um mit FeliCa zu kommunizieren
            NfcF nfc = NfcF.get(tag);

            try{

                nfc.connect();

                //Derzeit wird es von verschiedenen FeliCa-Rohbefehlen gesteuert. Tag für idm.getId()Du kannst es haben.

                //Polling-Befehl (FeliCa Raw-Befehl) Geben Sie den Systemcode 0xFE 0x00 des allgemeinen Bereichs an.
                byte[] polling_request = {(byte)0x06,(byte)0x00,(byte)0xFE,(byte)0x00,(byte)0x00,(byte)0x00};
                //Byte-Array zum Empfangen einer Antwort

                //Befehle senden / empfangen
                byte[] polling_response = nfc.transceive(polling_request);

                //Extraktion von idm
                byte[] idm = Arrays.copyOfRange(polling_response,2,10);
                //Pmm herausnehmen (zusätzlich)
                byte[] pmm = Arrays.copyOfRange(polling_response,11,19);

                //Konvertieren Sie die Byte-Zeichenfolge in eine Zeichenfolge
                final String idmString = bytesToHexString(idm);
                final String pmmString = bytesToHexString(pmm);

                //waonno Verarbeitung

                //waonnno request
                //Stellen Sie den Anforderungsbefehl mit einer benutzerdefinierten Funktion zusammen
                byte[] waonno_request = readWithoutEncryption(idm,2);
                //Befehle senden / empfangen
                byte[] wannno_response = nfc.transceive(waonno_request);

                //Schneiden Sie den WAON-Nummernteil aus
                byte[] waonno = Arrays.copyOfRange(wannno_response,13,21);

                //String-Konvertierung
                final String waonnoString = bytesToHexString(waonno);

                //Aktualisierung der Benutzeroberfläche des übergeordneten Threads
                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());
            }
        }
    }

    //Befehl zum Lesen eines nicht verschlüsselten Bereichs (WAON-Nummernbereichsspezialisierung)
    private byte[] readWithoutEncryption(byte[] idm, int blocksize) throws IOException {

        ByteArrayOutputStream bout = new ByteArrayOutputStream(100); //Vorerst

        //Befehlsassembly readWithoutEncryption
        bout.write(0); //Befehlslänge (später eingeben)
        bout.write(0x06); //0x06 steht für Lesen ohne Verschlüsselung
        bout.write(idm); //8byte:idm
        bout.write(1); //Anzahl der Dienste
        bout.write(0x4f); //Servicecode-Liste Die WAON-Kartennummer lautet 684F
        bout.write(0x68); //Service-Code-Liste
        bout.write(blocksize); //Anzahl der Blöcke

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

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

        return msg;
    }

    //Funktion zum Konvertieren von Bytes in hexadezimale Zeichenfolgen
    private String bytesToHexString(byte[] bytes){
        StringBuilder sb = new StringBuilder();
        Formatter formatter = new Formatter(sb);
        for(byte b: bytes){
            formatter.format("%02x",b);
        }
        //Zurück zum Kapital (passen Sie einfach das Erscheinungsbild an)
        return sb.toString().toUpperCase();
    }
}

das ist alles.

activity_main.xml

Activity_main.xml ist ebenfalls als Referenz enthalten, aber Sie sollten es so gestalten, wie Sie möchten.

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="WAON Number Viewer"
        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="WAON Nummer:"
        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

Dies dient auch nur als Referenz. Ich bearbeite nur die eingangs erwähnten NFC-Berechtigungen.

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

Lesen und sehen Sie die Informationen auf der FeliCa (WAON) -Karte
Lesen Sie den IC-Kontostand Ihres Studentenausweises (Felica) auf Android
Kompilieren Sie Java und führen Sie es in der Befehlszeile aus