您當前的位置:首頁 > 歷史

搞懂Nfc刷卡看這篇就夠了

作者:由 wizardev 發表于 歷史時間:2020-11-30

NFC在我們生活中出現的場景越來越多了,如藍芽耳機的連線、刷交通卡、智慧鎖開鎖等,相信在未來還會有越來越多的場景會用到NFC,所以作為開發者,掌握NFC的知識及NFC的開發技能、就顯得尤為必要

這裡放出Android

官方文件

,官方的文件講的大而全,本文是對官方文件的抽絲剝繭,相對官方文件來說會更容易理解,但是會比官方文件少一些內容,如果本文沒有你想了解的,可以自己查閱官方文件。

什麼是NFC

NFC

是Near Field Communication縮寫,即近距離無線通訊技術。由飛利浦公司和索尼公司共同開發的NFC是一種非接觸式識別和互聯技術,可以在移動裝置、消費類電子產品、PC 和智慧控制元件工具間進行近距離無線通訊。

簡單的說,

NFC

提供了一種簡單、觸控式的解決方案,可以讓消費者簡單直觀地交換資訊、訪問內容與服務。

NFC的工作模式

NFC的工作模式有三種,分別是讀卡器模式(Reader/writer mode)、模擬卡模式(Card Emulation Mode)、點對點模式(P2P mode)。

讀卡器模式

資料在NFC晶片中,可以簡單理解成“刷標籤”。本質上就是透過支援NFC的手機或其它電子裝置從帶有NFC晶片的標籤、貼紙、名片等媒介中讀寫資訊。通常NFC標籤是不需要外部供電的。當支援NFC的外設向NFC讀寫資料時,它會發送某種磁場,而這個磁場會自動的向NFC標籤供電。

模擬卡模式

資料在支援NFC的手機或其它電子裝置中,可以簡單理解成“刷手機”。本質上就是將支援NFC的手機或其它電子裝置當成借記卡、公交卡、門禁卡等IC卡使用。基本原理是將相應IC卡中的資訊憑證封裝成資料包儲存在支援NFC的外設中 。

在使用時還需要一個NFC射頻器(相當於刷卡器)。將手機靠近NFC射頻器,手機就會接收到NFC射頻器發過來的訊號,在透過一系列複雜的驗證後,將IC卡的相應資訊傳入NFC射頻器,最後這些IC卡資料會傳入NFC射頻器連線的電腦,並進行相應的處理(如電子轉帳、開門等操作)。

點對點模式

該模式與藍芽、紅外差不多,用於不同NFC裝置之間進行資料交換,不過這個模式已經沒有有“刷”的感覺了。其有效距離一般不能超過4釐米,但傳輸建立速度要比紅外和藍芽技術快很多,傳輸速度比紅外塊得多,如過雙方都使用Android4。2,NFC會直接利用藍芽傳輸。這種技術被稱為Android Beam。所以使用Android Beam傳輸資料的兩部裝置不再限於4釐米之內。

點對點模式的典型應用是兩部支援NFC的手機或平板電腦實現資料的點對點傳輸,例如,交換圖片或同步裝置聯絡人。因此,透過NFC,多個裝置如數字相機,計算機,手機之間,都可以快速連線,並交換資料或者服務。

本文會主要講解

讀卡器模式,

相信理解了這個模式,其他的兩種模式你也會觸類旁通的。在講解讀卡器模式前,有一些知識是需要提前掌握的。

卡片的知識

本文主要講解的是NFC的讀卡器模式,要想讀到卡片的內容,我們要對卡片有一些基本的瞭解,比如卡片的分類,每種卡片內部的資料結構等。

卡片的分類

現在市面上的卡片分類有IC卡、ID卡、M1卡和CPU卡,簡單的瞭解一下這些卡的區別和用途,

IC卡

IC卡又稱積體電路卡,通常是在塑膠卡片內嵌入一個或多個積體電路構成的PVC卡。積體電路晶片可以是儲存器或微處理器。帶有儲存器的IC卡又稱為記憶卡或儲存卡,帶有微處理器的IC卡又稱為智慧卡或智慧卡。記憶卡可以儲存大量資訊;智慧卡則不僅具有記憶能力,而且還具有處理資訊的功能。

IC卡可以十分方便地存汽車費、電話費、地鐵乘車費、食堂就餐費、公路付費以及購物旅遊、貿易服務等。

ID卡

ID卡又叫身份識別卡,是一種不可寫入的感應式卡,擁有一個固定卡號編號。卡號在封卡前寫入後不可再更改,絕對確保卡號的唯一性和安全性。

ID卡可以作為一般的門禁或停車場系統的使用者身份識別,因ID卡無金鑰安全認證機制,且不能寫卡,很難實現一卡通功能,同時也不合適做消費系統。

M1卡

M1是菲利浦下屬子公司恩智浦出品的晶片縮寫,目前該公司的M1晶片與國產晶片相相容,

其實M1卡也屬於非接觸式IC卡

M1卡,優點是可讀可寫的多功能卡,缺點是:價格稍貴,感應距離短,適合非定額消費系統、停車場系統、門禁考勤系統等。

CPU卡

CPU卡晶片是一個微處理器,它的功能相當於一臺微型計算機。CPU卡可適用於金融、保險、交警、政府行業等多個領域,CPU卡的優點是儲存空間大、讀取速度快、支援一卡多用功能等特點,CPU卡從外型上與普通IC卡,射頻卡並沒有太大差異,但是效能上卻有巨大提升,安全性和普通IC卡比,提高很多,通常CPU卡內含有隨機數發生器,硬體DES,3DES加密演算法等,配合CPU卡晶片上的COS作業系統,可以達到金融級的安全級別。

M1卡的資料結構

為什麼要介紹卡結構呢?因為用NFC讀取卡片,獲取卡片的內容的時候,你要知道卡片的資料結構,才能拿到自己想要的知識,這裡就以M1卡進行講解。

M1卡有從0到15共16個扇區,每個扇區配備了從0到3共4個段,每個段可以儲存16位元組的內容。見下圖

搞懂Nfc刷卡看這篇就夠了

要想讀取對應扇區的資料,需要知道對應扇區的秘鑰,否則讀取不到資料。

Android的NFC標籤排程系統

當手機發現外部NFC的標籤(指含有NFC功能的裝置)時,Android系統會尋找可以處理這個標籤的Activity,那怎麼知道哪個Activity能處理這條NFC訊息呢?答案是清單檔案,我們需要在清單檔案中設定

intent-filter

。系統會分發NFC訊息到設定

intent-filter

的Activity中,當然,接收NFC訊息也有優先順序之分,也是透過設定

intent-filter

來設定接收NFC訊息的優先順序的。

NFC的標籤排程系統綁定了3中intent,按優先順序的高低列出,如下

ACTION_NDEF_DISCOVERED

:如果掃描到包含此Intent的Activity,並且可識別其型別,則使用此 Intent 啟動 Activity。這是優先順序最高的 Intent,NFC標籤排程系統會盡可能嘗試使用此 Intent 啟動 Activity,在找不到這個Intent時才會嘗試使用其他 Intent。

ACTION_TECH_DISCOVERED

:如果沒有登記要處理

ACTION_NDEF_DISCOVERED

Intent 的 Activity,則標籤排程系統會嘗試使用此 Intent 來啟動應用。此外,如果掃描到的標籤包含無法對映到 MIME 型別或 URI 的 NDEF 資料,或者該標籤不包含 NDEF 資料,但它使用了已知的標籤技術,那麼也會直接啟動此 Intent(無需先啟動

ACTION_NDEF_DISCOVERED

)。

ACTION_TAG_DISCOVERED

:如果沒有處理

ACTION_NDEF_DISCOVERED

或者

ACTION_TECH_DISCOVERED

Intent 的 Activity,則使用此 Intent 啟動 Activity。

它們3者關係如下圖所示

搞懂Nfc刷卡看這篇就夠了

如果想處理所有的NFC標籤,上面3個可以在清單檔案中都進行設定。

實戰演練

前文我們已經知道了什麼是NFC以及NFC的幾種工作模式,也瞭解了市面上卡片的分類和M1卡的資料結構,基礎知識已經掌握了,下面就開始進入實戰演練,用Android的NFC來獲取M1卡的唯一程式碼。

在 Android 清單中請求 NFC 訪問許可權

先在

AndroidManifest。xml

檔案中宣告以下內容,然後才能訪問裝置的 NFC 硬體並正確處理 NFC Intent:

設定用於訪問 NFC 硬體的 NFC

android:name=

“android。permission。NFC”

/>

設定

uses-feature

元素,以便您的應用僅在那些具備 NFC 硬體的裝置的 Google Play 中顯示

xml

如果你的App不是必須要NFC功能,則

uses-feature

可以省略,然後再程式碼中透過

getDefaultAdapter()

是否為

null

來判斷 NFC 的可用性。

設定過濾 NFC Intent

以下示例展示瞭如何過濾 MIME 型別為

text/plain

ACTION_NDEF_DISCOVERED

Intent:

android:name=

“android。nfc。action。NDEF_DISCOVERED”

/>

android:name=

“android。intent。category。DEFAULT”

/>

android:mimeType=

“text/plain”

/>

另外兩種

intent-filter

的使用,可以查閱官方文件。

使用前臺排程系統

前臺排程系統的作用就是,在你開啟一個可以處理NFC標籤的Activity時,NFC的訊息會優先發送給當前的Activity,不論當前的Activity設定的是哪一個

intent-filter

。使用前臺排程系統的步驟如下

在 Activity 的

onCreate()

方法中新增以下程式碼:

a。 建立一個

PendingIntent

物件。

val

intent

=

Intent

this

javaClass

)。

apply

{

addFlags

Intent

FLAG_ACTIVITY_SINGLE_TOP

}

var

pendingIntent

PendingIntent

=

PendingIntent

getActivity

this

0

intent

0

b。宣告 Intent 過濾器,用來處理您要攔截的 Intent。前臺排程系統會對照裝置掃描標籤時所獲得的 Intent 來檢查所指定的 Intent 過濾器。如果匹配,那麼應用會處理該 Intent。如果不匹配,那麼前臺排程系統會回退到 Intent 排程系統。指定 Intent 過濾器和技術過濾器的

null

陣列,以指明要過濾所有回退到

TAG_DISCOVERED

Intent 的標籤。以下程式碼段會處理

NDEF_DISCOVERED

的所有 MIME 型別。

val

ndef

=

IntentFilter

NfcAdapter

ACTION_NDEF_DISCOVERED

)。

apply

{

try

{

addDataType

“/”

/

處理所有

MIME

型別的標籤

/

}

catch

e

IntentFilter

MalformedMimeTypeException

{

throw

RuntimeException

“fail”

e

}

}

intentFiltersArray

=

arrayOf

ndef

c。設定應用要處理的一組標籤技術。呼叫

Object。class。getName()

方法以獲取要支援的技術的類。

techListsArray

=

arrayOf

arrayOf

<

String

>(

NfcF

::

class

java

name

))

替換以下 Activity 生命週期回撥,並新增相應邏輯,以分別在 Activity 失去 (

onPause()

) 焦點和重新獲得 (

onResume()

) 焦點時啟用和停用前臺排程。

enableForegroundDispatch()

必須從主執行緒呼叫,並且只能在 Activity 在前臺執行時呼叫(在

onResume()

中呼叫可確保這一點)。您還需要實現

onNewIntent

回撥以處理掃描到的 NFC 標籤中的資料。

public

override

fun

onPause

()

{

super

onPause

()

adapter

disableForegroundDispatch

this

}

public

override

fun

onResume

()

{

super

onResume

()

adapter

enableForegroundDispatch

this

pendingIntent

intentFiltersArray

techListsArray

}

public

override

fun

onNewIntent

intent

Intent

{

val

tagFromIntent

Tag

=

intent

getParcelableExtra

NfcAdapter

EXTRA_TAG

//在這裡處理NFC掃描到的內容

}

程式碼示例

下面展示核心程式碼,讀取M1卡並解析卡號,程式碼如下

//解析實體卡號

fun

resolveCardNumIntent

intent

Intent

?):

String

{

if

intent

==

null

{

return

“”

}

//拿來裝讀取出來的資料,key代表扇區數,後面list存放四個塊的內容

//intent就是onNewIntent方法返回的那個intent

val

tag

Tag

=

intent

getParcelableExtra

NfcAdapter

EXTRA_TAG

val

mfc

=

MifareClassic

get

tag

//如果當前IC卡不是這個格式的mfc就會為空

if

null

!=

mfc

{

try

{

if

(!

mfc

isConnected

{

//連結NFC

mfc

connect

()

}

//驗證扇區密碼,否則會報錯(連結失敗錯誤)

val

isOpen

=

mfc

authenticateSectorWithKeyA

0

CARD_KEY_15

if

isOpen

{

//獲取扇區第一個塊對應晶片儲存器的位置

//(我是這樣理解的,因為第0扇區的這個值是4而不是0)

val

bIndex

=

mfc

sectorToBlock

0

val

data

=

mfc

readBlock

bIndex

val

byteArrToInt

=

DataUtils

byteArrToInt

data

0

4

// LogUtils。print(“卡號: $byteArrToInt”)

return

byteArrToInt

}

}

catch

e

Exception

{

e

printStackTrace

()

return

“”

}

finally

{

try

{

mfc

close

()

}

catch

e

IOException

{

e

printStackTrace

()

}

}

}

return

“”

}

上面的程式碼註釋很清晰,重點看下這段程式碼

val

tag

Tag

=

intent

getParcelableExtra

NfcAdapter

EXTRA_TAG

val

mfc

=

MifareClassic

get

tag

//用於解析MifareClassic的例項

這裡的Tag是獲取卡片的Tag,NFC支援的Tag如下表

表 1.

支援的標籤技術

說明

TagTechnology

這是所有標籤技術類都必須實現的介面。

NfcA

提供對 NFC-A (ISO 14443-3A) 屬性和 I/O 操作的訪問許可權。

NfcB

提供對 NFC-B (ISO 14443-3B) 屬性和 I/O 操作的訪問許可權。

NfcF

提供對 NFC-F (JIS 6319-4) 屬性和 I/O 操作的訪問許可權。

NfcV

提供對 NFC-V (ISO 15693) 屬性和 I/O 操作的訪問許可權。

IsoDepc

提供對 ISO-DEP (ISO 14443-4) 屬性和 I/O 操作的訪問許可權。

Ndef

提供對 NDEF 格式的 NFC 標籤上的 NDEF 資料和操作的訪問許可權。

NdefFormatable

為可設定為 NDEF 格式的標籤提供格式化操作。

Android 裝置還可以選擇支援以下標籤技術。

表 2.

可選擇支援的標籤技術

說明

MifareClassic

提供對 MIFARE Classic 屬性和 I/O 操作的訪問許可權(如果此 Android 裝置支援 MIFARE)。

MifareUltralight

提供對 MIFARE Ultralight 屬性和 I/O 操作的訪問許可權(如果此 Android 裝置支援 MIFARE)。

總結

本文首先介紹了NFC是什麼以及它的幾種工作模式,然後讓大家認識了一下市面上卡片的分類,也介紹了M1卡的資料結構,最後,演示了一下怎在Android中使用NFC來讀取M1卡的卡號。

雖然文章沒有把NFC的所有使用模式都進行講解,但是挑了一個模式進行詳細的講解,相信閱讀這篇文章後,你對Android的NFC不會那麼的陌生了,其他的NFC的工作模式就由大家自行了解學習,這樣才能加深印象和理解。

最後放出本文的demo,大家可以點選這裡下載

本文已由公眾號“愛碼者說”首發

搞懂Nfc刷卡看這篇就夠了

標簽: NFC  intent  標籤  activity