Android NFC的初次使用——公交卡資訊讀取

朕乃超哥發表於2017-05-18

通過NFC的讀模式,讀取公交卡的餘額和交易記錄。這是一個開源的工程,可以讀取深圳通、羊城通、北京卡、八達通、武漢通等等。

1.首先要在AndroidManifest.xml中宣告如下配置資訊:

使用<uses-permission>元素允許裝置訪問NFC硬體:

<uses-permission android:name="android.permission.NFC" />  
使用<uses-sdk>元素設定最小SDK版本,本人基於android 4.4環境,因此宣告如下:
<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="19" /> 
備註:API Level 9只通過ACTION_TAG_DISCOVERED來支援有限的標籤排程,並且只能通過EXTRA_NDEF_MESSAGES來訪問NDEF訊息。沒有其他的標籤屬性或I/O操作可用。API Level 10中包含了廣泛的讀寫支援,從而更好的推動了NDEF的應用前景,並且API Leve 14用Android   Beam和額外的方便的建立NDEF記錄的方法,向外提供了更容易的把NDEF訊息推送給其他裝置的方法。


下面這項不一定需要,如果你希望你的軟體可以在android market中顯示有NFC硬體,可以使用<uses-feature>元素宣告:

<uses-feature android:name="android.hardware.nfc" android:required="true" />  

2.NFC TAG的釋出系統:

當android裝置掃描到一個NFC標籤時,會自動尋找最適合的Activity來處理這個TAG,如果有多個Activity滿足條件的話,會讓使用者來選擇到底使用哪一個Activity來處理,可以理解為就是簡單的事件響應與事件處理。

那麼如何讓一個Activity監聽 ”當掃描到NFC標籤時” 的這一個事件呢?使用intent filter。

可以理解為當檢測到一個NFC標籤時,系統自動建立一個相關的Intent物件,含有響應intent filter的Activity將處理這個Intent。

其中,intent filter宣告如下:(在AndroidManifest.xml中宣告在你需要捕獲這個Intent的Activity裡)(如下是識別公交卡的TECH格式過濾標籤):

<intent-filter>             
        <action android:name="android.nfc.action.TECH_DISCOVERED" />
    </intent-filter> 
   <meta-data android:name="android.nfc.action.TECH_DISCOVERED"
          android:resource="@xml/nfc_tech_filter" />

在res資料夾下新建一個xml的資料夾,裡面放的是Android支援的NFC型別的配置資料。nfc_tech_filter.xml如下:

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <!-- 可以處理所有Android支援的NFC型別 -->
    <tech-list>
        <tech>android.nfc.tech.IsoDep</tech>
    </tech-list>
    <tech-list>
    <tech>android.nfc.tech.NfcA</tech>
    </tech-list>
    <tech-list>
    <tech>android.nfc.tech.NfcB</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcF</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcV</tech>
    </tech-list>
    <tech-list>
    <tech>android.nfc.tech.Ndef</tech>
    </tech-list>
    <tech-list>
    <tech>android.nfc.tech.NdefFormatable</tech>
    </tech-list>
    <tech-list>
    <tech>android.nfc.tech.MifareUltralight</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.MifareClassic</tech>
    </tech-list>
</resources>

另外還有:

NDEF格式

<intent-filter>
    <action android:name = "android.nfc.action.NDEF_DISCOVERED" />
    <data android:mimeType = "text/plain" />
</intent-filter>
TAG格式
<intent-filter>
       <action android:name="android.nfc.action.TAG_DISCOVERED"/>
       <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>


有興趣的同學可以看看Google官方的NFC介紹說明: https://developer.android.com/guide/topics/connectivity/nfc/nfc.html


到此你所寫的activity就能通過刷一下公交卡被調起來了,剩下的是怎麼讀取卡內資訊,讀取部分相對麻煩,因為區分了多種模式卡的資料解析,在此不做詳細說明,可參照最下方原始碼下載;

簡單來說分四個步驟:

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', };


2.選擇公交卡應用的名字或者ID
每個公交卡的名字都會不一樣。
深圳通:
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, };
北京市政交通卡ID:
byte[] DFI_EP = { (byte) 0x10, (byte) 0x01 };


其他公交卡:


3.讀取餘額
傳送命令讀取電子錢包的餘額:
final byte[] cmd = { (byte) 0x80, // CLA Class
(byte) 0x5C, // INS Instruction
(byte) 0x00, // P1 Parameter 1
(byte) 0x02, // P2 Parameter 2
(byte) 0x04, // Le
};
獲取到的餘額資料是byte[] data, 前4位元組合併成int,再除以100(兩個小數點),得到的結果就是餘額。


4.讀取交易記錄
一次性讀取命令,在不知道有多少條記錄的時候,用這個命令:
byte[] cmd = { (byte) 0x00, // CLA Class
(byte) 0xB2, // INS Instruction
(byte) 0x01, // P1 Parameter 1
(byte) 0xC5, // P2 Parameter 2
(byte) 0x00, // Le
};
返回所有的記錄byte[] data,每23個位元組代表一條記錄
也可以一條一條的讀取:
cmd = { (byte) 0x00, // CLA Class
(byte) 0xB2, // INS Instruction
(byte) index, // P1 Parameter 1
(byte) 0xC4, // P2 Parameter 2
(byte) 0x00, // Le
};
一條記錄是23個位元組byte[] data,對其解碼如下
data[0]-data[1]:index
data[2]-data[4]:over,金額溢位?
data[5]-data[8]:交易金額
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]);



原始碼下載地址

http://download.csdn.net/detail/bbenskye/9845382


相關文章