Skip to content

NDEF tag

Getting Started

Let's start in your AndroidManifest.xml file. In here there are a few things that need to be set up. First, add the permission's declaration for using NFC hardware.

<!-- Your application request the NFC permission to access the NFC hardware -->
<uses-permission android:name="android.permission.NFC" />

Following this, make sure that users using our app, have NFC on their device. For this, add a uses-feature tag on the manifest file.

<!-- Your application shows up in Google Play only for devices that have NFC hardware -->
<uses-feature android:name="android.hardware.nfc" android:required="true" />

Lastly, create an intent-filter under the activity tag that needs to be notified of NDEF tag discoveries. Specify this intent-filter, with an action, a category, and a data tag as seen below. For the example, we will only read/write text/plain MIME type.

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:mimeType="text/plain" />
</intent-filter>

Lastly, you need to override onNewIntent() method so your activity can receive the intent when discovering an NDEF tag.

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    // Either read or write an NDEF (NFC Data Exchange Format) tag here

Reading an NDEF tag

The first thing to do is to check the action of the intent you received. Then, the NdefMessage array is fetch as a Parcelable array. The next step is to extract all the NdefRecord objects from the NdefMessage. Finally, the byte array is converted into a String to obtain the payload of the NdefRecord.

private void readNdef(Intent intent) {
    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
        final Parcelable[] rawMessages =
                intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
        if (rawMessages != null) {
            final NdefMessage[] messages = new NdefMessage[rawMessages.length];
            // NDEF data is encapsulated inside an NdefMessage that contains one or more
            // NdefRecord
            for (int i = 0; i < rawMessages.length; i++) {
                messages[i] = (NdefMessage) rawMessages[i];
                for (NdefRecord ndefRecord : messages[i].getRecords()) {
                    final String message =
                            new String(ndefRecord.getPayload(), StandardCharsets.UTF_8)
                                    .substring(TNF_LENGTH);
                    Toast.makeText(MainActivity.this, "Tag: " + message, Toast.LENGTH_SHORT)
                            .show();
                }
            }
        }
    }
}

Writing an NDEF tag

Before writing an NDEF message, you need to be able to create one. Depending on the OS version your device is running on, it might be more or less complex. Above Lollipop version, a utility method simplifies the creation of a RTD_TEXT NdefRecord. For minor versions, the creation has to be manual.

private NdefMessage createNdefMessage() {
    final String payload = "<The text you'd like to write on the tag>";
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        return new NdefMessage(
                NdefRecord.createTextRecord(Locale.ENGLISH.getLanguage(), payload));
    } else {
        byte[] language = Locale.getDefault().getLanguage().getBytes(StandardCharsets.US_ASCII);
        byte[] textBytes = payload.getBytes(StandardCharsets.UTF_8);
        byte[] data = new byte[1 + language.length + textBytes.length];
        data[0] = (byte) language.length;
        System.arraycopy(language, 0, data, 1, language.length);
        System.arraycopy(textBytes, 0, data, 1 + language.length, textBytes.length);
        return new NdefMessage(new NdefRecord(
                NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], data));
    }
}

Once you have a well formatted message, you need to fetch the Ndef instance corresponding to the current Tag. Establish the connection by calling the connect() method and call writeNdefMessage() to perform the operation. Don't forget to end the connection by calling the close() method.

private void writeNdef(Intent intent) {
    final NdefMessage ndefMessage = createNdefMessage();

    final Ndef ndef = Ndef.get((Tag) intent.getParcelableExtra(NfcAdapter.EXTRA_TAG));
    try {
        ndef.connect();

        if (!ndef.isWritable()) {
            Toast.makeText(MainActivity.this, "Tag is read-only", Toast.LENGTH_SHORT).show();
            return;
        }
        if (ndef.getMaxSize() < ndefMessage.getByteArrayLength()) {
            Toast.makeText(MainActivity.this, "Message is too long to be written on this tag",
                         Toast.LENGTH_SHORT)
                    .show();
            return;
        }

        ndef.writeNdefMessage(ndefMessage);
        ndef.close();
        Toast.makeText(MainActivity.this, "Tag written successfully", Toast.LENGTH_SHORT)
                .show();
    } catch (IOException | FormatException e) {
        e.printStackTrace();
    }
}

For more information about NFC technology and the different available implementations in Android, report to the official documentation.