本文描述瞭如何在安卓中使用 NFC (近場通訊)。NFC 科技代表近場通訊,你可以在 NFC 論壇上找到 NFC 的詳細資訊。在本文中,我們將分析 NFC 的一些基礎知識,並且我們還將描述如何在安卓系統中實現一個利用 NFC 的 APP(應用程式)。
如果你想做 NFC 實驗,那麼你在幾個網站上花費幾歐元就能買到 NFC 。
NFC 可以用於不同的情景:在家中時,我們可以使用它來開啟 WiFi 或者執行一些任務操作等等。
本文中,我們將注意力集中在 NDEF 資料,它是一種特殊型別的 NFC 標記。不過,在使用 NFC 之前,我們必須遵循一些基本步驟。
NFC 過濾器
當我們使用 NFC 標記時,我們要做的第一件事就是,當我們接近一個 NFC 標記的時候,我們的 APP 可以收到通知。為了實現這個目的,我們需要使用一個意圖過濾器。安卓 SDK 中提供了三種不同的過濾器,我們可以以不同的優先順序來使用它們:
- ACTION_NDEF_DISCOVERED
- ACTION_TECH_DISCOVERED
- ACTION_TAG_DISCOVERED
我們重點關注 ACTION_NDEF_DISCOVERED,它擁有最高的優先順序。正如前面所說的,我們的目的是,當智慧手機接近一個 NFC 標記時能夠收到通知,並且如果我們只安裝了這一個 APP,並且它能夠處理這個 NFC 標記,那麼我們希望該 APP 能夠立即開始處理。為了實現這一點,我們在 Manifest.xml 中註冊過濾器:
1 2 3 4 5 6 7 8 9 10 |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.survivingwithandroid.nfc" > .... <intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain"/> </intent-filter> <manifest> |
在第 6 行,我們註冊了 APP,以使得它可以收到 ACTION_NDEF_DISCOVERED 通知。我們使用不同型別的過濾器,在這個例子中(第 8 行)我們使用了 mine 型別。換句話說,當發現一個 NFC 標記 NDEF 並且它的 mine 型別為“text/plain”時,我們的 APP 將會啟動。其實,我們可以使用幾種 mine 型別來過濾,而不僅僅是 text/plain。此外,我們還能以協議或一個字串模式來使用其他型別的過濾器(如 android:scheme)來過濾。
NFC 前臺排程
如果我們的 APP 沒處於前臺,就會開始意圖過濾。如果我們的應用程式執行在前臺,那麼當我們的智慧手機移動到一個 NFC 標記時,它將不會收到通知。在這種情況下,我們必須使用一種稱為NFC前臺排程的技術。第一步是,在我們的程式碼中定義意圖過濾器(正如我們在 Manifest.xml 中做的那樣):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@Override protected void onCreate(Bundle savedInstanceState) { ... Intent nfcIntent = new Intent(this, getClass()); nfcIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); nfcPendingIntent = PendingIntent.getActivity(this, 0, nfcIntent, 0); IntentFilter tagIntentFilter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED); try { tagIntentFilter.addDataType("text/plain"); intentFiltersArray = new IntentFilter[]{tagIntentFilter}; } catch (Throwable t) { t.printStackTrace(); } } |
現在,我們必須註冊我們的過濾器,在 onResume 方法中以這種方式實現它:
1 2 3 4 5 6 7 8 9 |
protected void onResume() { super.onResume(); nfcAdpt.enableForegroundDispatch( this, nfcPendingIntent, intentFiltersArray, null); handleIntent(getIntent()); } |
此外,也應該記住,只要 APP 退回到後臺,我們就應該關閉前臺排程,而要實現這一點,最好的地方是在 onPause 方法中。
1 2 3 4 5 |
@Override protected void onPause() { super.onPause(); nfcAdpt.disableForegroundDispatch(this); } |
其中,nfcAdpt 是 NFC 介面卡。
使用 NFCAdapter 處理 NFC
一旦我們建立了過濾器,我們必須與智慧手機中的 NFC 元件互動。為此,我們使用安卓 SDK 提供的 NfcAdapter。使用這個類,我們能夠檢測智慧手機是否支援 NFC,或者 NFC 功能是否開啟或關閉。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Override protected void onCreate(Bundle savedInstanceState) { ... nfcAdpt = NfcAdapter.getDefaultAdapter(this); // Check if the smartphone has NFC if (nfcAdpt == null) { Toast.makeText(this, "NFC not supported", Toast.LENGTH_LONG).show(); finish(); } // Check if NFC is enabled if (!nfcAdpt.isEnabled()) { Toast.makeText(this, "Enable NFC before using the app", Toast.LENGTH_LONG).show(); } } |
NFC 資料:負載
既然我們知道了如何處理 NFC 標記,接著我們就想讀取標記內容。在 NFC 說明文件中,定義了幾種型別的內容:
- NFC Forum well-known type
- Media-type
- Absolute URI
- NFC Forum external type
每種型別都有它自己的有效負載。一般來說,一個 NFC NDEF 資料由一條資訊組成,一條資訊可以包含一個或多個記錄,每個記錄由一個頭和一個負載(真正的資訊)組成。現在,如果我們想讀取 NFC NDEF 標記中的資料,我們可以使用下面的程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
@Override public void onNewIntent(Intent intent) { Log.d("Nfc", "New intent"); getTag(intent); } private void getTag(Intent i) { if (i == null) return ; String type = i.getType(); String action = i.getAction(); List dataList = new ArrayList(); if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) { Log.d("Nfc", "Action NDEF Found"); Parcelable[] parcs = i.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); for (Parcelable p : parcs) { recNumberTxt.setText(String.valueOf(numRec)); NdefRecord[] records = msg.getRecords(); for (NdefRecord record: records) { short tnf = record.getTnf(); // Here we handle the payload } } } } |