引言
NFC,即Near Field Communication,近距離無線通訊技術(shù),是一種短距離的(通常<=4cm或更短)高頻(13.56M Hz)無線通信技術(shù),它提供了一種簡單、觸控式的解決方案,可以讓消費(fèi)者簡單直觀地交換信息、訪問內(nèi)容與服務(wù)。NFC技術(shù)是由非接觸式射頻識(shí)別(RFID)及互連互通技術(shù)整合演變而來,通過在單一芯片上集成感應(yīng)式讀卡器、感應(yīng)式卡片和點(diǎn)對(duì)點(diǎn)通信的功能,利用移動(dòng)終端實(shí)現(xiàn)移動(dòng)支付、電子票務(wù)、門禁、移動(dòng)身份識(shí)別、防偽等應(yīng)用。
NFC技術(shù)
工作模式
NFC根據(jù)業(yè)務(wù)模式不同大概分為三種模式。
(1)讀卡器模式
??數(shù)據(jù)在NFC芯片中,可以簡單理解成“刷標(biāo)簽”。本質(zhì)上就是通過支持NFC的手機(jī)或其它電子設(shè)備從帶有NFC芯片的標(biāo)簽、貼紙、名片等媒介中讀寫信息。通常NFC標(biāo)簽是不需要外部供電的。當(dāng)支持NFC的外設(shè)向NFC讀寫數(shù)據(jù)時(shí),它會(huì)發(fā)送某種磁場,而這個(gè)磁場會(huì)自動(dòng)的向NFC標(biāo)簽供電。
(2)仿真卡模式
??數(shù)據(jù)在支持NFC的手機(jī)或其它電子設(shè)備中,可以簡單理解成“刷手機(jī)”。本質(zhì)上就是將支持NFC的手機(jī)或其它電子設(shè)備當(dāng)成借記卡、公交卡、門禁卡等IC卡使用?;驹硎菍⑾鄳?yīng)IC卡中的信息憑證封裝成數(shù)據(jù)包存儲(chǔ)在支持NFC的外設(shè)中 。
在使用時(shí)還需要一個(gè)NFC射頻器(相當(dāng)于刷卡器)。將手機(jī)靠近NFC射頻器,手機(jī)就會(huì)接收到NFC射頻器發(fā)過來的信號(hào),在通過一系列復(fù)雜的驗(yàn)證后,將IC卡的相應(yīng)信息傳入NFC射頻器,最后這些IC卡數(shù)據(jù)會(huì)傳入NFC射頻器連接的電腦,并進(jìn)行相應(yīng)的處理(如電子轉(zhuǎn)帳、開門等操作)。
(3)點(diǎn)對(duì)點(diǎn)模式
??該模式與藍(lán)牙、紅外差不多,用于不同NFC設(shè)備之間進(jìn)行數(shù)據(jù)交換,不過這個(gè)模式已經(jīng)沒有有“刷”的感覺了。其有效距離一般不能超過4厘米,但傳輸建立速度要比紅外和藍(lán)牙技術(shù)快很多,傳輸速度比紅外塊得多,如過雙方都使用Android4.2,NFC會(huì)直接利用藍(lán)牙傳輸。這種技術(shù)被稱為Android Beam。所以使用Android Beam傳輸數(shù)據(jù)的兩部設(shè)備不再限于4厘米之內(nèi)。
??點(diǎn)對(duì)點(diǎn)模式的典型應(yīng)用是兩部支持NFC的手機(jī)或平板電腦實(shí)現(xiàn)數(shù)據(jù)的點(diǎn)對(duì)點(diǎn)傳輸,例如,交換圖片或同步設(shè)備聯(lián)系人。因此,通過NFC,多個(gè)設(shè)備如數(shù)字相機(jī),計(jì)算機(jī),手機(jī)之間,都可以快速連接,并交換資料或者服務(wù)。
重要參數(shù)
- 有效傳輸范圍<=4cm
- 傳輸速度有三種:106kbps;?212kbps;?424kbps
- 建立連接時(shí)間<1s
- NFC工作頻率為13.65兆赫茲
開發(fā)流程
NFC標(biāo)簽的復(fù)雜度不一。簡單的標(biāo)簽僅能夠提供讀寫語義,有時(shí)編程域是一次性的,寫完卡片就變成只讀。更復(fù)雜一點(diǎn)的tag能夠提供數(shù)學(xué)運(yùn)算,擁有加密硬件保護(hù)區(qū)塊的訪問。最最復(fù)雜的tag包含操作環(huán)境,允許tag上執(zhí)行的代碼進(jìn)行交互。我們還能夠以各種格式來向tag中寫入存儲(chǔ)數(shù)據(jù),但很多Android的API框架都是基于NFC論壇制定的NDEF標(biāo)準(zhǔn)。
添加NFC權(quán)限
首先,在AndroidManifests.xml中聲明NFC和添加相應(yīng)的權(quán)限。
<uses-feature android:name="android.hardware.nfc"
android:required="true" />
<uses-permission android:name="android.permission.NFC" />
添加識(shí)別NFC標(biāo)簽
NFC有三種過濾器分別是ACTION_NDEF_DISCOVERED,ACTION_TECH_DISCOVERED,ACTION_TAG_DISCOVERED。
- ACTION_NDEF_DISCOVERED
當(dāng)掃描到的tag中包含有NDEF載荷且為已知類型,該intent將用來啟動(dòng)Activity。該intent的優(yōu)先級(jí)最高,tag分發(fā)系統(tǒng)總是先于其他intent用該intent來啟動(dòng)Activity。
- ACTION_TECH_DISCOVERED
如果manifest中沒有注冊(cè)處理ACTION_NDEF_DISCOVERED類型的intent,該intent將被用以啟動(dòng)Activity。如果tag中沒有包含可以映射到MIME或者URI類型的數(shù)據(jù),或者雖然沒有包含NDEF數(shù)據(jù),但是已知的tag技術(shù),則該intent也會(huì)被直接啟用。
- ACTION_TAG_DISCOVERED
如果沒有上述兩個(gè)intent,那么該intent就會(huì)啟動(dòng)。
當(dāng)android設(shè)備掃描到一個(gè)NFC標(biāo)簽時(shí),會(huì)自動(dòng)尋找最適合的Activity來處理這個(gè)Tag。在Activity中添加intent-filter標(biāo)簽,當(dāng)掃描到NFC設(shè)備時(shí)系統(tǒng)會(huì)打開此Activity。
1.ACTION_NDEF_DISCOVERED過濾器定義如下:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
2.ACTION_TECH_DISCOVERED過濾器定義如下:
<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" />
filter_nfc.xml文件
<?xml version="1.0" encoding="utf-8" ?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<tech-list>
<tech>android.nfc.tech.IsoDep</tech>
<tech>android.nfc.tech.NfcA</tech>
<tech>android.nfc.tech.NfcB</tech>
<tech>android.nfc.tech.NfcF</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcV</tech>
<tech>android.nfc.tech.Ndef</tech>
<tech>android.nfc.tech.NdefFormatable</tech>
<tech>android.nfc.tech.MifareClassic</tech>
<tech>android.nfc.tech.MifareUltralight</tech>
</tech-list>
</resources>
MIFARE Classic數(shù)據(jù)格式就是NfcA,MIFARE DESFire數(shù)據(jù)格式是IsoDep(交通卡),NfcB(身份證),Felica用的就是NfcF,德州儀器的VicinityCard卡用的是NfcV,而Android分享文件就是實(shí)用的Ndef格式傳輸數(shù)據(jù)。
3.ACTION_TAG_DISCOVERED過濾器定義如下:
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
</intent-filter>
初始化適配器
NFC開發(fā)需要使用安卓系統(tǒng)提供的NfcAdapter對(duì)象,使用該對(duì)象管理NFC設(shè)備。
//獲取NfcAdapter對(duì)象,此方法與獲取藍(lán)牙適配器對(duì)象類似
mNfcAdapter = NfcAdapter.getDefaultAdapter(getApplicationContext());
if (mNfcAdapter == null) {
Toast.makeText(this, "該設(shè)備不支持nfc", Toast.LENGTH_SHORT).show();
finish();
return;
}
if (!mNfcAdapter.isEnabled()) {
startActivity(new Intent("android.settings.NFC_SETTINGS"));
Toast.makeText(this, "設(shè)備未開啟nfc", Toast.LENGTH_SHORT).show();
}
啟用NFC前臺(tái)調(diào)度
在Activity的onResume方法中打開前臺(tái)調(diào)度。
@Override
protected void onResume() {
super.onResume();
//一旦截獲NFC消息,就會(huì)通過PendingIntent調(diào)用窗口
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter[] intentFilters = new IntentFilter[]{};
//用于打開前臺(tái)調(diào)度(擁有最高的權(quán)限),當(dāng)這個(gè)Activity位于前臺(tái)(前臺(tái)進(jìn)程),即可調(diào)用這個(gè)方法開啟前臺(tái)調(diào)度
mNfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFilters, null);
}
接收數(shù)據(jù)
當(dāng)手機(jī)端檢測接收到NFC設(shè)備數(shù)據(jù)時(shí),在onNewIntent方法中即可接受到數(shù)據(jù)。在onNewIntent方法參數(shù)intent對(duì)象中獲取數(shù)據(jù)。
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())
|| NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())
|| NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
//讀取NFC的id
String id = ByteArrayToHexString(tag.getId());
//獲取tag中的數(shù)據(jù)信息
String[] tagTechList = tag.getTechList();
if (tagTechList != null) {
for (int i = 0; i < tagTechList.length; i++) {
stringBuilder.append("*").append(tagTechList[i]).append("*").append("\n");
stringBuilder.append(readTech(tag, tagTechList[i],intent));
}
}
Parcelable[] rawArray = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawArray != null) {
//獲取NDEF描述信息
NdefMessage mNdefMsg = (NdefMessage) rawArray[0];
//獲取NDEF記錄信息
NdefRecord mNdefRecord = mNdefMsg.getRecords()[0];
if (mNdefRecord != null) {
String readResult = new String(mNdefRecord.getPayload(), "UTF-8");
}
}
}
}
發(fā)送數(shù)據(jù)
* 向NFC發(fā)送數(shù)據(jù)
* data要發(fā)送的數(shù)據(jù)
* intent onNewIntent方法回調(diào)的Intent對(duì)象
public static void writeNFCToTag(String data, Intent intent) throws IOException, FormatException {
//獲取Tag對(duì)象
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
Ndef ndef = Ndef.get(tag);
//連接
ndef.connect();
NdefRecord ndefRecord = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
ndefRecord = NdefRecord.createTextRecord(null, data);
}
//數(shù)據(jù)格式打包
NdefRecord[] records = {ndefRecord};
NdefMessage ndefMessage = new NdefMessage(records);
//發(fā)送數(shù)據(jù)
ndef.writeNdefMessage(ndefMessage);
}
關(guān)閉NFC前臺(tái)調(diào)度
之前在Activity的onResume方法中啟用NFC的前臺(tái)調(diào)度,相應(yīng)的,在onPuse方法中關(guān)閉NFC的前臺(tái)調(diào)度。
//調(diào)用disableForegroundDispatch方法關(guān)閉前臺(tái)調(diào)度
if(mNfcAdapter != null){
mNfcAdapter.disableForegroundDispatch(this);
}
總結(jié)
NFC技術(shù)作為一種新興技術(shù)在世界范圍內(nèi)受到了廣泛關(guān)注,尤其是手機(jī)的廣泛應(yīng)用,為NFC技術(shù)的長足發(fā)展提供了前提。NFC技術(shù)原理簡單,因此成本相對(duì)低廉,除此之外NFC通信的帶寬高、能耗低等特點(diǎn)也是促進(jìn)NFC技術(shù)發(fā)展的一大優(yōu)勢。