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.
Es sieht wie folgt aus.
Es sieht wie folgt aus.
Der allgemeine Ablauf vom Erkennen einer Karte zum Lesen ist wie folgt.
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.
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>