3

This code works fine when I use it on a device with Android Lollipop (5.x) or Marshmallow (6.0):

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public NdefMessage createNdfMessage(String content) {
    NdefRecord record = NdefRecord.createTextRecord("en", content);
    NdefMessage msg = new NdefMessage(new NdefRecord[]{record});
    return msg;
}

But when I try this on a device with Android 4.2.2 (API level 17) my app crashes. How can I use this code to create a Text record on API levels below 21 (that's the API level where the method NdefRecord.createTextRecord became available)?

Michael Roland
  • 39,663
  • 10
  • 99
  • 206

2 Answers2

7

The method NdefRecord.createTextRecord() was introduced in API level 21. Consequently, it is not available on platforms below that API level. However, you could easily assemble the Text record on your own. The payload of a Text record consists of a status byte, a language code field, and a text field:

+-------------+---------------+--------------------------+
| Status byte | Language code | Text                     |
| (1 byte)    | (n byte)      | (m byte)                 |
+-------------+---------------+--------------------------+
  • The status byte indicates the character encoding of the text field (0 = UTF-8, 1 = UTF-16) in bit 7 and the length n of the language code in bits 5..0. Bit 6 must always be zero.
  • The language code filed contains an IANA language code encoded in US-ASCII (e.g. "en").

You could create the Text record using this method:

public static NdefRecord createTextRecord(String language, String text) {
    byte[] languageBytes;
    byte[] textBytes;
    try {
        languageBytes = language.getBytes("US-ASCII");
        textBytes = text.getBytes("UTF-8");
    } catch (UnsupportedEncodingException e) {
        throw new AssertionError(e);
    }

    byte[] recordPayload = new byte[1 + (languageBytes.length & 0x03F) + textBytes.length];

    recordPayload[0] = (byte)(languageBytes.length & 0x03F);
    System.arraycopy(languageBytes, 0, recordPayload, 1, languageBytes.length & 0x03F);
    System.arraycopy(textBytes, 0, recordPayload, 1 + (languageBytes.length & 0x03F), textBytes.length);

    return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, null, recordPayload);
}

NdefRecord r = createTextRecord("en", content);
Michael Roland
  • 39,663
  • 10
  • 99
  • 206
0

Yes, createTextRecord is introduced in API 21, so you can't call it in the previous versions. https://developer.android.com/reference/android/nfc/NdefRecord.html

Check if your API level is 21 before to call createTextRecord.

public NdfeMessage create(String content){
    int currentapiVersion = android.os.Build.VERSION.SDK_INT;
    if (currentapiVersion >= android.os.Build.VERSION_CODES.LOLLIPOP){
        NdefRecord record = NdefRecord.createTextRecord("en", content);
        NdefMessage msg = new NdefMessage(new NdefRecord[]{record});
        return msg;
    } else{
        return null;
    }
}
Erik Minarini
  • 4,795
  • 15
  • 19
  • but i also want to write plain/text from devices below api level 21 – Syed Muhammad Arslan Jun 17 '16 at 07:36
  • You can write a message from API level 10, but you cant write a new record under level 21, is not the same. https://developer.android.com/reference/android/nfc/tech/Ndef.html#writeNdefMessage(android.nfc.NdefMessage) – Erik Minarini Jun 17 '16 at 07:48
  • 1
    API below 21 does't mean you can't write a record, but it means `NdefRecord.createTextRecord` isn't available. You can still create it in other way as the other answer states. – Aritz Feb 06 '18 at 09:10