IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android NFC之标签解析 -> 正文阅读

[移动开发]Android NFC之标签解析

NFC标签解析

本文讲NFC各种标签的解析实现,本文从Tag讲起,如何拿到Tag请看Android NFC之读卡器模式


import android.nfc.Tag;

import java.io.Closeable;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public abstract class CardReader {
    public static String getId(Tag tag) {
        return ByteArrayToHexString(tag.getId());
    }

    public static final String readTag(Tag tag) {
        CardReader reader = with(tag);
        if (reader == null) {
            return "暂不支持此卡类型";
        }
        return reader.parse(tag);
    }

    public static final CardReader with(Tag tag) {
        List<String> techs = Arrays.asList(tag.getTechList());
        if (techs.contains("android.nfc.tech.IsoDep")) {
            return new CustomIsoDepReader();
        }
        if (techs.contains("android.nfc.tech.NfcBarcode")) {
            return new NfcBarcodeReader();
        }
        if (techs.contains("android.nfc.tech.MifareClassic")) {
            return new MifareClassicReader();
        }
        if (techs.contains("android.nfc.tech.MifareUltralight")) {
            return new MifareUltralightReader();
        }
        if (techs.contains("android.nfc.tech.Ndef")) {
            return new NdefReader();
        }
        if (techs.contains("android.nfc.tech.NfcA")) {
            return new NfcAReader();
        }
        if (techs.contains("android.nfc.tech.NfcB")) {
            return new NfcBReader();
        }
        if (techs.contains("android.nfc.tech.NfcV")) {
            return new NfcVReader();
        }
        if (techs.contains("android.nfc.tech.NfcF")) {
            return new NfcFReader();
        }
        if (techs.contains("android.nfc.tech.NdefFormatable")) {
        }
        return null;
    }


    public abstract String parse(Tag tag);


    /**
     * 将字节数组转换为字符串
     */
    protected static String ByteArrayToHexString(byte[] inarray) {
        int i, j, in;
        String[] hex = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
        String out = "";

        for (j = 0; j < inarray.length; ++j) {
            in = (int) inarray[j] & 0xff;
            i = (in >> 4) & 0x0f;
            out += hex[i];
            i = in & 0x0f;
            out += hex[i];
        }
        return out;
    }

    /**
     * Utility class to convert a hexadecimal string to a byte string.
     *
     * <p>Behavior with input strings containing non-hexadecimal characters is undefined.
     *
     * @param s String containing hexadecimal characters to convert
     * @return Byte array generated from input
     */
    protected static byte[] HexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i + 1), 16));
        }
        return data;
    }

    protected void close(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            closeable = null;
        }
    }


}

1.Ndef


import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.Tag;
import android.nfc.tech.Ndef;

public class NdefReader extends CardReader {
    @Override
    public String parse(Tag tag) {
        Ndef ndef = Ndef.get(tag);
        try {
            ndef.connect();
            NdefMessage ndefMessage = ndef.getNdefMessage();
            NdefRecord[] records = ndefMessage.getRecords();
            if (records == null || records.length <= 0) {
                return "getRecords() is null";
            }
            StringBuffer buffer = new StringBuffer();
            for (NdefRecord record : records) {
                buffer.append("\nNdefRecord:").append(record.toString());
            }
            return buffer.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return e.getMessage();
        } finally {
            close(ndef);
        }
    }
}

2.MifareClassic

import android.nfc.Tag;
import android.nfc.tech.MifareClassic;
import android.util.Log;

import java.io.IOException;

public class MifareClassicReader extends CardReader {
    private static final String TAG = "MifareClassicReader";

    @Override
    public String parse(Tag tag) {
        MifareClassic mifareClassic = MifareClassic.get(tag);
        try {
            mifareClassic.connect();
            int type = mifareClassic.getType();//获取TAG的类型
            int sectorCount = mifareClassic.getSectorCount();//获取TAG中包含的扇区数
            String typeS = "";
            switch (type) {
                case MifareClassic.TYPE_CLASSIC:
                    typeS = "TYPE_CLASSIC";
                    break;
                case MifareClassic.TYPE_PLUS:
                    typeS = "TYPE_PLUS";
                    break;
                case MifareClassic.TYPE_PRO:
                    typeS = "TYPE_PRO";
                    break;
                case MifareClassic.TYPE_UNKNOWN:
                    typeS = "TYPE_UNKNOWN";
                    break;
            }
            StringBuffer buffer = new StringBuffer();
            buffer.append("\n卡片类型:").append(typeS);
            buffer.append("\n共").append(sectorCount).append("个扇区");
            buffer.append("\n共").append(mifareClassic.getBlockCount()).append("个块");
            buffer.append("\n存储空间:").append(mifareClassic.getSize()).append("B");
            boolean auth = false;
            for (int j = 0; j < sectorCount; j++) {
                //Authenticate a sector with key A.
                buffer.append("\nSector").append(j);
                auth = mifareClassic.authenticateSectorWithKeyA(j, MifareClassic.KEY_DEFAULT);
                int bCount;
                int bIndex;
                if (auth) {
                    buffer.append("验证成功");
                    // 读取扇区中的块
                    bCount = mifareClassic.getBlockCountInSector(j);
                    bIndex = mifareClassic.sectorToBlock(j);
                    for (int i = 0; i < bCount; i++) {
                        byte[] data = mifareClassic.readBlock(bIndex);
                        buffer.append("\nBlock " + bIndex + " : " + ByteArrayToHexString(data) + "");
                        bIndex++;
                    }
                } else {
                    buffer.append("验证失败");
                }
            }
            return buffer.toString();
        } catch (IOException e) {
            Log.d(TAG, "parse", e);
            return e.getMessage();
        } finally {
            close(mifareClassic);
        }
    }
}

3.MifareUltralight


import android.nfc.Tag;
import android.nfc.tech.MifareUltralight;

import java.io.IOException;

/**
 * Mifare UltraLight又称为MF0,从UltraLight(超轻的)这个名字就可以看出来,它是一个低成本、小容量的卡片。低成本,是指它是目前市场中价格最低的遵守ISO14443A协议的芯片之一;小容量,是指其存储容量只有512bit(Mifare S50有8192bit)。
 * Mifare UltraLight的512bit存储容量分成16个Page,每个Page包含4个字节
 */
public class MifareUltralightReader extends CardReader {
    @Override
    public String parse(Tag tag) {
        MifareUltralight mifareUltralight = MifareUltralight.get(tag);
        try {
            mifareUltralight.connect();
            StringBuffer buffer = new StringBuffer();
            int type = mifareUltralight.getType();
            switch (type) {
                case MifareUltralight.TYPE_ULTRALIGHT:
                    buffer.append("TYPE_ULTRALIGHT");
                    break;
                case MifareUltralight.TYPE_ULTRALIGHT_C:
                    buffer.append("TYPE_ULTRALIGHT_C");
                    break;
                case MifareUltralight.TYPE_UNKNOWN:
                    buffer.append("TYPE_UNKNOWN");
                    break;
            }
            byte[] payload = mifareUltralight.readPages(0);
            byte[] payload1 = mifareUltralight.readPages(4);
            byte[] payload2 = mifareUltralight.readPages(8);
            byte[] payload3 = mifareUltralight.readPages(12);
            buffer.append("\nPage0-3:").append(ByteArrayToHexString(payload));
            buffer.append("\npage4-7:").append(ByteArrayToHexString(payload1));
            buffer.append("\npage8-11:").append(ByteArrayToHexString(payload2));
            buffer.append("\npage12-15:").append(ByteArrayToHexString(payload3));

            return buffer.toString();
        } catch (IOException e) {
            e.printStackTrace();
            return e.getMessage();
        } finally {
            close(mifareUltralight);
        }
    }
}

4.IsoDep

import android.nfc.Tag;
import android.nfc.tech.IsoDep;
import android.util.Log;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

/**
 * IsoDep主要用于读取各城市公交卡信息如:武汉通,羊城通,深圳通,北京市政交通卡,长安通。
 *
 * 深圳通:
 * byte[] DFN_SRV = { (byte) 'P', (byte) 'A', (byte) 'Y',
 * (byte) '.', (byte) 'S', (byte) 'Z', (byte) 'T' };
 * 武汉通:
 * byte[] DFN_SRV = { (byte) 0x41, (byte) 0x50,
 * (byte) 0x31, (byte) 0x2E, (byte) 0x57, (byte) 0x48, (byte) 0x43,
 * (byte) 0x54, (byte) 0x43, };
 * 羊城通:
 * byte[] DFN_SRV = { (byte) 'P', (byte) 'A', (byte) 'Y',
 * (byte) '.', (byte) 'A', (byte) 'P', (byte) 'P', (byte) 'Y', };
 * 长安通:
 * byte[] DFN_SRV = { (byte) 0xA0, (byte) 0x00,
 * (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x86, (byte) 0x98,
 * (byte) 0x07, (byte) 0x01, };
 * 北京市政交通卡:
 * byte[] DFI_EP = { (byte) 0x10, (byte) 0x01 };
 */
public class IsoDepReader extends CardReader {
    private static final String TAG = "IsoDepReader";

    protected final static byte TRANS_CSU = 6; // 如果等于0x06或者0x09,表示刷卡;否则是充值
    protected final static byte TRANS_CSU_CPX = 9; // 如果等于0x06或者0x09,表示刷卡;否则是充值

    @Override
    public String parse(Tag tag) {
        IsoDep isoDep = IsoDep.get(tag);
        try {
            isoDep.connect();
            StringBuffer buffer = new StringBuffer();
            if (isoDep.isConnected()) {
                Log.d("h_bl", "isoDep.isConnected"); // 判断是否连接上
                // 1.select PSF (1PAY.SYS.DDF01)
                // 选择支付系统文件,它的名字是1PAY.SYS.DDF01。
                byte[] DFN_PSE = {(byte) '1', (byte) 'P', (byte) 'A', (byte) 'Y', (byte) '.', (byte) 'S', (byte) 'Y', (byte) 'S', (byte) '.', (byte) 'D', (byte) 'D', (byte) 'F', (byte) '0', (byte) '1',};
                isoDep.transceive(getSelectCommand(DFN_PSE));
                // 2.选择公交卡应用的名称
                byte[] DFN_SRV = {(byte) 0xA0, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x86, (byte) 0x98, (byte) 0x07, (byte) 0x01,};
                isoDep.transceive(getSelectCommand(DFN_SRV));
                // 3.读取余额
                byte[] ReadMoney = {(byte) 0x80, // CLA Class
                        (byte) 0x5C, // INS Instruction
                        (byte) 0x00, // P1 Parameter 1
                        (byte) 0x02, // P2 Parameter 2
                        (byte) 0x04, // Le
                };
                byte[] Money = isoDep.transceive(ReadMoney);
                if (Money != null && Money.length > 4) {
                    int cash = byteToInt(Money, 4);
                    float ba = cash / 100.0f;
                    buffer.append("余额:" + ba);
                }
                // 4.读取所有交易记录
                byte[] ReadRecord = {(byte) 0x00, // CLA Class
                        (byte) 0xB2, // INS Instruction
                        (byte) 0x01, // P1 Parameter 1
                        (byte) 0xC5, // P2 Parameter 2
                        (byte) 0x00, // Le
                };
                byte[] Records = isoDep.transceive(ReadRecord);
                // 处理Record
                Log.d("h_bl", "总消费记录" + Records);
                ArrayList<byte[]> ret = parseRecords(Records);
                List<String> retList = parseRecordsToStrings(ret);
                buffer.append("\n" + "消费记录如下:");
                for (String string : retList) {
                    Log.d("h_bl", "消费记录" + string);
                    buffer.append("\n" + string);
                }
            } else {
                buffer.append("not connected");
            }
            return buffer.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return e.getMessage();
        } finally {
            close(isoDep);
        }
    }


    private byte[] getSelectCommand(byte[] aid) {
        final ByteBuffer cmd_pse = ByteBuffer.allocate(aid.length + 6);
        cmd_pse.put((byte) 0x00) // CLA Class
                .put((byte) 0xA4) // INS Instruction
                .put((byte) 0x04) // P1 Parameter 1
                .put((byte) 0x00) // P2 Parameter 2
                .put((byte) aid.length) // Lc
                .put(aid).put((byte) 0x00); // Le
        return cmd_pse.array();
    }

    /**
     * 整条Records解析成ArrayList<byte[]>
     *
     * @param Records
     * @return
     */
    private ArrayList<byte[]> parseRecords(byte[] Records) {
        int max = Records.length / 23;
        Log.d("h_bl", "消费记录有" + max + "条");
        ArrayList<byte[]> ret = new ArrayList<byte[]>();
        for (int i = 0; i < max; i++) {
            byte[] aRecord = new byte[23];
            for (int j = 23 * i, k = 0; j < 23 * (i + 1); j++, k++) {
                aRecord[k] = Records[j];
            }
            ret.add(aRecord);
        }
        for (byte[] bs : ret) {
            Log.d("h_bl", "消费记录有byte[]" + bs); // 有数据。解析正确。
        }
        return ret;
    }

    /**
     * ArrayList<byte[]>记录分析List<String> 一条记录是23个字节byte[] data,对其解码如下
     * data[0]-data[1]:index data[2]-data[4]:over,金额溢出??? data[5]-data[8]:交易金额
     * ??代码应该是(5,4) data[9]:如果等于0x06或者0x09,表示刷卡;否则是充值
     * data[10]-data[15]:刷卡机或充值机编号
     * data[16]-data[22]:日期String.format("%02X%02X.%02X.%02X %02X:%02X:%02X"
     * ,data[16], data[17], data[18], data[19], data[20], data[21], data[22]);
     *
     * @return
     */
    private List<String> parseRecordsToStrings(ArrayList<byte[]>... Records) {
        List<String> recordsList = new ArrayList<String>();
        for (ArrayList<byte[]> record : Records) {
            if (record == null)
                continue;
            for (byte[] v : record) {
//                StringBuilder r = new StringBuilder();
//                int cash = Util.toInt(v, 5, 4);
//                char t = (v[9] == TRANS_CSU || v[9] == TRANS_CSU_CPX) ? '-' : '+';
//                r.append(String.format("%02X%02X.%02X.%02X %02X:%02X ", v[16], v[17], v[18], v[19], v[20], v[21], v[22]));
//                r.append("   " + t).append(Util.toAmountString(cash / 100.0f));
//                String aLog = r.toString();
//                recordsList.add(aLog);
            }
        }
        return recordsList;
    }

    // byteArray转化为int
    private int byteToInt(byte[] b, int n) {
        int ret = 0;
        for (int i = 0; i < n; i++) {
            ret = ret << 8;
            ret |= b[i] & 0x00FF;
        }
        if (ret > 100000 || ret < -100000)
            ret -= 0x80000000;
        return ret;
    }

}

5.NfcA

import android.nfc.Tag;
import android.nfc.tech.NfcA;

import java.nio.charset.Charset;

public class NfcAReader extends CardReader {
    @Override
    public String parse(Tag tag) {
        NfcA nfca = NfcA.get(tag);
        try {
            nfca.connect();
            if (nfca.isConnected()) {//NTAG216的芯片
                byte[] SELECT = {
                        (byte) 0x30,
                        (byte) 5 & 0x0ff,//0x05
                };
                byte[] response = nfca.transceive(SELECT);
                nfca.close();
                if (response != null) {
                    return new String(response, Charset.forName("utf-8"));
                } else {
                    return "response is null";
                }
            } else {
                return "not connected";
            }
        } catch (Exception e) {
            e.printStackTrace();
            return e.getMessage();
        }finally {
            close(nfca);
        }
    }
}

6.NfcB


import android.nfc.Tag;
import android.nfc.tech.NfcB;
import android.widget.Toast;

import com.socsi.tools.nfccardreader.MainActivity;

import java.io.IOException;

public class NfcBReader extends CardReader {
    @Override
    public String parse(Tag tag) {

        NfcB nfcb = NfcB.get(tag);
        try {
            nfcb.connect();
            StringBuffer buffer = new StringBuffer();
            if (nfcb.isConnected()) {//身份证已连接
                System.out.println("已连接");
                byte[] applicationData = nfcb.getApplicationData();
                byte[] protocolInfo = nfcb.getProtocolInfo();
                buffer.append("ApplicationData:").append(ByteArrayToHexString(applicationData));
                buffer.append("\nProtocolInfo:").append(ByteArrayToHexString(protocolInfo));
            } else {
                buffer.append("not connected");
            }
            return buffer.toString();
        } catch (IOException e) {
            e.printStackTrace();
            return e.getMessage();
        } finally {
            close(nfcb);
        }
    }
}

7.Felica

import android.nfc.Tag;
import android.nfc.tech.NfcF;
import android.util.Log;

public class NfcFReader extends CardReader {
    @Override
    public String parse(Tag tag) {
        NfcF nfcf = NfcF.get(tag);
        try {
            nfcf.connect();
            byte[] felicaIDm = new byte[]{0};
            byte[] req = readWithoutEncryption(felicaIDm, 10);
            byte[] res = nfcf.transceive(req);
            return ByteArrayToHexString(res);
        } catch (Exception e) {
            e.printStackTrace();
            return e.getMessage();
        }finally {
            close(nfcf);
        }
    }
}

8.NfcV


import android.nfc.Tag;
import android.nfc.tech.NfcV;

import java.io.IOException;
import java.nio.charset.Charset;

public class NfcVReader extends CardReader {
    @Override
    public String parse(Tag tag) {
        NfcV nfcV = NfcV.get(tag);
        try {
            nfcV.connect();
            byte[] tagUid = tag.getId();
            int blockAddress = 0;
            int blocknum = 4;
            byte[] cmd = new byte[]{
                    (byte) 0x22,  // FLAGS
                    (byte) 0x23,  // 20-READ_SINGLE_BLOCK,23-所有块
                    0, 0, 0, 0, 0, 0, 0, 0,
                    (byte) (blockAddress & 0x0ff), (byte) (blocknum - 1 & 0x0ff)
            };
            System.arraycopy(tagUid, 0, cmd, 2, tagUid.length);
            byte[] response = nfcV.transceive(cmd);
            if (response != null) {
                return new String(response, Charset.forName("utf-8"));
            } else {
                return "respones is null";
            }
        } catch (IOException e) {
            e.printStackTrace();
            return e.getMessage();
        } finally {
            close(nfcV);
        }
    }
}

9.NfcBarcode


import android.nfc.Tag;
import android.nfc.tech.NfcBarcode;

public class NfcBarcodeReader extends CardReader {
    @Override
    public String parse(Tag tag) {
        NfcBarcode barcode = NfcBarcode.get(tag);
        try {
            barcode.connect();
            byte[] bytes = barcode.getBarcode();
            return ByteArrayToHexString(bytes);
        } catch (Exception e) {
            e.printStackTrace();
            return e.getMessage();
        } finally {
            close(barcode);
        }
    }
}

主要的NFC类就这些,代码仅测试使用,如有错误请指正,谢谢!

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-10-13 11:33:29  更:2021-10-13 11:34:34 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:27:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码