Android NfcManager 之NFC接入與介紹
NFC:全稱(chēng)是近場(chǎng)通信(Near Field Communication),是一種短距離無(wú)線技術(shù)
Android Beam是一個(gè)基于近場(chǎng)通信所做的新功能,這個(gè)功能可以為其他手機(jī)分享你正在使用的功能。 Android升級(jí)到4.1后,Android Beam現(xiàn)在可以在兩臺(tái)支持NFC的Android設(shè)備間分享照片和視頻,還可以與支持NFC的藍(lán)牙設(shè)備相連。
Android NFC同時(shí)支持三個(gè)主要的操作模式:
1.設(shè)備讀/寫(xiě)模式,允許NFC設(shè)備的讀/寫(xiě)NFC目標(biāo)設(shè)備;
2.P2P模式,使NFC設(shè)備與其他NFC節(jié)點(diǎn)交換數(shù)據(jù);這種運(yùn)作模式被使用在Android Beam中;
3/卡仿真模式,使NFC設(shè)備本身作為一個(gè)NFC卡。然后模擬NFC卡可以通過(guò)一個(gè)外部的NFC讀寫(xiě)訪問(wèn),如銷(xiāo)售終端NFC點(diǎn)。
4.NDEF數(shù)據(jù)
從NFC便簽讀取NDEF格式的數(shù)據(jù)
向NFC標(biāo)簽寫(xiě)入NDEF格式的數(shù)據(jù)
通過(guò)Android Beam技術(shù)將NDEF數(shù)據(jù)發(fā)送到另一部NFC設(shè)備
5.NFC的三重過(guò)濾機(jī)制intent-filter
兩個(gè)終端設(shè)備要想讀寫(xiě)數(shù)據(jù),會(huì)有個(gè)短暫配對(duì)的時(shí)間,數(shù)據(jù)接收端會(huì)根據(jù)具體的數(shù)據(jù)格式和標(biāo)簽類(lèi)型調(diào)用相應(yīng)的Activity(Tag Dispatch),這個(gè)activity需要定義一個(gè)intent filter中指定不同的過(guò)濾機(jī)制,分三個(gè)等級(jí),所以叫NFC的三重過(guò)濾機(jī)制
5.1NDEF_DISCOVERED
只過(guò)濾固定格式的NDEF數(shù)據(jù),比如純文本,指定協(xié)議(HTTP FTP SMB等)的URI
5.2TECH_DISCOVERED
當(dāng)ACTION_NDEF_DISCOVERED指定的過(guò)濾機(jī)制無(wú)法匹配Tag時(shí),就會(huì)使用這種過(guò)濾機(jī)制進(jìn)行匹配,這種過(guò)濾機(jī)制并不是通過(guò)Tag的數(shù)據(jù)進(jìn)行匹配的,而是根據(jù)Tag支持的數(shù)據(jù)存儲(chǔ)格式進(jìn)行匹配,因此這種機(jī)制使用范圍很廣
5.3TAG_DISCOVERED
這種機(jī)制用來(lái)處理未識(shí)別的Tag
接入流程:
1.首選NFC依賴(lài)硬件,這個(gè)就需要權(quán)限支持
外獲取NFC設(shè)備數(shù)據(jù)需要在內(nèi)添加如下內(nèi)容
nfc_tech_filter是在res/xml文件下的自定義xml文件:
android.nfc.tech.IsoDep
android.nfc.tech.NfcA
2.三種模式的Demo運(yùn)行
NFC的數(shù)據(jù)NfcAdapter來(lái)管理的,NfcAdapter有兩種途徑獲取
NfcManager manager=(NfcManager)getSystemService(Context.NFC_SERVICE);
NfcAdapter adapter= manager.getDefaultAdapter();
這是通過(guò)NFCmanager獲取,

NfcManger的構(gòu)造器 也是通過(guò)NcfAdapter.getNfcAdapter(Context)獲取adapter的實(shí)例。
同理:我們也可以直接獲取NfcAdapter,不通過(guò)NfcManger來(lái)獲取。
NcfAdapter adapter=NfcAdapter.getDefaultAdapter(Context context)

這個(gè)adapter其實(shí)也是需要通過(guò)NfcManager來(lái)獲取,直接調(diào)用靜態(tài)方法,針對(duì)不熟悉getSystemService來(lái)說(shuō),可以直接使用封裝現(xiàn)成的。
adapter的內(nèi)部會(huì)有一個(gè):
static HashMap
,所以NFC是獨(dú)立于Activity,因?yàn)閍dapter內(nèi)部有一個(gè)靜態(tài)變量,會(huì)把當(dāng)前山下文使用的nfcadapter緩存起來(lái)。
2.Tag接收頁(yè)面的啟動(dòng)模式
AIN" />
launchMode:因?yàn)镹FC是一個(gè)獨(dú)立特性,所有頁(yè)面啟動(dòng)需要保持一個(gè),singleTask或者
singleTop
NdefMessage:
主要是描寫(xiě)敘述NDEF格式的信息
NdefRecord:
這個(gè)是秒速NDEF信息的一個(gè)信息段
這兩個(gè)都是Android NCF技術(shù)的核心類(lèi),不管是讀寫(xiě)NFC標(biāo)簽還是通過(guò)Android Beam技術(shù)傳遞數(shù)據(jù)都須要這兩個(gè)類(lèi)
小牛刀
1.獲取Tag對(duì)象
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
正常該intent通過(guò)Activity這個(gè)方法獲?。?/p>
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
}
因?yàn)槿魏雾?yè)面被打開(kāi)多少次,都會(huì)執(zhí)行onNewIntent方法
2.推斷NFC標(biāo)簽的數(shù)格式
Ndef ndef = Ndef.get(tag);
3.寫(xiě)入數(shù)據(jù)
ndef.wrriteNdefMessage(ndefMessage);
4.NdefRecord:NDEF格式數(shù)據(jù),創(chuàng)建對(duì)象提供如下
public static NdefRecord createApplicationRecord(String packageName)
public static NdefRecord createUri(Uri uri)
public static NdefRecord createUri(String uriString)
public static NdefRecord createMime(String mimeType, byte[] mimeData)
public static NdefRecord createExternal(String domain, String type, byte[] data)
public static NdefRecord createTextRecord(String languageCode, String text)
public NdefRecord(short tnf, byte[] type, byte[] id, byte[] payload)
public NdefRecord(byte[] data)
Uri支持格式如下:
private static final String[] URI_PREFIX_MAP = new String[] {
"", // 0x00
"http://www.", // 0x01
"https://www.", // 0x02
"http://", // 0x03
"https://", // 0x04
"tel:", // 0x05
"mailto:", // 0x06
"ftp://anonymous:anonymous@", // 0x07
"ftp://ftp.", // 0x08
"ftps://", // 0x09
"sftp://", // 0x0A
"smb://", // 0x0B
"nfs://", // 0x0C
"ftp://", // 0x0D
"dav://", // 0x0E
"news:", // 0x0F
"telnet://", // 0x10
"imap:", // 0x11
"rtsp://", // 0x12
"urn:", // 0x13
"pop:", // 0x14
"sip:", // 0x15
"sips:", // 0x16
"tftp:", // 0x17
"btspp://", // 0x18
"btl2cap://", // 0x19
"btgoep://", // 0x1A
"tcpobex://", // 0x1B
"irdaobex://", // 0x1C
"file://", // 0x1D
"urn:epc:id:", // 0x1E
"urn:epc:tag:", // 0x1F
"urn:epc:pat:", // 0x20
"urn:epc:raw:", // 0x21
"urn:epc:", // 0x22
"urn:nfc:", // 0x23
};
三、核心業(yè)務(wù)
1.action的校驗(yàn)
String action = intent.getAction();
if (TextUtils.equals(action, NfcAdapter.ACTION_TAG_DISCOVERED)) {
return true;
}
2.讀
private void readNfcTag(Intent intent) {
if (intent == null)
return;
Parcelable[] parcelables = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (parcelables == null || parcelables.length == 0)
return;
NdefMessage mNdefMsg = (NdefMessage) parcelables[0];
NdefRecord mNdefRecord = mNdefMsg.getRecords()[0];
if (mNdefRecord != null) {
try {
String msg = new String(mNdefRecord.getPayload(), "utf-8");
} catch (Exception e) {
}
}
}
3.寫(xiě)
//NFC寫(xiě)入
private void writeNFC(Tag tag) {
//null不執(zhí)行操作,強(qiáng)調(diào)敲代碼的邏輯性
if (tag == null) {
return;
}
NdefMessage ndefMessage = new NdefMessage(new NdefRecord[]{NdefRecord.createApplicationRecord(mPackNmae)});
//獲得寫(xiě)入大小
int size = ndefMessage.toByteArray().length;
//2.推斷是否是NDEF標(biāo)簽
try {
Ndef ndef = Ndef.get(tag);
if (ndef != null) {
//說(shuō)明是NDEF標(biāo)簽,開(kāi)始連接
ndef.connect();
//推斷是否可寫(xiě)
if (!ndef.isWritable()) {
showToast("當(dāng)前設(shè)備不支持寫(xiě)入");
return;
}
//推斷大小
if (ndef.getMaxSize() < size) {
showToast("容量太小了");
return;
}
//寫(xiě)入
ndef.writeNdefMessage(ndefMessage);
showToast("寫(xiě)入成功");
}
} catch (Exception e) {
e.printStackTrace();
}
}
加密卡芯片的讀寫(xiě)MifareClassic
MifareClassic:
“MIFARE Classic是恩智浦半導(dǎo)體開(kāi)發(fā)的可用于非接觸式智能卡,符合ISO/IEC 14443 A類(lèi)標(biāo)準(zhǔn)。用于公共交通票證等應(yīng)用,還可用于各類(lèi)其他應(yīng)用有S20,S50(M1),S70幾種規(guī)格,主要是根據(jù)存儲(chǔ)器容量劃分,存儲(chǔ)器容量分別有320B,1K,4K
這種卡和其他的不同,是有密碼校驗(yàn),不同廠家可以定制不同的密碼和數(shù)據(jù)格式,簡(jiǎn)單的介紹如下
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
MifareClassic mifareClassic = MifareClassic.get(tag);
try {
boolean connected = mifareClassic.isConnected();
if (connected) {
int count = mifareClassic.getSectorCount();
for (int index = 0; index < count; index++) {
//獲取善區(qū)數(shù)
boolean keyAopen = mifareClassic.authenticateSectorWithKeyA(index, MifareClassic.KEY_DEFAULT);
if (keyAopen) {
//獲取扇區(qū)里面塊的數(shù)量
int bCount = mifareClassic.getBlockCountInSector(index);
int bIndex = mifareClassic.sectorToBlock(index);
for (int position = 0; position < bCount; position++) {
byte[] data = mifareClassic.readBlock(bIndex + position);//進(jìn)行了讀卡
msgBuffer.append("塊" + (bIndex + position) + "數(shù)據(jù):").append(ByteArrayToHexString(data)).append("\r\n");
//修改KeyA和KeyB
if ((bIndex + position) == (4 * index + 3)) {
//將所有扇區(qū)的最后一個(gè)Block修改為111111111111ff078069111111111111
mifareClassic.writeBlock(bIndex + position, new byte[]{(byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0xff, 0x07, (byte) 0x80, (byte) 0x69, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11});
// Log.e("onNewIntent:",(bIndex+position)+"塊加密成功");
}
}
}
}
}
} catch (Exception e) {
}
關(guān)于Mifare Classic也是用的比較多的地方,暫時(shí)先寫(xiě)到這,以后將會(huì)整理一份詳細(xì)的介紹。
本文僅代表作者觀點(diǎn),版權(quán)歸原創(chuàng)者所有,如需轉(zhuǎn)載請(qǐng)?jiān)谖闹凶⒚鱽?lái)源及作者名字。
免責(zé)聲明:本文系轉(zhuǎn)載編輯文章,僅作分享之用。如分享內(nèi)容、圖片侵犯到您的版權(quán)或非授權(quán)發(fā)布,請(qǐng)及時(shí)與我們聯(lián)系進(jìn)行審核處理或刪除,您可以發(fā)送材料至郵箱:service@tojoy.com





