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.
Cela ressemble à ce qui suit.
Cela ressemble à ce qui suit.
Le déroulement général de la reconnaissance d'une carte à sa lecture est le suivant.
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.
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>