How to write “Hello World” into a NFC tag in Android.

When I started my experience with NFC technology finding a “Hello Word” tutorial to get minimal bases on NFC wasn’t so easy.
For this I decided to write it!
In this tutorial we will see how it’s possible to write a String in a NFC tag.

What do we need?
1) a mobile phone with a nfc chip (Nexus S, Galaxy Nexus, Samsung Galaxy SIII ect…)
2) a NFC Tag. There are many website where it’s possible to buy them. I bought it here: http://www.tagage.net/tagage-shop/ . And In particular the one used for this tutorial is: Mifare Classic (Standard) – Rectangle (Racetrack)
3) An application to read the NFC to verify if our application works properly. (I use https://play.google.com/store/apps/details?id=com.nxp.nfc.tagwriter)

The goal of this tutorial is to build an application that can write a NFC tag following these steps:
1) Run manually the application
2) Write a String in a EditText
3) Put the mobile phone close to the tag
4) Push a button to write the string into the tag.

Let’s start! I know the theoretical part is boring, but some snippets are needed.
So we start with general information about nfc technology:

NFC builds upon Radio-frequency identification (RFID) systems by allowing two-way communication between endpoints, where earlier systems such as contactless smart cards were one-way only.[6] Since unpowered NFC “tags” can also be read by NFC devices,[2] it is also capable of replacing earlier one-way applications.[Wikipedia]

So with the NFC technology it’s possible to send messages (NDEF) between mobile-tag or mobile-mobile. NDEF messages were defined b y the NFC forum.
Obviously, Android supports this standards. In particular with Android there are two modes:

1) Reading NDEF data from an NFC tag
2) Beaming NDEF messages from one device to another with Android Beam™

We are focusing on the first mode. It’s possible also to build non-NDEF message, but it’s over from the goals of this tutorial (For details Advanced NFC
Ok, are we ready to code? No! We need just to understand how Android system works. When a tag is detected, the tag dispatch system analyzes it and starts an application to work on it. The system decides between the applications that have declared an Intent filter.

Reading NDEF data from an NFC tag is handled with the tag dispatch system, which analyzes discovered NFC tags, appropriately categorizes the data, and starts an application that is interested in the categorized data. An application that wants to handle the scanned NFC tag can declare an intent filter and request to handle the data. [Android Doc]

According to that, our application has to:

1) Declare an Intent Filter to announce to the system that it’s enabled to work on NFC.
2) Have a method that Android will call when NFC is detected.
3) Create a method to build a NDEF message.
4) Create a method to write the NDEF message.

NfcAdapter adapter;
PendingIntent pendingIntent;
IntentFilter writeTagFilters[];
boolean writeMode;
Tag mytag;
Context ctx;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    ctx=this;
    Button btnWrite = (Button) findViewById(R.id.button);
    final TextView message = (TextView)findViewById(R.id.edit_message);
    btnWrite.setOnClickListener(new View.OnClickListener()
    {
        @Override
        public void onClick(View v) {
            try {
                if(mytag==null){
                    Toast.makeText(ctx, ctx.getString(R.string.error_detected), Toast.LENGTH_LONG ).show();
                }else{
                    write(message.getText().toString(),mytag);
                    Toast.makeText(ctx, ctx.getString(R.string.ok_writing), Toast.LENGTH_LONG ).show();
                }
            } catch (IOException e) {
                Toast.makeText(ctx, ctx.getString(R.string.error_writing), Toast.LENGTH_LONG ).show();
                e.printStackTrace();
            } catch (FormatException e) {
                Toast.makeText(ctx, ctx.getString(R.string.error_writing) , Toast.LENGTH_LONG ).show();
                e.printStackTrace();
            }
        }
    });

    adapter = NfcAdapter.getDefaultAdapter(this);
    pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
    IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
    tagDetected.addCategory(Intent.CATEGORY_DEFAULT);
    writeTagFilters = new IntentFilter[] { tagDetected };
}

In the OnCreate of our activity we set graphic elements like Button, in particular when you push it, the tag will be written (write(message.getText().toString(),mytag);). With last 5 rows we create a IntentFilter, so we tell Android that our application is enabled to work on nfc tag (NfcAdapter.ACTION_TAG_DISCOVERED). We could register our app directly with a intentFilter in the Manifest. In this way we couldn’t lunch our Activity like a simple program, but Android will boot it when it detects a tag. In both ways, after detecting and deciding which app has to work on with the tag, Android will call the method onNewIntent and pass the object tag to the activity:

@Override
protected void onNewIntent(Intent intent){
    if(NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())){
        mytag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        Toast.makeText(this, this.getString(R.string.ok_detection) + mytag.toString(), Toast.LENGTH_LONG ).show();
    }
}

So now we have the object tag and we have to build the function to create the NDEF message and to write it into the NFC tag.

private NdefRecord createRecord(String text) throws UnsupportedEncodingException {

    //create the message in according with the standard
    String lang = "en";
    byte[] textBytes = text.getBytes();
    byte[] langBytes = lang.getBytes("US-ASCII");
    int langLength = langBytes.length;
    int textLength = textBytes.length;

    byte[] payload = new byte[1 + langLength + textLength];
    payload[0] = (byte) langLength;

    // copy langbytes and textbytes into payload
    System.arraycopy(langBytes, 0, payload, 1, langLength);
    System.arraycopy(textBytes, 0, payload, 1 + langLength, textLength);

    NdefRecord recordNFC = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload);
    return recordNFC;
}

private void write(String text, Tag tag) throws IOException, FormatException {

    NdefRecord[] records = { createRecord(text) };
    NdefMessage message = new NdefMessage(records);
    Ndef ndef = Ndef.get(tag);
    ndef.connect();
    ndef.writeNdefMessage(message);
    ndef.close();
}

The NFC forum provides for NDEF message a structure with a payload and content. The payload contains information regarding how to interpret the information inside the NDEF message as language, coding etc… (for details: NDEF message ). The behavior of the method write is enough clear: calls the method to create the NDEF message, opens a connection with the tag and writes the message into it.

Now we need to check if everything works in a proper way. If it is, we can read “HELLO WORLD!” inside the tag!! ;)
Here you can download the whole project. See you at our next tutorial!

android-tutorial , , ,

19 responses to How to write “Hello World” into a NFC tag in Android.


  1. Luca

    Interessante, funzionale e molto semplice….GRAZIE!
    Una sola domanda: ho notato che quando il tuo esempio legge i tag hanno una codifica “strana”. Ho controlalto e dicono che sia una conversione esadacimale…può essere vero?

  2. Salvatore

    Ciao Luca,
    scusa sto iniziando adesso a cercare di usare NFC su android e volevo chiederti un favore.

    Potresti estrapolare per tutti la parte di codice che si occupa SOLTANTO della lettura delle informazioni dal TAG? Io avrei bisogno di leggere le info da un TAG e, in base alle informazioni contenute, effettuare delle azioni tipo apertura browser ecc..

    Grazie..

    • Salvatore

      Ho inserito questo codice nell’activity ma è come se “vincesse” un’altra app.. Ecco l’activity

      Tag myTag;
          NfcAdapter adapter;
          PendingIntent pendingIntent;
         
          @Override
          public void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
             
              adapter = NfcAdapter.getDefaultAdapter(this);
              pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
              IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
              tagDetected.addCategory(Intent.CATEGORY_DEFAULT);
             
          }
         
          @Override
          protected void onNewIntent(Intent intent) {    
              super.onNewIntent(intent);
              Toast.makeText(getApplicationContext(), "Hello", Toast.LENGTH_LONG).show();
             
              Log.d("NFC intent", intent.getAction());
              myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
              Log.d("NFC tag", myTag.toString());
          }
  3. Sachin Dhivare

    Thanks for such a nice tutorial. I am not able to understand the program flow. Can you just elaborate it somewhat more in depth??

  4. Awesome tutorial.This is my first NFC app. It worth to be the first NFC app.

  5. Manish

    Great post. this helped me a lot in understanding the NFC android concept. Do you have any sample application for reading the data from tag as well?

    thanks
    Manish

    • Castelo

      You can use this.

      Classe Mifare:

      public class Mifare {

          private static String TAG = "MIFARE";

          public static String readTag(Intent intent) {

              Log.i(TAG, "readTag");

              Tag mifare = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
              long TagId = ByteArrayToLong(mifare.getId());
              Log.i(TAG, "Tag ID: " + TagId);

              return String.valueOf(TagId);
          }

         
           * @SuppressWarnings("unused") private long ByteLong(byte[] inarray) { int i
           * = 0; //AnyType[] resultado; resultado = inarray[0]; for(i = 1;i<=3 ;i++)
           * { resultado = resultado + (inarray[i] * 2 ^ (8 * i)); }
           *
           * return resultado; }
           */
          // Buscar xpass
          /*
           * public static int getInt(byte[] array, int offset) { return
           * ((array[offset] & 0xff) * 2 ^ (8 * 3+array[offset+1]& 0xff) * 2 ^ (8 *
           * 2)) | ((array[offset+2] & 0xff) * 2 ^ (8 * 1)) | (array[offset+3] &
           * 0xff)* 2 ^ (8 * 0); }
           */

          public static void putInt(int value, byte[] array, int offset) {
              array[offset] = (byte) (0xff & (value * 2 ^ (8 * 0) >> 24));
              array[offset + 1] = (byte) (0xff & (value * 2 ^ (8 * 1) >> 16));
              array[offset + 2] = (byte) (0xff & (value * 2 ^ (8 * 2) >> 8));
              array[offset + 3] = (byte) (0xff & value * 2 ^ (8 * 3));
          }

      Class main: read tag

      @SuppressLint("NewApi")
      public class SCA extends Activity {
          private static String TAG = "SCA:";
          // NFC
          private NfcAdapter mAdapter;
          private PendingIntent mPendingIntent;
          private IntentFilter[] mFilters;
          private String[][] mTechLists; 

          @TargetApi(10)
          @Override
          public void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
             
              // NFC
              try {
                  mAdapter = NfcAdapter.getDefaultAdapter(this);
                  // Create a generic PendingIntent that will be deliver to this
                  // activity. The NFC stack
                  // will fill in the intent with the details of the discovered tag
                  // before delivering to
                  // this activity.
                  mPendingIntent = PendingIntent.getActivity(this, 0,
                          new Intent(this, getClass())
                                  .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
                  // Setup an intent filter for all MIME based dispatches
                  IntentFilter ndef = new IntentFilter(
                          NfcAdapter.ACTION_TECH_DISCOVERED);
                  mFilters = new IntentFilter[] { ndef, };
                  // Setup a tech list for all NfcF tags
                  mTechLists = new String[][] { new String[] { NfcA.class.getName() } };
              } catch (Exception e) {
                  Log.i(TAG, "onCreate " + e.getMessage());
              }
          }


          public void resolveIntent(Intent intent) throws Exception {
              Log.i(TAG, "Função - resolveIntent");
              Cursor contacto = null;
              try {
                 
                  tagId = Mifare.readTag(intent);
                  String action = intent.getAction();
                 
                      if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {
                          Log.i(TAG, "getCartao");
                     
              }
              Log.i(TAG, "Função - resolveIntent");
          }

          // ********************************************** NFC
          // ****************************************************************
          @Override
          public void onNewIntent(Intent intent) {
              try {
                  Log.i(TAG, "onNewIntent");
                  setIntent(intent);
                  resolveIntent(intent);
                  // CleanTextView();
              } catch (Exception e) {
                  Log.i(TAG, "Exception onNewIntent " + e.getMessage());
              }
          }

          @TargetApi(10)
          @Override
          public void onPause() {
              super.onPause();
              Log.d(TAG, "onPause() called");
              if (mAdapter != null)
                  mAdapter.disableForegroundDispatch(this);
          }

          @TargetApi(10)
          @Override
          public void onResume() {
              super.onResume();
              Log.d(TAG, "onResume() called");
              if (mAdapter != null)
                  mAdapter.enableForegroundDispatch(this, mPendingIntent, mFilters,
                          mTechLists);
          }

          // **********************************************FIM - NFC
          // *********************************************************************

          // *********************************************** Verificar IMEI
          // TELEMOVEL**************************************************
          public String TelemovelImei() {
              String IMEI = "";
              TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
              IMEI = telephonyManager.getDeviceId();
              return IMEI;
          }
      • Castelo

        ups classe mifare

        private static long ByteArrayToLong(byte[] inarray) {

                long resultado = inarray[0] & 0xff;

                for (int i = 1; i <= 3; i++) {
                    // Log.i(TAG, "resultado " + resultado);
                    resultado = (long) (resultado + ((inarray[i] & 0xff) * Math.pow(2,
                            (8 * i))));
                }
                return resultado;
            }
  6. Bindhu

    Hi i downloaded your source code,while running i got error Unable to resume activity,Null pointer exception,why so?
    Thanks in advance

    • Hiran Patel

      Hi, if you go onto the manifest and change minimum sdk version to 9, it will get rid of this error! Can you tell me where to download the source code from please. thanks

  7. now I want to run NFC applications on the virtual machine, how do I write one app to open the function of reading, writing, NFC beam but do not know how to run on a virtual machine

  8. thandra

    will you please provide me android source code to read nfc tag …..

  9. Divya

    Hi,
    Thank you for such a great sample, i was doing my final year project to build an nfc app to write tags,
    But i am afraid when i try your code and implement in my source i am having a error from logcat: http://pastebin.com/8ppAZBSN

    Please Help

    Thanks

  10. Roberta

    Ciao a tutti…volevo chiedervi una mano..dovrei realizzare per la mia tesi un app che legga un tag nfc..voi potreste aiutarmi..io sto partendo quasi da zero!
    Grazie mille a tutti!

  11. Android

    Thanks so much for the tutorial! I downloaded the code and tried to run it, I see this error. What do I do?
    Call requires API level 9 (current min is 8): android.nfc.FormatException#printStackTrace

    Thanks in advance!

  12. Hallo!

    I am going to develop a desktop application that the NFC reader should read the tag and write the data in the tag. I want to know how to write this desktop application in Java language and how to structure my task to detect the tag, and write as a NDEF message. I mean how I should tell the system to write like this or that.

    Thanks
    waiting for your responses.

  13. Thomas

    For more advanced NDEF content, you might be interested in

    https://code.google.com/p/ndef-tools-for-android/

    Cheers!

  14. richard

    what was the string in a EditText????

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>