Android 2.3 (API Level 9) — Basics
Android 2.3.3 (API Level 10) — NDEF - NFC Data Exchange Format
Android 4.0 (API Level 14) — "Android Beam"
Eigenschaften
Geräte
Use-Cases
NDEF — NFC Data Exchange Format
AndroidManifest.xml
<uses-sdk android:targetSdkVersion="9|10|14" />
...
<uses-permission android:name="android.permission.NFC" />
...
<uses-feature android:name="android.hardware.nfc"
android:required="true|false" />
NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
NfcAdapter adapter = manager.getDefaultAdapter();
if (adapter != null && adapter.isEnabled()) {
...
}
Rückwärtskompatibel:
Object manager = context.getSystemService(Context.NFC_SERVICE);
if (manager != null) {
NfcTools.publish(nfcManager, ...);
}
class NfcTools {
public static void publish(Object nfcManager, ...) {
NfcAdapter adapter = ((NfcManager) nfcManager).getDefaultAdapter();
if (adapter != null && adapter.isEnabled()) {
...
}
}
}
Tag mit NDEF Message beschreiben
protected void onResume() {
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter intentFilter = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
adapter.enableForegroundDispatch(this, pendingIntent, new IntentFilter[] { intentFilter }, null);
...
}
protected void onPause() {
adapter.disableForegroundDispatch(this);
...
}
public void onNewIntent(Intent intent) {
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
Ndef ndef = Ndef.get(tag);
NdefRecord record = uriRecord("http://schildbach.de/talks/nfc/");
NdefMessage message = new NdefMessage(new NdefRecord[] { record });
ndef.connect();
// ndef.getMaxSize();
ndef.writeNdefMessage(message);
// ndef.makeReadOnly();
ndef.close();
}
private NdefRecord uriRecord(String uri) {
final byte[] uriBytes = uri.getBytes(UTF_8);
final byte[] recordBytes = new byte[uriBytes.length + 1];
recordBytes[0] = (byte) 0x0;
System.arraycopy(uriBytes, 0, recordBytes, 1, uriBytes.length);
return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], recordBytes);
}
private NdefRecord mimeRecord(String mimeType, byte[] payload) {
final byte[] mimeBytes = mimeType.getBytes(US_ASCII);
return new NdefRecord(NdefRecord.TNF_MIME_MEDIA, mimeBytes, new byte[0], payload);
}
Android 4+:
NdefRecord.createUri(String uri)
NDEF Message von Tag lesen
protected void onResume() {
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter intentFilter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
intentFilter.addDataScheme("http");
adapter.enableForegroundDispatch(this, pendingIntent, new IntentFilter[] { intentFilter }, null);
...
}
protected void onPause() {
adapter.disableForegroundDispatch(this);
...
}
public void onNewIntent(Intent intent) {
Uri uri = intent.getData();
...
}
Intent Dispatch
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<data android:scheme="bitcoin" /> oder
<data android:mimeType="text/x-vcard" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
protected void onCreate(Bundle savedInstanceState) {
handleIntent(getIntent());
...
}
protected void onNewIntent(Intent intent) {
handleIntent(intent);
}
private void handleIntent(Intent intent) {
Uri data = intent.getData();
if (data != null && "bitcoin".equals(data.getScheme())) {
...
}
}
Funktioniert ohne Permission!
NDEF Push / Tag emulation
protected void onResume() {
NdefRecord record = uriRecord("http://schildbach.de/talks/nfc/");
NdefMessage message = new NdefMessage(new NdefRecord[] { record });
adapter.enableForegroundNdefPush(Activity.this, message);
...
}
protected void onPause() {
adapter.disableForegroundNdefPush(Activity.this);
...
}
Variante mit Lifecycle-Management (Android 4+):
protected void onCreate() {
NdefRecord record = NdefRecord.createUri("http://schildbach.de/talks/nfc/");
NdefMessage message = new NdefMessage(new NdefRecord[] { record });
adapter.setNdefPushMessage(message, Activity.this);
...
}
Message dynamisch erstellen (Android 4+):
protected void onCreate() {
CreateNdefMessageCallback callback = new CreateNdefMessageCallback() {
public NdefMessage createNdefMessage(NfcEvent event) {
NdefRecord record = NdefRecord.createUri("http://schildbach.de/talks/nfc/");
return new NdefMessage(new NdefRecord[] { record });
}
};
adapter.setNdefPushMessageCallback(callback, Activity.this);
}
Außerdem Android 4+: adapter.setOnNdefPushCompleteCallback(callback, Activity.this);
Android Application Record
Android 4+:
NdefRecord record = NdefRecord.createUri("bitcoin:1CX6NdhkSiyYvsauTr2HUgeyuaEqJAN6st");
NdefRecord appRecord = NdefRecord.createApplicationRecord("de.schildbach.wallet");
NdefMessage message = new NdefMessage(new NdefRecord[] { record, appRecord });
Rückwärtskompatibel:
NdefRecord record = uriRecord("bitcoin:1CX6NdhkSiyYvsauTr2HUgeyuaEqJAN6st");
final byte[] RTD_ANDROID_APP = "android.com:pkg".getBytes(US_ASCII);
NdefRecord appRecord = new NdefRecord(NdefRecord.TNF_EXTERNAL_TYPE,
RTD_ANDROID_APP, new byte[0], "de.schildbach.wallet".getBytes(US_ASCII));
NdefMessage message = new NdefMessage(new NdefRecord[] { record, appRecord });
Achtung: Application Records stehen offenem App-Ökosystem entgegen!
Low Level
<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" />
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<tech-list>
<tech>android.nfc.tech.MifareClassic</tech>
</tech-list>
</resources>
MifareClassic mifare = MifareClassic.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG));
mifare.connect();
mifare.authenticateSectorWithKeyA(...);
mifare.readBlock(...);
mifare.writeBlock(...);
mifare.close();
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<tech-list>
<tech>android.nfc.tech.IsoDep</tech>
</tech-list>
</resources>
IsoDep isodep = IsoDep.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG));
isodep.connect();
byte[] request = new byte[] { ... };
byte[] response = isodep.transceive(request);
isodep.close();
Vortragsfolien — http://schildbach.de/talks/nfc/
Weitere Infos:
NFC Spezifikationen — http://www.nfc-forum.org/specs/spec_list/
NFC im Android Dev Guide — http://developer.android.com/guide/topics/nfc/index.html
Android Beam Demo — http://developer.android.com/resources/samples/AndroidBeamDemo/index.html
Q & A