300 lines
12 KiB
Plaintext
300 lines
12 KiB
Plaintext
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/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/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> |