Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> NFC的android實現

NFC的android實現

編輯:關於Android編程

NFC簡介:

Near Field Communication 近場通信,是一種數據傳輸技術。

與wifi、藍牙、紅外線等數據傳輸技術的一個主要差異就是有效距離一般不能超過4cm。

 

NFC支持3種工作模式:

1.讀卡器模式;

2.仿真卡模式;

3.點對點模式;

 

1.讀卡器模式:

通過NFC設備(支持NFC的Android手機)從帶有NFC芯片的標簽、貼紙、報紙、明信片等媒介讀取信息,或將數據寫到這些媒介中。

 

2.仿真卡模式:

是將支持NFC的手機或其他電子設備當成借記卡、信用卡、公交卡、門禁卡等IC卡使用;基本原理是將相應的IC卡中的信息(支付憑證)封裝成數據包存儲在支持NFC的手機中,在使用時還需要一個NFC射頻器(相當於刷傳統IC卡時使用的刷卡器),將手機靠近NFC射頻器,手機就會收到NFC射頻器發過來的信號,在通過一系列復雜的驗證後,將IC卡的相應信息傳入NFC射頻器,最後這些IC卡數據會傳入NFC射頻器連接的計算機,並進行相應的處理(如電子轉賬、開門等操作)。

 

3.點對點模式:

與藍牙、紅外差不多,可以用於不同的NFC設備之間進行數據交換,只是NFC的點對點模式有效距離更短,不能超過4cm;但是如果兩個設備使用的都是Android4.2及以上版本,NFC會直接利用藍牙傳輸,這種技術被稱為Android Beam,所以Android Beam傳輸數據的兩部設備不局限於4cm之內。

 

基礎知識:

1.Android SDK API主要支持NFC論壇標准(Forum Standard),這種標准被稱為NDEF(NFC Data Exchange Format,NFC數據交換格式);

 

2.Android SDK API支持如下三種NDEF數據的操作:

a.從NFC標簽讀取NDEF格式的數據;

b.向NFC標簽寫入NDEF格式的數據;

c.通過Android Beam技術將NDEF數據發送到另一部NFC設備;

 

3.在一個NFC設備讀取NFC標簽或另一個NFC設備中的數據之前會在0.1秒的時間之內建立NFC連接,然後數據會自動從被讀取一端流向讀取數據的一端;數據接收端會根據具體的數據格式和標簽類型調用相應的Activity(這種行為也稱為Tag Dispatch),這些Activity都需要定義Intent Filter,這些Intent Filter中就會指定不同的過濾機制,分為三個級別,也稱為NFC的三重過濾機制。

 

4.NDEF_DISCOVERED:

只過濾固定格式的NDEF數據。例如:純文本、指定協議(http、ftp、smb等)的URI等;

 

TECH_DISCOVERED:

當ACTION_NDEF_DISCOVERED指定的過濾機制無法匹配Tag時,就會使用這種過濾機制進行匹配,這種過濾機制並不是通過Tag中的數據格式進行匹配的,而是根據Tag支持的數據存儲格式進行匹配,因此這種過濾機制的范圍更廣;

 

TAG_DISCOVERED:

如果將NFC過濾機制看成if...else if...else語句的話,那麼這種過濾機制就相當於else部分,當前面兩種過濾機制都匹配失敗後,系統就會利用這種過濾機制來處理,這種過濾機制用來處理未識別的Tag(數據格式不對,而且Tag支持的格式也不匹配)。

 

5.Android系統會依次匹配NDEF_DISCOVERED、TECH_DISCOVERED和TAG_DISCOVERED;如果通過三重過濾機制仍然無法匹配Tag,則什麼都不做;通常在成功匹配Tag後,Android設備會發出比較清脆的聲音,而未成功匹配Tag,就會發出比較沉悶的聲音。

 

此過程的處理流程如下圖所示:

\

6.在manifest文件中需要設置的部分有:

設置權限:

<uses-permission android:name="android.permission.NFC" />

限制Android版本:

android:minSdkVersion="14"

限制安裝的設備:

<uses-feature  android:name="android.hardware.nfc"  android:required="true" />

設置Activity的Intent Filter,比如設置為三種過濾機制的一種:

<intent-filter>
    <action android:name="android.nfc.action.TECH_DISCOVERED" />
</intent-filter>

接下來,我們來第一個例子,這個例子是屬於讀卡器模式,從NFC芯片中讀取和寫入數據。

它的manifest文件內容如下:

<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    package="com.r8c.nfc_demo"  
    android:versionCode="110"  
    android:versionName="1.1.0" >  
  
    <uses-sdk  
        android:minSdkVersion="15"  
        android:targetSdkVersion="17" />  
    <!-- NFC權限聲明 -->  
    <uses-permission android:name="android.permission.NFC" />  
  
    <uses-feature  
        android:name="android.hardware.nfc"  
        android:required="true" />  
  
    <application  
        android:allowBackup="true"  
        android:icon="@drawable/ic_launcher"  
        android:label="@string/app_name"  
        android:theme="@style/AppTheme" >  
  
        <activity  
            android:name="com.r8c.nfc_demo.NfcDemoActivity"  
            android:configChanges="orientation|keyboardHidden|screenSize"  
            android:label="@string/app_name"   
            android:launchMode="singleTask">  
            <intent-filter>  
                <action android:name="android.intent.action.MAIN" />  
  
                <category android:name="android.intent.category.LAUNCHER" />  
            </intent-filter>  
            <!-- TECH_DISCOVERED類型的nfc -->  
            <intent-filter>  
                <action android:name="android.nfc.action.TECH_DISCOVERED" />  
            </intent-filter>  
            <!-- 後設資源  調用自己建立的文件夾xml中的文件 -->  
            <meta-data  
                android:name="android.nfc.action.TECH_DISCOVERED"  
                android:resource="@xml/nfc_tech_filter" />  
        </activity>  
    </application>  
  
</manifest>  

它的Activity的內容如下,包括讀取、寫入、刪除三大功能:(其中刪除功能是通過寫入空值來實現的)

importjava.io.IOException;
importjava.io.UnsupportedEncodingException;
importjava.nio.charset.Charset;

importandroid.media.AudioManager;
importandroid.media.MediaPlayer;
importandroid.media.RingtoneManager;
importandroid.net.Uri;
importandroid.nfc.FormatException;
importandroid.nfc.NdefMessage;
importandroid.nfc.NdefRecord;
importandroid.nfc.NfcAdapter;
importandroid.nfc.Tag;
importandroid.nfc.tech.MifareUltralight;
importandroid.nfc.tech.Ndef;
importandroid.nfc.tech.NfcA;
importandroid.os.Bundle;
importandroid.app.Activity;
importandroid.app.PendingIntent;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.content.IntentFilter;
importandroid.graphics.Color;
importandroid.util.Log;
importandroid.view.Menu;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.widget.Button;
importandroid.widget.TextView;
importandroid.widget.Toast;

publicclassNfcDemoActivityextendsActivityimplementsOnClickListener{

//NFC適配器
privateNfcAdapternfcAdapter=null;
//傳達意圖
privatePendingIntentpi=null;
//濾掉組件無法響應和處理的Intent
privateIntentFiltertagDetected=null;
//文本控件
privateTextViewpromt=null;
//是否支持NFC功能的標簽
privatebooleanisNFC_support=false;
//讀、寫、刪按鈕控件
privateButtonreadBtn,writeBtn,deleteBtn;

@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_nfc_demo);
setupViews();
initNFCData();
}

@Override
protectedvoidonResume(){
super.onResume();
if(isNFC_support==false){
//如果設備不支持NFC或者NFC功能沒開啟,就return掉
return;
}
//開始監聽NFC設備是否連接
startNFC_Listener();

if(NfcAdapter.ACTION_TECH_DISCOVERED.equals(this.getIntent()
.getAction())){
//注意這個if中的代碼幾乎不會進來,因為剛剛在上一行代碼開啟了監聽NFC連接,下一行代碼馬上就收到了NFC連接的intent,這種幾率很小
//處理該intent
processIntent(this.getIntent());
}
}

@Override
protectedvoidonPause(){
super.onPause();
if(isNFC_support==true){
//當前Activity如果不在手機的最前端,就停止NFC設備連接的監聽
stopNFC_Listener();
}
}

@Override
protectedvoidonNewIntent(Intentintent){
super.onNewIntent(intent);
//當前app正在前端界面運行,這個時候有intent發送過來,那麼系統就會調用onNewIntent回調方法,將intent傳送過來
//我們只需要在這裡檢驗這個intent是否是NFC相關的intent,如果是,就調用處理方法
if(NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())){
processIntent(intent);
}
}

@Override
publicvoidonClick(Viewv){

//點擊讀按鈕後
if(v.getId()==R.id.read_btn){
try{
Stringcontent=read(tagFromIntent);
if(content!=null&&!content.equals("")){
promt.setText(promt.getText()+"nfc標簽內容:\n"+content
+"\n");
}else{
promt.setText(promt.getText()+"nfc標簽內容:\n"+"內容為空\n");
}
}catch(IOExceptione){
promt.setText(promt.getText()+"錯誤:"+e.getMessage()+"\n");
Log.e("myonclick","讀取nfc異常",e);
}catch(FormatExceptione){
promt.setText(promt.getText()+"錯誤:"+e.getMessage()+"\n");
Log.e("myonclick","讀取nfc異常",e);
}
//點擊寫後寫入
}elseif(v.getId()==R.id.write_btn){
try{
write(tagFromIntent);
}catch(IOExceptione){
promt.setText(promt.getText()+"錯誤:"+e.getMessage()+"\n");
Log.e("myonclick","寫nfc異常",e);
}catch(FormatExceptione){
promt.setText(promt.getText()+"錯誤:"+e.getMessage()+"\n");
Log.e("myonclick","寫nfc異常",e);
}
}elseif(v.getId()==R.id.delete_btn){
try{
delete(tagFromIntent);
}catch(IOExceptione){
promt.setText(promt.getText()+"錯誤:"+e.getMessage()+"\n");
Log.e("myonclick","刪除nfc異常",e);
}catch(FormatExceptione){
promt.setText(promt.getText()+"錯誤:"+e.getMessage()+"\n");
Log.e("myonclick","刪除nfc異常",e);
}
}
}

privatevoidsetupViews(){
//控件的綁定
promt=(TextView)findViewById(R.id.promt);
readBtn=(Button)findViewById(R.id.read_btn);
writeBtn=(Button)findViewById(R.id.write_btn);
deleteBtn=(Button)findViewById(R.id.delete_btn);
//給文本控件賦值初始文本
promt.setText("等待RFID標簽");
//監聽讀、寫、刪按鈕控件
readBtn.setOnClickListener(this);
writeBtn.setOnClickListener(this);
deleteBtn.setOnClickListener(this);
}

privatevoidinitNFCData(){
//初始化設備支持NFC功能
isNFC_support=true;
//得到默認nfc適配器
nfcAdapter=NfcAdapter.getDefaultAdapter(getApplicationContext());
//提示信息定義
StringmetaInfo="";
//判定設備是否支持NFC或啟動NFC
if(nfcAdapter==null){
metaInfo="設備不支持NFC!";
Toast.makeText(this,metaInfo,Toast.LENGTH_SHORT).show();
isNFC_support=false;
}
if(!nfcAdapter.isEnabled()){
metaInfo="請在系統設置中先啟用NFC功能!";
Toast.makeText(this,metaInfo,Toast.LENGTH_SHORT).show();
isNFC_support=false;
}

if(isNFC_support==true){
init_NFC();
}else{
promt.setTextColor(Color.RED);
promt.setText(metaInfo);
}
}

@Override
publicbooleanonCreateOptionsMenu(Menumenu){
//Inflatethemenu;thisaddsitemstotheactionbarifitispresent.
getMenuInflater().inflate(R.menu.nfc_demo,menu);
returntrue;
}

//字符序列轉換為16進制字符串
privateStringbytesToHexString(byte[]src){
returnbytesToHexString(src,true);
}

privateStringbytesToHexString(byte[]src,booleanisPrefix){
StringBuilderstringBuilder=newStringBuilder();
if(isPrefix==true){
stringBuilder.append("0x");
}
if(src==null||src.length<=0){
returnnull;
}
char[]buffer=newchar[2];
for(inti=0;i buffer[0]=Character.toUpperCase(Character.forDigit(
(src[i]>>>4)&0x0F,16));
buffer[1]=Character.toUpperCase(Character.forDigit(src[i]&0x0F,
16));
System.out.println(buffer);
stringBuilder.append(buffer);
}
returnstringBuilder.toString();
}

privateTagtagFromIntent;

/**
*ParsestheNDEFMessagefromtheintentandprintstotheTextView
*/
publicvoidprocessIntent(Intentintent){
if(isNFC_support==false)
return;

//取出封裝在intent中的TAG
tagFromIntent=intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);

promt.setTextColor(Color.BLUE);
StringmetaInfo="";
metaInfo+="卡片ID:"+bytesToHexString(tagFromIntent.getId())+"\n";
Toast.makeText(this,"找到卡片",Toast.LENGTH_SHORT).show();

//TechList
Stringprefix="android.nfc.tech.";
String[]techList=tagFromIntent.getTechList();

//分析NFC卡的類型:MifareClassic/UltraLightInfo
StringCardType="";
for(inti=0;i if(techList[i].equals(NfcA.class.getName())){
//讀取TAG
NfcAmfc=NfcA.get(tagFromIntent);
try{
if("".equals(CardType))
CardType="MifareClassic卡片類型\n不支持NDEF消息\n";
}catch(Exceptione){
e.printStackTrace();
}
}elseif(techList[i].equals(MifareUltralight.class.getName())){
MifareUltralightmifareUlTag=MifareUltralight
.get(tagFromIntent);
StringlightType="";
//TypeInfo
switch(mifareUlTag.getType()){
caseMifareUltralight.TYPE_ULTRALIGHT:
lightType="Ultralight";
break;
caseMifareUltralight.TYPE_ULTRALIGHT_C:
lightType="UltralightC";
break;
}
CardType=lightType+"卡片類型\n";

Ndefndef=Ndef.get(tagFromIntent);
CardType+="最大數據尺寸:"+ndef.getMaxSize()+"\n";

}
}
metaInfo+=CardType;
promt.setText(metaInfo);
}

//讀取方法
privateStringread(Tagtag)throwsIOException,FormatException{
if(tag!=null){
//解析Tag獲取到NDEF實例
Ndefndef=Ndef.get(tag);
//打開連接
ndef.connect();
//獲取NDEF消息
NdefMessagemessage=ndef.getNdefMessage();
//將消息轉換成字節數組
byte[]data=message.toByteArray();
//將字節數組轉換成字符串
Stringstr=newString(data,Charset.forName("UTF-8"));
//關閉連接
ndef.close();
returnstr;
}else{
Toast.makeText(NfcDemoActivity.this,"設備與nfc卡連接斷開,請重新連接...",
Toast.LENGTH_SHORT).show();
}
returnnull;
}

//寫入方法
privatevoidwrite(Tagtag)throwsIOException,FormatException{
if(tag!=null){
//新建NdefRecord數組,本例中數組只有一個元素
NdefRecord[]records={createRecord()};
//新建一個NdefMessage實例
NdefMessagemessage=newNdefMessage(records);
//解析TAG獲取到NDEF實例
Ndefndef=Ndef.get(tag);
//打開連接
ndef.connect();
//寫入NDEF信息
ndef.writeNdefMessage(message);
//關閉連接
ndef.close();
promt.setText(promt.getText()+"寫入數據成功!"+"\n");
}else{
Toast.makeText(NfcDemoActivity.this,"設備與nfc卡連接斷開,請重新連接...",
Toast.LENGTH_SHORT).show();
}
}

//刪除方法
privatevoiddelete(Tagtag)throwsIOException,FormatException{
if(tag!=null){
//新建一個裡面無任何信息的NdefRecord實例
NdefRecordnullNdefRecord=newNdefRecord(NdefRecord.TNF_MIME_MEDIA,
newbyte[]{},newbyte[]{},newbyte[]{});
NdefRecord[]records={nullNdefRecord};
NdefMessagemessage=newNdefMessage(records);
//解析TAG獲取到NDEF實例
Ndefndef=Ndef.get(tag);
//打開連接
ndef.connect();
//寫入信息
ndef.writeNdefMessage(message);
//關閉連接
ndef.close();
promt.setText(promt.getText()+"刪除數據成功!"+"\n");
}else{
Toast.makeText(NfcDemoActivity.this,"設備與nfc卡連接斷開,請重新連接...",
Toast.LENGTH_SHORT).show();
}
}

//返回一個NdefRecord實例
privateNdefRecordcreateRecord()throwsUnsupportedEncodingException{
//組裝字符串,准備好你要寫入的信息
Stringmsg="BEGIN:VCARD\n"+"VERSION:2.1\n"+"中國湖北省武漢市\n"
+"武漢大學計算機學院\n"+"END:VCARD";
//將字符串轉換成字節數組
byte[]textBytes=msg.getBytes();
//將字節數組封裝到一個NdefRecord實例中去
NdefRecordtextRecord=newNdefRecord(NdefRecord.TNF_MIME_MEDIA,
"text/x-vCard".getBytes(),newbyte[]{},textBytes);
returntextRecord;
}

privateMediaPlayerring()throwsException,IOException{
//TODOAuto-generatedmethodstub
Urialert=RingtoneManager
.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
MediaPlayerplayer=newMediaPlayer();
player.setDataSource(this,alert);
finalAudioManageraudioManager=(AudioManager)getSystemService(Context.AUDIO_SERVICE);
if(audioManager.getStreamVolume(AudioManager.STREAM_NOTIFICATION)!=0){
player.setAudioStreamType(AudioManager.STREAM_NOTIFICATION);
player.setLooping(false);
player.prepare();
player.start();
}
returnplayer;
}

privatevoidstartNFC_Listener(){
//開始監聽NFC設備是否連接,如果連接就發pi意圖
nfcAdapter.enableForegroundDispatch(this,pi,
newIntentFilter[]{tagDetected},null);
}

privatevoidstopNFC_Listener(){
//停止監聽NFC設備是否連接
nfcAdapter.disableForegroundDispatch(this);
}

privatevoidinit_NFC(){
//初始化PendingIntent,當有NFC設備連接上的時候,就交給當前Activity處理
pi=PendingIntent.getActivity(this,0,newIntent(this,getClass())
.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),0);
//新建IntentFilter,使用的是第二種的過濾機制
tagDetected=newIntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
tagDetected.addCategory(Intent.CATEGORY_DEFAULT);
}

}

 


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved