使用android (android studio)和蘋果ios手機讀寫NFC卡內容(MifareUltralight)方法 親身完美體驗過程

最近工作需要購買了一些nfc卡進行讀寫操作,目標是使用手機實現一些業務流程

淘寶購買1-2塊錢一張卡,賣家提供的信息:卡的芯片是215

網上找的內容都是一段一段的,我現在把用到的資料都整合起來,以便看一篇就可以知道怎麼操作。

蘋果手機的NFC卡使用說明:

蘋果手機讀取,需要iphone7+  ios12以上,纔有nfc功能,讀取時不能直接讀取卡序列號,安卓可以,需要用安卓手機安裝NFC TagWriter by NXP_v4.8.2_apkpure.com.apk (Google play可以下載)進行寫卡後,蘋果纔可以讀取寫入的內容

 

一、該卡屬於MifareUltralight格式規範,規範如下:

https://blog.csdn.net/wxh0000mm/article/details/79708807?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

這裏有兩個地方特別獨家補充一下的,網上的網文都沒有說明清楚,看得到有點暈

1、是卡的序列號使用16進制讀取

2、page2中lock使用二進制來標記(再轉16進制)設置

 

存儲結構:

頁號

Byte0

Byte1

Byte2

Byte3

說明

0

SN0

SN1

SN2

BCC0

只讀,存放卡的序列號:Page0前3字節+整個Page1

這裏是16進制讀取(注意讀取方式,其它網文都沒有標明)

1

SN3

SN4

SN5

SN6

2

BCC1

保留

LOCK0

LOCK1

只讀,通過設置LOCK0和LOCK1可以講16個page設爲只讀

二進制方式設置(注意讀取方式,其它網文都沒有標明)

3

OTP0

OTP1

OTP2

OTP3

可讀寫,一次性交易計數器,不可逆

4

Data0

Data1

Data2

Data3

可讀寫,數據存放區域

5

Data0

Data1

Data2

Data3

6

Data0

Data1

Data2

Data3

7

Data0

Data1

Data2

Data3

8

Data0

Data1

Data2

Data3

9

Data0

Data1

Data2

Data3

10

Data0

Data1

Data2

Data3

11

Data0

Data1

Data2

Data3

12

Data0

Data1

Data2

Data3

13

Data0

Data1

Data2

Data3

14

Data0

Data1

Data2

Data3

15

Data0

Data1

Data2

Data3

 

 Page2的第3和第4個字節用於將存儲區鎖定爲只讀,如下圖示,L4-L15的某一位設置爲1,則對應序號的Page內容鎖定爲只讀,每一個Page都可以單獨設置。Lotp用於鎖定Page3爲只讀。Lotp-L15可以鎖定別人,這些位本身又被三個BL位鎖定,BL15-10用於鎖定L15-L10,BL9-4用於鎖定L9-L4,BLotp用於鎖定Lotp。所有的這16個鎖定位也具有OTP特性,通俗的講就是這些“鎖”沒有“鑰匙”,一旦鎖死就改不回來,所以鎖定時一定要小心。

 

如lock1對應8位二進制11110000,1代表鎖定只讀,然後把二進制轉換成16進制寫入卡

二進制方式設置(注意讀取方式,其它網文都沒有標明)

二、讀寫方法網上有比較多,寫法如下:

https://www.cnblogs.com/sjjg/p/4783743.html

親測有效,我的測試源代碼下載地址:https://download.csdn.net/download/qq_16005627/12366636

通過以上讀寫方法擴展

1、 讀取卡序列號方法

public String readTagc(Tag tag) throws Exception {
    //讀數據 第1步,從nfc標籤中得到MifareUltralight
    MifareUltralight ultralight = MifareUltralight.get(tag);

    try {
        //讀數據 第2步,接連
        ultralight.connect();
        //讀數據 第3步,從ultralight數據中的下標爲4的位開始讀數據.
        byte[] data = ultralight.readPages(0);
        byte[] serialNumber = new byte[7];
        serialNumber[0] = data[0];
        serialNumber[1] = data[1];
        serialNumber[2] = data[2];
        serialNumber[3] = data[4];
        serialNumber[4] = data[5];
        serialNumber[5] = data[6];
        serialNumber[6] = data[7];
        String CardCode = bytes2HexString(serialNumber);       
        return CardCode ;
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            ultralight.close();
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }
    return null;
}

 

//16進制轉字符串

private static String bytes2HexString(final byte[] bytes) {
    if (bytes == null) return "";
    int len = bytes.length;
    if (len <= 0) return "";
    char[] ret = new char[len << 1];
    for (int i = 0, j = 0; i < len; i++) {
        ret[j++] = HEX_DIGITS[bytes[i] >> 4 & 0x0f];
        ret[j++] = HEX_DIGITS[bytes[i] & 0x0f];
    }
    return new String(ret);
}

private static final char[] HEX_DIGITS =
        {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

 

二、設置page2中lock

ultralight.writePage(2, hexString2Bytes("DF48f000"));//第2頁 LOCK設置     11110000二進制轉16進制

//16進制轉字節

public static byte[] hexString2Bytes(String src) 
    int l = src.length() / 2;
    byte[] ret = new byte[l];
    for (int i = 0; i < l; i++) {
        ret[i] = (byte) Integer
                .valueOf(src.substring(i * 2, i * 2 + 2), 16).byteValue();
    }
    return ret;
}

覺得好的同學,記得點個贊!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章