android 文件mimetype_【Android】NFC课件
NFC課件
1.NFC基礎(chǔ)知識
一、NFC基礎(chǔ)知識
1、NFC是什么
NFC,即Near Field Communication,近距離無線通訊技術(shù),是一種短距離的(通常<=4cm或更短)高頻(13.56M Hz)無線通信技術(shù),它提供了一種簡單、觸控式的解決方案,可以讓消費者簡單直觀地交換信息、訪問內(nèi)容與服務(wù)。
2、NFC與RFID的異同
NFC是在RFID的基礎(chǔ)上發(fā)展而來,NFC從本質(zhì)上與RFID沒有太大區(qū)別,都是基于地理位置相近的兩個物體之間的信號傳輸。
不過NFC與RFID還是有區(qū)別的,NFC技術(shù)增加了點對點通信功能,可以快速建立設(shè)備之間的P2P(點對點)無線通信,NFC設(shè)備彼此尋找對方并建立通信連接。P2P通信的雙方設(shè)備是對等的,而RFID通信的雙方設(shè)備是主從關(guān)系。
**1. NFC只是限于13.56MHz的頻段!而RFID的頻段有低頻(125KHz到135KHz),高頻(13.56MHz)和超高頻(860MHz到960MHz之間。
2. 工作有效距離:NFC(小于10cm,所以具有很高的安全性),RFID距離從幾米到幾十米都有!**
二、更細地說NFC
跟NFC有關(guān)的常見的ISO標(biāo)準(zhǔn)有:
| ISO 14443 | RFID卡標(biāo)準(zhǔn)(非接觸IC卡),該標(biāo)準(zhǔn)又有很多子標(biāo)準(zhǔn) | ISO 7816 | 接觸式IC卡標(biāo)準(zhǔn) | ISO 15693 | 某種射頻卡標(biāo)準(zhǔn)吧,這個沒查到資料 | ISO 18092 | NFC標(biāo)準(zhǔn)也就說如果我要實現(xiàn)一個國際通用的RFID卡,就需要滿足ISO14443標(biāo)準(zhǔn)。
我們再來說說現(xiàn)在射頻卡常用的解決方案:飛利浦的Mifare,索尼的Felica,中國人名銀行的Pboc。
Mifare卡有很多種版本(詳見http://en.wikipedia.org/wiki/MIFARE),常見的版本有MIFARE Classic 和MIFARE DESFire,他們分別按照ISO 14443-3 Type A和ISO 14443-4 Type A來實現(xiàn)。
Felica卡之前想通過ISO 14443 Type C認(rèn)證,但是由于某種原因最后失敗了,所以他搞了自己的一套標(biāo)準(zhǔn)叫JIS: X6319-4
Pboc是國內(nèi)常見的支付卡,大部分城市的公交通都是基于Pboc解決方案實現(xiàn)的,據(jù)我個人的理解Pboc卡使用的是基于ISO7816接觸式IC卡標(biāo)準(zhǔn)實現(xiàn)的接觸或非接觸式IC卡。
最后我們解釋一下NFC的常見數(shù)據(jù)格式:NfcA/NfcB/NfcF/NfcV/IsoDep/Ndef/NdefFormatable/
MifareClassic/MifareUltralight(其實后兩種是補充,可選的).
這就是說不同的芯片(解決方案、采用不同的標(biāo)準(zhǔn)實現(xiàn)的)卡中數(shù)據(jù)格式是不一樣的,比如之前我們提到的MIFARE Classic數(shù)據(jù)格式就是NfcA,MIFARE DESFire數(shù)據(jù)格式是IsoDep,我們使用的二代身份證用的就是NfcB,Felica用的就是NfcF,德州儀器的VicinityCard卡用的是NfcV,而Android分享文件就是實用的Ndef格式傳輸數(shù)據(jù)。
三、具體測試過程:
1.首先要在AndroidManifest.xml中聲明如下配置信息:
使用元素允許設(shè)備訪問NFC硬件:
使用元素設(shè)置最小SDK版本,筆者基于android 4.0環(huán)境,因此聲明如下:
<uses-sdkandroid:minSdkVersion="14"android:targetSdkVersion="21" />下面這項不一定需要,如果你希望你的軟件可以在android market中顯示有NFC硬件,可以使用元素聲明:
<uses-featureandroid:name="android.hardware.nfc"android:required="true" />四、NFC標(biāo)簽過濾
當(dāng)系統(tǒng)檢測到一個NFC標(biāo)簽的時候,他會自動去尋找最合適的activity去處理這個intent.
他所發(fā)出的這個Intent將會有三種action:
ACTION_ NDEF_ DISCOVERED:當(dāng)系統(tǒng)檢測到tag中含有NDEF格式的數(shù)據(jù)時,且系統(tǒng)中有activity聲明可以接受包含NDEF數(shù)據(jù)的Intent的時候,系統(tǒng)會優(yōu)先發(fā)出這個action的intent。
ACTION_ TECH_ DISCOVERED:當(dāng)沒有任何一個activity聲明自己可以響應(yīng)ACTION_NDEF_DISCOVERED時,系統(tǒng)會嘗試發(fā)出TECH的intent.即便你的tag中所包含的數(shù)據(jù)是NDEF的,但是如果這個數(shù)據(jù)的MIME type或URI不能和任何一個activity所聲明的想吻合,系統(tǒng)也一樣會嘗試發(fā)出tech格式的intent,而不是NDEF.
ACTION_TAG_DISCOVERED:當(dāng)系統(tǒng)發(fā)現(xiàn)前兩個intent在系統(tǒng)中無人會接受的時候,就只好發(fā)這個默認(rèn)的TAG類型的
在activity的intent過濾xml聲明中,你可以同時聲明過濾這三種action.但是由之前所說,你應(yīng)該知道系統(tǒng)在發(fā)送intent的時候是有優(yōu)先級的,所以你最好清楚自己最想處理哪個。
1:過濾ACTION _ TAG _ DISCOVERED:
<intent-filter ><action android:name="android.nfc.action.TECH_DISCOVERED"/></intent-filter>這個最簡單,也是最后一個被嘗試接受intent的選項。
2:過濾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>其中最重要的應(yīng)該算是data的mimeType類型了,這個定義的越準(zhǔn)確,intent指向你這個activity的成功率就越高,否則系統(tǒng)可能不會發(fā)出你想要的NDEF intent了。下面在講如何使用NDEF寫入NFC標(biāo)簽的時候會多舉幾個類型的例子。
3:過濾ACTION_ TECH_ DISCOVERED:
你首先需要在你的 /res/xml 下面創(chuàng)建一個過濾規(guī)則文件。名字任取,比如可以叫做nfc_tech_filter.xml。這個里面定義的是nfc實現(xiàn)的各種標(biāo)準(zhǔn),每一個nfc卡都會符合多個不同的標(biāo)準(zhǔn),個人理解為這些標(biāo)準(zhǔn)有些相互之間也是兼容的。你可以在檢測到nfc標(biāo)簽后使用getTechList()方法來查看你所檢測的tag到底支持哪些nfc標(biāo)準(zhǔn)。
一個nfc_tech_filter.xml中可以定義多個結(jié)構(gòu)組。每一組代表我聲明我只接受同時滿足這些標(biāo)準(zhǔn)的nfc標(biāo)簽。比如A組表示,只有同時滿足IsoDep,NfcA,NfcB,NfcF這四個標(biāo)準(zhǔn)的nfc標(biāo)簽的intent才能進入。A與B組之間的關(guān)系就是只要滿足其中一個就可以了。換句話說,你的nfc標(biāo)簽技術(shù),滿足A的聲明也可以,滿足B的聲明也可以。
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"><tech-list> --------------------------------A組<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>-----------------------------------------B組<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>在androidManifest文件中聲明xml過濾的舉例如下
<activity><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" />----這個就是你的資源文件名</activity>五:nfc標(biāo)簽前臺分發(fā)系統(tǒng)
之所以把他也歸類在nfc的過濾里面,主要是因為他跟解析nfc標(biāo)簽到不是那么的緊密,他解決的是接受哪些nfc標(biāo)準(zhǔn)的標(biāo)簽問題。所以更接近nfc的過濾。
什么叫nfc的前臺發(fā)布系統(tǒng)?就是說當(dāng)我們已經(jīng)打開我們的應(yīng)用的時候,那么通過這個前臺發(fā)布系統(tǒng)的設(shè)置,我們可以讓我們已經(jīng)啟動的activity擁有更高的優(yōu)先級來依據(jù)我們在代碼中定義的標(biāo)準(zhǔn)來過濾和處理intent,而不是讓別的聲明了intent filter的activity來干擾,甚至連自己聲明在androidManifest中的intent filter都不會來干擾。也就是說foreground Dispatch的優(yōu)先級大于intent filter。
第一種情況:當(dāng)你的activity沒有啟動的時候,去掃描tag,那么系統(tǒng)中所有的intent filter都將一起參與過濾。
第二種情況:當(dāng)你的actiity啟動了,去掃描tag時,那么將直接使用你在foreground dispatch中代碼寫入的過濾標(biāo)準(zhǔn)。如果這個標(biāo)準(zhǔn)沒有命中任何intent,那么系統(tǒng)將使用所有activity聲明的intent filter xml來過濾。
在OnCreate中你可以添加如下代碼
// Create a generic PendingIntent that will be deliver to this activity. The NFC stack will fill in the intent with the details of the discovered tag before delivering to this activity.mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);// 做一個IntentFilter過濾你想要的action 這里過濾的是ndef IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED); //如果你對action的定義有更高的要求,比如data的要求,你可以使用如下的代碼來定義intentFilter // try { // ndef.addDataType("*/*"); // } catch (MalformedMimeTypeException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } //生成intentFilter mFilters = new IntentFilter[] {ndef};// 做一個tech-list??梢钥吹绞嵌S數(shù)據(jù),每一個一維數(shù)組之間的關(guān)系是或,但是一個一維數(shù)組之內(nèi)的各個項就是與的關(guān)系了 mTechLists = new String[][] { new String[] { NfcF.class.getName()},new String[]{NfcA.class.getName()},new String[]{NfcB.class.getName()},new String[]{NfcV.class.getName()}}; 在onPause和 onResume中需要加入相應(yīng)的代碼。 public void onPause() {super.onPause(); //反注冊 mAdapter.disableForegroundDispatch(this); }public void onResume() { super.onResume(); //設(shè)定intentfilter和tech-list。如果兩個都為null就代表優(yōu)先接收任何形式的TAG action。也就是說系統(tǒng)會主動發(fā)TAG intent。 mAdapter.enableForegroundDispatch(this, mPendingIntent, mFilters, mTechLists); }六、開發(fā)實例(讀取數(shù)據(jù))
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.nfc"android:versionCode="1"android:versionName="1.0" ><uses-permission android:name="android.permission.NFC" /><uses-sdkandroid:minSdkVersion="14"android:targetSdkVersion="21" /><!-- 這個聲明可以讓你的應(yīng)用在google play上被聲明使用者必須擁有nfc功能 --><uses-featureandroid:name="android.hardware.nfc"android:required="true" /><applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><activityandroid:name=".MainActivity"android:label="@string/app_name"android:launchMode="singleTop" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter><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"/></activity></application></manifest>res/xml/nfc_tech_filter.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.MifareClassic</tech></tech-list> </resources>Permissions
<uses-permission android:name="android.permission.NFC" />當(dāng)手機開啟了NFC,并且檢測到一個TAG后,TAG分發(fā)系統(tǒng)會自動創(chuàng)建一個封裝了NFC TAG信息的intent。如果多于一個應(yīng)用程序能夠處理這個intent的話,那么手機就會彈出一個框,讓用戶選擇處理該TAG的Activity。TAG分發(fā)系統(tǒng)定義了3中intent。按優(yōu)先級從高到低排列為:
NDEF_DISCOVERED, TECH_DISCOVERED, TAG_DISCOVERED
當(dāng)Android設(shè)備檢測到有NFC Tag靠近時,會根據(jù)Action申明的順序給對應(yīng)的Activity 發(fā)送含NFC消息的 Intent。
此處我們使用的intent-filter的Action類型為TECH_DISCOVERED從而可以處理所有類型為ACTION_TECH_DISCOVERED并且使用的技術(shù)為nfc_tech_filter.xml文件中定義的類型的TAG。
res/layout/activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context="com.example.nfc.MainActivity" ><ScrollView android:id="@+id/scrollView"android:layout_width="match_parent"android:layout_height="match_parent"><TextView android:id="@+id/promt"android:layout_width="match_parent"android:layout_height="wrap_content"android:scrollbars="vertical"android:singleLine="false"android:text="@string/info"/></ScrollView> </LinearLayout>src/com/example/nfc/MainActivity.java
package com.example.nfc;import android.app.Activity; import android.content.Intent; import android.nfc.NfcAdapter; import android.nfc.Tag; import android.nfc.tech.MifareClassic; import android.os.Bundle; import android.widget.TextView;public class MainActivity extends Activity {NfcAdapter nfcAdapter;TextView promt;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);promt = (TextView) findViewById(R.id.promt);//獲取默認(rèn)的NFC控制器nfcAdapter = NfcAdapter.getDefaultAdapter(this);if (nfcAdapter == null) {promt.setText("設(shè)備不支持NFC");return;}if (!nfcAdapter.isEnabled()) {promt.setText("請在系統(tǒng)設(shè)置中先啟用NFC功能");return;}}@Overrideprotected void onResume() {super.onResume();//得到是否檢測到ACTION_TECH_DISCOVERED觸發(fā)if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(getIntent().getAction())) {//處理該intentprocessIntent(getIntent());}}//字符序列轉(zhuǎn)換為16進制字符串private String bytesToHexString(byte[] src) {StringBuilder stringBuilder = new StringBuilder("0x");if (src == null || src.length <= 0) {return null;}char[] buffer = new char[2];for (int i = 0; i < src.length; i++) {buffer[0] = Character.forDigit((src[i] >>> 4) & 0x0F, 16);buffer[1] = Character.forDigit(src[i] & 0x0F, 16);// System.out.println(buffer);stringBuilder.append(buffer);}return stringBuilder.toString();}/*** Parses the NDEF Message from the intent and prints to the TextView*/private void processIntent(Intent intent) {//取出封裝在intent中的TAGString tmp = "此tag到底支持哪些nfc標(biāo)準(zhǔn):n";Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);//獲取支持哪些nfc標(biāo)準(zhǔn) : getTechListfor (String tech : tagFromIntent.getTechList()) {System.out.println(tech);tmp += tech + "n";}boolean auth = false;//讀取TAGMifareClassic mfc = MifareClassic.get(tagFromIntent);try {//Enable I/O operations to the tag from this TagTechnology object.mfc.connect();int type = mfc.getType();//獲取TAG的類型int sectorCount = mfc.getSectorCount();//獲取TAG中包含的扇區(qū)數(shù)String typeS = "";switch (type) {case MifareClassic.TYPE_CLASSIC:typeS = "TYPE_CLASSIC";break;case MifareClassic.TYPE_PLUS:typeS = "TYPE_PLUS";break;case MifareClassic.TYPE_PRO:typeS = "TYPE_PRO";break;case MifareClassic.TYPE_UNKNOWN:typeS = "TYPE_UNKNOWN";break;}tmp += "卡片類型:" + typeS + "n共" + sectorCount + "個扇區(qū)n共" + mfc.getBlockCount() + "個塊n存儲空間:" + mfc.getSize()+ "Bn";for (int j = 0; j < sectorCount; j++) {//嘗試去獲取每個sector的認(rèn)證,只有認(rèn)證通過才能訪問auth = mfc.authenticateSectorWithKeyA(j, MifareClassic.KEY_DEFAULT);int bCount;int bIndex;if (auth) {tmp += "Sector " + j + ":驗證成功n";//讀取扇區(qū)中的塊;這句話其實不是必須的,因為每個sector中本來就只有4個blockbCount = mfc.getBlockCountInSector(j);//我們可以得到每一個sector中的第一個block的編號bIndex = mfc.sectorToBlock(j);//循環(huán)4次拿出一個sector中所有的block//每次循環(huán)bIndex會去++,然后可以得出每一個block的數(shù)據(jù)。這些數(shù)據(jù)是字節(jié)碼,所以你還有一個翻譯的工作要做for (int i = 0; i < bCount; i++) {byte[] data = mfc.readBlock(bIndex);tmp += "Block " + bIndex + " : " + bytesToHexString(data) + "n";bIndex++;}} else {tmp += "Sector " + j + ":驗證失敗n";}}promt.setText(tmp);} catch (Exception e) {e.printStackTrace();}} }關(guān)于MifareClassic卡的背景介紹:數(shù)據(jù)分為16個區(qū)(Sector) ,每個區(qū)有4個塊(Block) ,每個塊可以存放16字節(jié)的數(shù)據(jù)。
每個區(qū)最后一個塊稱為Trailer ,主要用來存放讀寫該區(qū)Block數(shù)據(jù)的Key ,可以有A,B兩個Key,每個Key 長度為6個字節(jié),缺省的Key值一般為全FF或是0. 由 MifareClassic.KEY_DEFAULT 定義。
因此讀寫Mifare Tag 首先需要有正確的Key值(起到保護的作用),如果鑒權(quán)成功
然后才可以讀寫該區(qū)數(shù)據(jù)。
代碼下載:http://download.csdn.net/detail/yingpaixiaochuan/9162381
參考鏈接:
Android NFC 開發(fā)實例
NfcA/NfcB/NfcF/NfcV/IsoDep/Ndef/Mifare/Felica/Pboc/ISOxxxx 都是些什么鳥玩意?
android NFC學(xué)習(xí)筆記(一)
總結(jié)
以上是生活随笔為你收集整理的android 文件mimetype_【Android】NFC课件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 节假日api_iOS能跳过节假日的晚安闹
- 下一篇: simulink显示多个数据_State