好吊视频一区二区三区-国产精品V欧美精品V日韩精品-老司机亚洲精品影院-国产精品视频免费播放

物聯傳媒 旗下網站
登錄 注冊
RFID世界網 >  新聞中心  >  行業動態  >  正文

什么是NFC近場通信

作者:老歐
來源:公眾號/老歐說安卓
日期:2018-02-22 09:32:01
摘要:帶有NFC功能的手機,在實際生活中主要有三項應用:讀卡、寫卡、分享內容(兩部手機之間傳輸數據)。為了能更迅速地了解NFC技術在Android中的開發流程,下面通過相對簡單的讀卡功能,來介紹如何進行手機App的NFC開發。
關鍵詞:NFCRFID通信

  NFC的全稱是“Near Field Communication”,意思是近場通信、與鄰近的區域通信。大眾所熟知的NFC技術應用,主要是智能手機的刷卡支付功能。別看智能手機是近十年前才出現的,NFC的歷史可比智能手機要悠久得多,它脫胎于上世紀的RFID無線射頻識別技術。

  所謂RFID是“Radio Frequency Identification”的縮寫,它通過無線電信號便可識別特定目標并讀寫數據,而無需自身與該目標之間建立任何機械或者光學接觸。像日常生活中的門禁卡、公交卡,乃至二代身份證,都是采用了RFID技術的卡片。若想讀寫這些RFID卡片,則需相應的讀卡器,只要用戶把卡片靠近,讀卡器就會產生感應動作。

  既然RFID已經廣泛使用,那么何苦又要另外制定NFC標準呢?其實正是因為RFID用的地方太多了,導致隨意性較大,反而不便于更好地管控。所以業界重新定義了NFC規范,試圖在兩個方面彌補RFID的固有缺憾:

  1、RFID的信號傳播距離較遠,致使位于遠處的設備也可能獲取卡片信息,這對安全性較高的場合是不可接受的。而NFC的有效工作距離在十厘米之內,即可避免卡片信息被竊取的風險。

  2、RFID的讀寫操作是單向的,也就是說,只有讀卡器能讀寫卡片,卡片不能拿讀卡器怎么樣。現在NFC不再沿用“讀卡器——卡片”的模式,取而代之的是只有NFC設備的概念,兩個NFC設備允許互相讀寫,既可以由設備A讀寫設備B,也可以由設備B讀寫設備A。

  改進之后的NFC技術既提高了安全性,又拓寬了應用場合,同時還兼容現有的大部分RFID卡片,因此在智能手機上運用NFC而非RFID也就不足為怪了。

  帶有NFC功能的手機,在實際生活中主要有三項應用:讀卡、寫卡、分享內容(兩部手機之間傳輸數據)。為了能更迅速地了解NFC技術在Android中的開發流程,下面通過相對簡單的讀卡功能,來介紹如何進行手機App的NFC開發。

  首先App工程要在AndroidManifest.xml中聲明NFC的操作權限,下面是配置聲明的例子:

  <!--NFC-->

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

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

  其次還要對活動頁面聲明NFC過濾器,目前Android支持NDEF_DISCOVERED、TAG_DISCOVERED、TECH_DISCOVERED這三種過濾器,最好把它們都加入到過濾器列表中,示例如下:

  <activity android:name=".NfcActivity">

  <intent-filter>

  <action android:name="android.nfc.action.NDEF_DISCOVERED"/>

  </intent-filter>

  <intent-filter>

  <action android:name="android.nfc.action.TAG_DISCOVERED"/>

  <category android:name="android.intent.category.DEFAULT"/>

  </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>

  其中TECH_DISCOVERED類型另外指定了過濾器的來源是 xml/nfc_tech_filter,該文件的實際路徑為xml/nfc_tech_filter.xml,文件內容如下所示:

  <resources>

  <!--可以處理所有Android支持的NFC類型-->

  <tech-list>

  <tech>android.nfc.tech.NfcA</tech>

  <tech>android.nfc.tech.NfcB</tech>

  <tech>android.nfc.tech.NfcF</tech>

  <tech>android.nfc.tech.NfcV</tech>

  <tech>android.nfc.tech.IsoDep</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>

  上面的過濾器列表乍看過去真是令人大吃一驚,這都是些什么東東,它們之間有哪些區別呢?倘若認真對這幾個專業術語追根溯源,勢必要一番長篇大論才能理清其中的歷史脈絡,因此不妨將事情簡單化,這些NFC類型只不過是一個大家族內部的兄弟姐妹罷了。譬如說中國近代史上顯赫的宋氏三姐妹,原是同一對父母,然后分別嫁給三個人罷了。NFC類型雖多,常見的NfcA、NfcB、IsoDep三個系出ISO14443標準(即RFID卡標準),它們仨各自用于生活中的幾種場合,說明如下:

  1、NfcA遵循ISO14443-3A標準,常用于門禁卡;

  2、NfcB遵循ISO14443-3B標準,常用于二代身份證;

  3、IsoDep遵循ISO14443-4標準,常用于公交卡;

  好不容易把AndroidManifest.xml的相關配置弄完,接著便是代碼方面的處理邏輯了。NFC編碼主要有三個步驟:初始化適配器、啟用感應/禁用感應、接收到感應消息并對消息解碼,下面分別進行介紹:

  一、初始化NFC適配器

  這里的初始化動作又可分解為三部分:

  1、調用NfcAdapter類的getDefaultAdapter方法,獲取系統當前默認的NFC適配器。

  2、聲明一個延遲意圖,告訴系統一旦接收到NFC感應,則應當啟動哪個頁面進行處理。

  3、定義一個NFC消息的過濾器,這個過濾器是AndroidManifest.xml所配置過濾器的子集。因為接下來要讀取的卡片兼容RFID標準(ISO14443家族),所以過濾器的動作名稱為NfcAdapter.ACTION_TECH_DISCOVERED,并且設置該動作包含了兩項卡片標準,分別是NfcA(用于門禁卡)和IsoDep(用于公交卡)。

  詳細的NFC初始化代碼示例如下:

  private void initNfc(){

  //獲取默認的NFC適配器

  nfcAdapter=NfcAdapter.getDefaultAdapter(this);

  if(nfcAdapter==null){

  tv_nfc_result.setText("當前手機不支持NFC");

  return;

  }else if(!nfcAdapter.isEnabled()){

  tv_nfc_result.setText("請先在系統設置中啟用NFC功能");

  return;

  }

  //探測到NFC卡片后,必須以FLAG_ACTIVITY_SINGLE_TOP方式啟動Activity,

  //或者在AndroidManifest.xml中設置launchMode屬性為singleTop或者singleTask,

  //保證無論NFC標簽靠近手機多少次,Activity實例都只有一個。

  Intent intent=new Intent(this,NfcActivity.class).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

  //聲明一個NFC卡片探測事件的相應動作

  mPendingIntent=PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);

  try{

  //定義一個過濾器(檢測到NFC卡片)

  mFilters=new IntentFilter[]{new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED,"*/*")};

  }catch(Exception e){

  e.printStackTrace();

  }

  //讀標簽之前先確定標簽類型

  mTechLists=new String[][]{new String[]{NfcA.class.getName()},{IsoDep.class.getName()}};

  }

  二、啟用NFC感應/禁用NFC感應

  為了讓測試App能夠接收NFC的感應動作,需要重載Activity的onResume函數,在該函數中調用NFC適配器的enableForegroundDispatch方法,指定啟用NFC功能時的響應動作以及過濾條件。另外也需重載onPause函數,在該函數中調用NFC適配器的disableForegroundDispatch方法,表示當前頁面在暫停狀態之時不再接收NFC感應消息。具體的NFC啟用和禁用代碼如下所示:

   Override

  protected void onResume(){

  super.onResume();

  if(nfcAdapter!=null&&nfcAdapter.isEnabled()){

  //為本App啟用NFC感應

  nfcAdapter.enableForegroundDispatch(this,mPendingIntent,mFilters,mTechLists);

  }

  }

   Override

  public void onPause(){

  super.onPause();

  if(nfcAdapter!=null&&nfcAdapter.isEnabled()){

  //禁用本App的NFC感應

  nfcAdapter.disableForegroundDispatch(this);

  }

  }

  三、接收到感應消息并對消息解碼

  通過前面的第二步啟用NFC感應之后,一旦App接收到感應消息,就會回調Activity的onNewIntent函數,因此開發者可以重寫該函數來處理NFC的消息內容。以NFC技術常見的小區門禁卡為例,門禁卡采取的子標準為NfcA,對應的數據格式則為MifareClassic。于是利用MifareClassic類的相關方法即可獲取卡片數據,下面是MifareClassic類的方法說明:

  get:從Tag對象中獲取卡片對象的信息。該方法為靜態方法。

  connect:連接卡片數據。

  close:釋放卡片數據。

  getType:獲取卡片的類型。TYPE_CLASSIC表示傳統類型,TYPE_PLUS表示增強類型,TYPE_PRO表示專業類型。

  getSectorCount:獲取卡片的扇區數量。

  getBlockCount:獲取卡片的分塊個數。

  getSize:獲取卡片的存儲空間大小,單位字節。

  使用MifareClassic工具查詢卡片數據的流程很常規,先調用connect方法建立連接,然后調用各個get方法獲取詳細信息,最后調用close方法關閉連接。具體的門禁卡讀取代碼示例如下:

   Override

  protected void onNewIntent(Intent intent){

  super.onNewIntent(intent);

  String card_info="";

  String action=intent.getAction();//獲取到本次啟動的action

  if(action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED)//NDEF類型

  ||action.equals(NfcAdapter.ACTION_TECH_DISCOVERED)//其他類型

  ||action.equals(NfcAdapter.ACTION_TAG_DISCOVERED)){//未知類型

  //從intent中讀取NFC卡片內容

  Tag tag=intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);

  //獲取NFC卡片的序列號

  byte[]ids=tag.getId();

  card_info=String.format("卡片的序列號為:%s",ByteArrayChange.ByteArrayToHexString(ids));

  if(rb_guard_card.isChecked()){

  String result=readGuardCard(tag);

  card_info=String.format("%s\n詳細信息如下:\n%s",card_info,result);

  tv_nfc_result.setText(card_info);

  }

  }

  }

  //讀取小區門禁卡信息

  public String readGuardCard(Tag tag){

  MifareClassic classic=MifareClassic.get(tag);

  String info;

  try{

  classic.connect();//連接卡片數據

  int type=classic.getType();//獲取TAG的類型

  String typeDesc;

  if(type==MifareClassic.TYPE_CLASSIC){

  typeDesc="傳統類型";

  }else if(type==MifareClassic.TYPE_PLUS){

  typeDesc="增強類型";

  }else if(type==MifareClassic.TYPE_PRO){

  typeDesc="專業類型";

  }else{

  typeDesc="未知類型";

  }

  info=String.format("\t卡片類型:%s\n\t扇區數量:%d\n\t分塊個數:%d\n\t存儲空間:%d字節",

  typeDesc,classic.getSectorCount(),classic.getBlockCount(),classic.getSize());

  }catch(Exception e){

  e.printStackTrace();

  info=e.getMessage();

  }finally{//無論是否發生異常,都要釋放資源

  try{

  classic.close();//釋放卡片數據

  }catch(Exception e){

  e.printStackTrace();

  info=e.getMessage();

  }

  }

  return info;

  }

  編碼完畢,找一臺支持NFC的手機安裝測試App,啟動應用前注意開啟手機的NFC功能。然后進入App的測試頁面,拿一張門禁卡靠近手機背面(門禁卡不一定是卡片,也可能是鑰匙扣模樣),稍等片刻便會讀取并顯示門禁卡的基本信息,卡片信息截圖如下所示: