http://blog.csdn.net/pku_android/article/details/7430788
類:?Android應用開發系列教程?Android應用開發技巧2012-04-06 08:56?
51910人閱讀??
收藏?
舉報
androidtypesactionlayoutstringbuffer
作者:裘德超
使用硬件:Google Nexus S,北京大學學生卡。(ps:筆者本想使用公交一卡通進行測試,發現手機不能正確識別)
手機操作系統:Android ICS 4.04。
開發時,筆者從Google Play Store上下載了NFC TagInfo軟件進行對比學習。所以我們可以使用任意一張能被TagInfo軟件正確識別的卡做測試。
在Android NFC 應用中,Android手機通常是作為通信中的發起者,也就是作為各種NFC卡的讀寫器。Android對NFC的支持主要在 android.nfc 和android.nfc.tech 兩個包中。
android.nfc 包中主要類如下:
NfcManager 可以用來管理Android設備中指出的所有NFCAdapter,但由于大部分Android設備只支持一個NFC Adapter,所以一般直接調用getDefaultAapater來獲取手機中的Adapter。
NfcAdapter 相當于一個NFC適配器,類似于電腦裝了網絡適配器才能上網,手機裝了NfcAdapter才能發起NFC通信。
?NDEF: NFC Data Exchange Format,即NFC數據交換格式。
NdefMessage 和NdefRecord NDEF 為NFC forum 定義的數據格式。
Tag 代表一個被動式Tag對象,可以代表一個標簽,卡片等。當Android設備檢測到一個Tag時,會創建一個Tag對象,將其放在Intent對象,然后發送到相應的Activity。
android.nfc.tech 中則定義了可以對Tag進行的讀寫操作的類,這些類按照其使用的技術類型可以分成不同的類如:NfcA, NfcB, NfcF,以及MifareClassic 等。其中MifareClassic比較常見。
在本次實例中,筆者使用北京大學學生卡進行數據讀取測試,學生卡的TAG類型為MifareClassic。
AndroidManifest.xml:
[html]?view plaincopy
<span?style="font-size:16px;"><?xml?version="1.0"?encoding="utf-8"?>?? <manifest?xmlns:android="http://schemas.android.com/apk/res/android"?? ????package="org.reno"?? ????android:versionCode="1"?? ????android:versionName="1.0"?>?? ????<uses-permission?android:name="android.permission.NFC"?/>?? ????<uses-sdk?android:minSdkVersion="14"?/>?? ????<uses-feature?android:name="android.hardware.nfc"?android:required="true"?/>?? ????<application?? ????????android:icon="@drawable/ic_launcher"?? ????????android:label="@string/app_name"?>?? ????????<activity?? ????????????android:name="org.reno.Beam"?? ????????????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>?? </span>??
res/xml/nfc_tech_filter.xml:
<resources?xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
????<tech-list>
???????<tech>android.nfc.tech.MifareClassic</tech>
????</tech-list>
</resources>
<uses-permission?android:name="android.permission.NFC"?/>
<uses-feature?android:name="android.hardware.nfc"?android:required="true"?/>
表示會使用到硬件的NFC功能。并且當用戶在Google Play Store中搜索時,只有帶有NFC功能的手機才能夠搜索到本應用。
?
當手機開啟了NFC,并且檢測到一個TAG后,TAG分發系統會自動創建一個封裝了NFC TAG信息的intent。如果多于一個應用程序能夠處理這個intent的話,那么手機就會彈出一個框,讓用戶選擇處理該TAG的Activity。TAG分發系統定義了3中intent。按優先級從高到低排列為:
NDEF_DISCOVERED, TECH_DISCOVERED, TAG_DISCOVERED
當Android設備檢測到有NFC Tag靠近時,會根據Action申明的順序給對應的Activity 發送含NFC消息的 Intent。
此處我們使用的intent-filter的Action類型為TECH_DISCOVERED從而可以處理所有類型為ACTION_TECH_DISCOVERED并且使用的技術為nfc_tech_filter.xml文件中定義的類型的TAG。
?
詳情可查看http://developer.android.com/guide/topics/nfc/nfc.html說明。下圖為當手機檢測到一個TAG時,啟用Activity的匹配過程。
res/layout/main.xml
[html]?view plaincopy
<?xml?version="1.0"?encoding="utf-8"?>?? <LinearLayout?xmlns:android="http://schemas.android.com/apk/res/android"?? ????android:layout_width="fill_parent"?? ????android:layout_height="fill_parent"?? ????android:orientation="vertical"?>?? ?? ????<ScrollView?? ????????android:id="@+id/scrollView"?? ????????android:layout_width="fill_parent"?? ????????android:layout_height="fill_parent"?? ????????android:background="@android:drawable/edit_text"?>?? ?? ????????<TextView?? ????????????android:id="@+id/promt"?? ????????????android:layout_width="fill_parent"?? ????????????android:layout_height="wrap_content"?? ????????????android:scrollbars="vertical"?? ????????????android:singleLine="false"?? ????????????android:text="@string/info"?/>?? ????</ScrollView>?? ?? </LinearLayout>??
定義了Activity的布局:只有一個帶有滾動條的TextView用于顯示從TAG中讀取的信息。
res/values/strings.xml
[html]?view plaincopy
<?xml?version="1.0"?encoding="utf-8"?>?? <resources>?? ????<string?name="app_name">NFC測試</string>?? ????<string?name="info">掃描中。。。</string>?? </resources>??
src/org/reno/Beam.java
[java]?view plaincopy
package?org.reno;?? ?? 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?Beam?extends?Activity?{?? ????NfcAdapter?nfcAdapter;?? ????TextView?promt;?? ????@Override?? ????public?void?onCreate(Bundle?savedInstanceState)?{?? ????????super.onCreate(savedInstanceState);?? ????????setContentView(R.layout.main);?? ????????promt?=?(TextView)?findViewById(R.id.promt);?? ?????????? ????????nfcAdapter?=?NfcAdapter.getDefaultAdapter(this);?? ????????if?(nfcAdapter?==?null)?{?? ????????????promt.setText("設備不支持NFC!");?? ????????????finish();?? ????????????return;?? ????????}?? ????????if?(!nfcAdapter.isEnabled())?{?? ????????????promt.setText("請在系統設置中先啟用NFC功能!");?? ????????????finish();?? ????????????return;?? ????????}?? ????}?? ?? ????@Override?? ????protected?void?onResume()?{?? ????????super.onResume();?? ?????????? ????????if?(NfcAdapter.ACTION_TECH_DISCOVERED.equals(getIntent().getAction()))?{?? ?????????????? ????????????processIntent(getIntent());?? ????????}?? ????}?? ?????? ????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();?? ????}?? ?? ????? ? ?? ????private?void?processIntent(Intent?intent)?{?? ?????????? ????????Tag?tagFromIntent?=?intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);?? ????????for?(String?tech?:?tagFromIntent.getTechList())?{?? ????????????System.out.println(tech);?? ????????}?? ????????boolean?auth?=?false;?? ?????????? ????????MifareClassic?mfc?=?MifareClassic.get(tagFromIntent);?? ????????try?{?? ????????????String?metaInfo?=?"";?? ?????????????? ????????????mfc.connect();?? ????????????int?type?=?mfc.getType();?? ????????????int?sectorCount?=?mfc.getSectorCount();?? ????????????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;?? ????????????}?? ????????????metaInfo?+=?"卡片類型:"?+?typeS?+?"\n共"?+?sectorCount?+?"個扇區\n共"?? ????????????????????+?mfc.getBlockCount()?+?"個塊\n存儲空間:?"?+?mfc.getSize()?+?"B\n";?? ????????????for?(int?j?=?0;?j?<?sectorCount;?j++)?{?? ?????????????????? ????????????????auth?=?mfc.authenticateSectorWithKeyA(j,?? ????????????????????????MifareClassic.KEY_DEFAULT);?? ????????????????int?bCount;?? ????????????????int?bIndex;?? ????????????????if?(auth)?{?? ????????????????????metaInfo?+=?"Sector?"?+?j?+?":驗證成功\n";?? ?????????????????????? ????????????????????bCount?=?mfc.getBlockCountInSector(j);?? ????????????????????bIndex?=?mfc.sectorToBlock(j);?? ????????????????????for?(int?i?=?0;?i?<?bCount;?i++)?{?? ????????????????????????byte[]?data?=?mfc.readBlock(bIndex);?? ????????????????????????metaInfo?+=?"Block?"?+?bIndex?+?"?:?"?? ????????????????????????????????+?bytesToHexString(data)?+?"\n";?? ????????????????????????bIndex++;?? ????????????????????}?? ????????????????}?else?{?? ????????????????????metaInfo?+=?"Sector?"?+?j?+?":驗證失敗\n";?? ????????????????}?? ????????????}?? ????????????promt.setText(metaInfo);?? ????????}?catch?(Exception?e)?{?? ????????????e.printStackTrace();?? ????????}?? ????}?? }??
關于MifareClassic卡的背景介紹:數據分為16個區(Sector) ,每個區有4個塊(Block) ,每個塊可以存放16字節的數據。
每個區最后一個塊稱為Trailer ,主要用來存放讀寫該區Block數據的Key ,可以有A,B兩個Key,每個Key 長度為6個字節,缺省的Key值一般為全FF或是0. 由 MifareClassic.KEY_DEFAULT 定義。
因此讀寫Mifare Tag 首先需要有正確的Key值(起到保護的作用),如果鑒權成功
然后才可以讀寫該區數據。
執行效果:
參考聯接:
http://developer.android.com/guide/topics/nfc/nfc.html
http://developer.android.com/reference/android/nfc/tech/MifareClassic.html
http://www.imobilebbs.com/wordpress/?p=2822
總結
以上是生活随笔為你收集整理的Android NFC 开发实例的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。