| page.title=Advanced NFC |
| @jd:body |
| |
| <div id="qv-wrapper"> |
| <div id="qv"> |
| <h2>In this document</h2> |
| <ol> |
| <li><a href="#tag-tech">Working with Supported Tag Technologies</a> |
| <ol> |
| <li><a href="#tech-intent">Working with tag technologies and the ACTION_TECH_DISCOVERED |
| intent</a></li> |
| <li><a href="#read-write">Reading and writing to tags</a></li> |
| </ol></li> |
| <li><a href="#foreground-dispatch">Using the Foreground Dispatch System</a></li> |
| </ol> |
| </div> |
| </div> |
| |
| <p>This document describes advanced NFC topics, such as working with various tag technologies, |
| writing to NFC tags, and foreground dispatching, which allows an application in the foreground to |
| handle intents even when other applications filter for the same ones.</p> |
| |
| <h2 id="tag-tech">Working with Supported Tag Technologies</h2> |
| <p>When working with NFC tags and Android-powered devices, the main format you use to read |
| and write data on tags is NDEF. When a device scans a tag with NDEF data, Android provides support |
| in parsing the message and delivering it in an {@link android.nfc.NdefMessage} when |
| possible. There are cases, however, when you scan a tag that does not contain |
| NDEF data or when the NDEF data could not be mapped to a MIME type or URI. |
| In these cases, you need to open communication directly with the tag and read and write to it with |
| your own protocol (in raw bytes). Android provides generic support for these use cases with the |
| {@link android.nfc.tech} package, which is described in <a href="#tech-table">Table 1</a>. You can |
| use the {@link android.nfc.Tag#getTechList getTechList()} method to determine the technologies |
| supported by the tag and create the corresponding {@link android.nfc.tech.TagTechnology} |
| object with one of classes provided by {@link android.nfc.tech} </p> |
| |
| <p class="table-caption" id="table1"> |
| <strong>Table 1.</strong> Supported tag technologies</p> |
| <table id="tech-table"> |
| |
| <tr> |
| <th>Class</th> |
| |
| <th>Description</th> |
| </tr> |
| |
| <tr> |
| <td>{@link android.nfc.tech.TagTechnology}</td> |
| |
| <td>The interface that all tag technology classes must implement.</td> |
| </tr> |
| |
| <tr> |
| <td>{@link android.nfc.tech.NfcA}</td> |
| |
| <td>Provides access to NFC-A (ISO 14443-3A) properties and I/O operations.</td> |
| </tr> |
| |
| <tr> |
| <td>{@link android.nfc.tech.NfcB}</td> |
| |
| <td>Provides access to NFC-B (ISO 14443-3B) properties and I/O operations.</td> |
| </tr> |
| |
| <tr> |
| <td>{@link android.nfc.tech.NfcF}</td> |
| |
| <td>Provides access to NFC-F (JIS 6319-4) properties and I/O operations.</td> |
| </tr> |
| |
| <tr> |
| <td>{@link android.nfc.tech.NfcV}</td> |
| |
| <td>Provides access to NFC-V (ISO 15693) properties and I/O operations.</td> |
| </tr> |
| |
| <tr> |
| <td>{@link android.nfc.tech.IsoDep}</td> |
| |
| <td>Provides access to ISO-DEP (ISO 14443-4) properties and I/O operations.</td> |
| </tr> |
| |
| <tr> |
| <td>{@link android.nfc.tech.Ndef}</td> |
| |
| <td>Provides access to NDEF data and operations on NFC tags that have been formatted as |
| NDEF.</td> |
| </tr> |
| |
| <tr> |
| <td>{@link android.nfc.tech.NdefFormatable}</td> |
| |
| <td>Provides a format operations for tags that may be NDEF formattable.</td> |
| </tr> |
| </table> |
| <p>The following tag technlogies are not required to be supported by Android-powered devices.</p> |
| <p class="table-caption" id="table2"> |
| <strong>Table 2.</strong> Optional supported tag technologies</p> |
| <table> |
| <tr> |
| <th>Class</th> |
| |
| <th>Description</th> |
| </tr> |
| <tr> |
| <td>{@link android.nfc.tech.MifareClassic}</td> |
| |
| <td>Provides access to MIFARE Classic properties and I/O operations, if this Android device |
| supports MIFARE.</td> |
| </tr> |
| |
| <tr> |
| <td>{@link android.nfc.tech.MifareUltralight}</td> |
| |
| <td>Provides access to MIFARE Ultralight properties and I/O operations, if this Android |
| device supports MIFARE.</td> |
| </tr> |
| </table> |
| |
| <h3 id="tech-intent">Working with tag technologies and the ACTION_TECH_DISCOVERED intent</h3> |
| <p>When a device scans a tag that has NDEF data on it, but could not be mapped to a MIME or URI, |
| the tag dispatch system tries to start an activity with the {@link |
| android.nfc.NfcAdapter#ACTION_TECH_DISCOVERED} |
| intent. The {@link android.nfc.NfcAdapter#ACTION_TECH_DISCOVERED} is also used when a tag |
| with non-NDEF data is scanned. Having this fallback allows you to work with the data on the tag |
| directly if the tag dispatch system could not parse it for you. The basic steps when working with |
| tag technologies are as follows:</p> |
| |
| <ol> |
| <li>Filter for an {@link android.nfc.NfcAdapter#ACTION_TECH_DISCOVERED} intent specifying the |
| tag technologies that you want to handle. See <a |
| href="{@docRoot}guide/topics/connectivity/nfc/nfc.html#tech-disc">Filtering for NFC |
| intents</a> for more information. In general, the tag dispatch system tries to start a {@link |
| android.nfc.NfcAdapter#ACTION_TECH_DISCOVERED} intent when an NDEF message |
| cannot be mapped to a MIME type or URI, or if the tag scanned did not contain NDEF data. For |
| more information on how this is determined, see <a |
| href="{@docRoot}guide/topics/connectivity/nfc/nfc.html#tag-dispatch">The Tag Dispatch System</a>.</li> |
| <li>When your application receives the intent, obtain the {@link android.nfc.Tag} object from |
| the intent: |
| <pre>Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);</pre></li> |
| <li>Obtain an instance of a {@link android.nfc.tech.TagTechnology}, by calling one of the |
| <code>get</code> factory methods of the classes in the {@link android.nfc.tech} package. You can |
| enumerate the supported technologies of the tag by calling {@link android.nfc.Tag#getTechList |
| getTechList()} before calling a <code>get</code> factory method. For example, to obtain an instance |
| of {@link android.nfc.tech.MifareUltralight} from a {@link android.nfc.Tag}, do the following: |
| |
| <pre> |
| MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)); |
| </pre> |
| </li> |
| </ol> |
| |
| |
| |
| <h3 id="read-write">Reading and writing to tags</h3> |
| |
| <p>Reading and writing to an NFC tag involves obtaining the tag from the intent and |
| opening communication with the tag. You must define your own protocol stack to read and write data |
| to the tag. Keep in mind, however, that you can still read and write NDEF data when working |
| directly with a tag. It is up to you how you want to structure things. The |
| following example shows how to work with a MIFARE Ultralight tag.</p> |
| |
| <pre> |
| package com.example.android.nfc; |
| |
| import android.nfc.Tag; |
| import android.nfc.tech.MifareUltralight; |
| import android.util.Log; |
| import java.io.IOException; |
| import java.nio.charset.Charset; |
| |
| public class MifareUltralightTagTester { |
| |
| private static final String TAG = MifareUltralightTagTester.class.getSimpleName(); |
| |
| public void writeTag(Tag tag, String tagText) { |
| MifareUltralight ultralight = MifareUltralight.get(tag); |
| try { |
| ultralight.connect(); |
| ultralight.writePage(4, "abcd".getBytes(Charset.forName("US-ASCII"))); |
| ultralight.writePage(5, "efgh".getBytes(Charset.forName("US-ASCII"))); |
| ultralight.writePage(6, "ijkl".getBytes(Charset.forName("US-ASCII"))); |
| ultralight.writePage(7, "mnop".getBytes(Charset.forName("US-ASCII"))); |
| } catch (IOException e) { |
| Log.e(TAG, "IOException while closing MifareUltralight...", e); |
| } finally { |
| try { |
| ultralight.close(); |
| } catch (IOException e) { |
| Log.e(TAG, "IOException while closing MifareUltralight...", e); |
| } |
| } |
| } |
| |
| public String readTag(Tag tag) { |
| MifareUltralight mifare = MifareUltralight.get(tag); |
| try { |
| mifare.connect(); |
| byte[] payload = mifare.readPages(4); |
| return new String(payload, Charset.forName("US-ASCII")); |
| } catch (IOException e) { |
| Log.e(TAG, "IOException while writing MifareUltralight |
| message...", e); |
| } finally { |
| if (mifare != null) { |
| try { |
| mifare.close(); |
| } |
| catch (IOException e) { |
| Log.e(TAG, "Error closing tag...", e); |
| } |
| } |
| } |
| return null; |
| } |
| } |
| </pre> |
| |
| </pre> |
| |
| <h2 id="foreground-dispatch">Using the Foreground Dispatch System</h2> |
| |
| <p>The foreground dispatch system allows an activity to intercept an intent and claim |
| priority over other activities that handle the same intent. Using this system involves |
| constructing a few data structures for the Android system to be able to send the appropriate |
| intents to your application. To enable the foreground dispatch system:</p> |
| |
| <ol> |
| <li>Add the following code in the <code>onCreate()</code> method of your activity: |
| |
| <ol> |
| <li>Create a {@link android.app.PendingIntent} object so the Android system can populate it |
| with the details of the tag when it is scanned. |
| <pre> |
| PendingIntent pendingIntent = PendingIntent.getActivity( |
| this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0); |
| </pre> |
| </li> |
| |
| <li>Declare intent filters to handle the intents that you want to intercept. The foreground |
| dispatch system checks the specified intent filters with the intent that is received when |
| the device scans a tag. If it matches, then your application handles the intent. If it does |
| not match, the foreground dispatch system falls back to the intent dispatch system. |
| Specifying a <code>null</code> array of intent filters and technology filters, specifies |
| that you want to filter for all tags that fallback to the <code>TAG_DISCOVERED</code> |
| intent. The code snippet below handles all MIME types for <code>NDEF_DISCOVERED</code>. You |
| should only handle the ones that you need. |
| <pre> |
| IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED); |
| try { |
| ndef.addDataType("*/*"); /* Handles all MIME based dispatches. |
| You should specify only the ones that you need. */ |
| } |
| catch (MalformedMimeTypeException e) { |
| throw new RuntimeException("fail", e); |
| } |
| intentFiltersArray = new IntentFilter[] {ndef, }; |
| </pre> |
| </li> |
| |
| <li>Set up an array of tag technologies that your application wants to handle. Call the |
| <code>Object.class.getName()</code> method to obtain the class of the technology that you |
| want to support. |
| <pre> |
| techListsArray = new String[][] { new String[] { NfcF.class.getName() } }; |
| </pre> |
| </li> |
| </ol> |
| </li> |
| |
| <li>Override the following activity lifecycle callbacks and add logic to enable and disable the |
| foreground dispatch when the activity loses ({@link android.app.Activity#onPause onPause()}) |
| and regains ({@link android.app.Activity#onResume onResume()}) focus. {@link |
| android.nfc.NfcAdapter#enableForegroundDispatch enableForegroundDispatch()} must be called from |
| the main thread and only when the activity is in the foreground (calling in {@link |
| android.app.Activity#onResume onResume()} guarantees this). You also need to implement the {@link |
| android.app.Activity#onNewIntent onNewIntent} callback to process the data from the scanned NFC |
| tag.</li> |
| |
| <pre> |
| public void onPause() { |
| super.onPause(); |
| mAdapter.disableForegroundDispatch(this); |
| } |
| |
| public void onResume() { |
| super.onResume(); |
| mAdapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray); |
| } |
| |
| public void onNewIntent(Intent intent) { |
| Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); |
| //do something with tagFromIntent |
| } |
| </pre> |
| </li> |
| </ol> |
| |
| <p>See the <a href= |
| "{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/nfc/ForegroundDispatch.html"> |
| ForegroundDispatch</a> sample from API Demos for the complete sample.</p> |