The above footage from our NFC Workshop walks Android developers through code which demonstrates how to write content to an NFC tag. 


You can follow along below or download the source here




We start by coming into our 'onCreate()' and getting the default NFC adapter.


We want to create our pending intent as a 'FLAG_ACTIVITY_SINGLE_TOP' so that as we tap it, we aren't creating multiple instances of the same application.


Notice that there are three different intent filters: 

  • 'ACTION_TAG_DISCOVERED', 
  • 'ACTION_NDEF_DISCOVERED'
  • 'ACTION_TECH_DISCOVERED'.  

The only one we are using in our array is 'ACTION_TAG_DISCOVERED' because right now we are just trying to find a tag.

 public class MainActivity extends Activity {  
      private static final String TAG = "NFCWriteTag";  
      private NfcAdapter mNfcAdapter;  
   private IntentFilter[] mWriteTagFilters;  
      private PendingIntent mNfcPendingIntent;  
      private boolean silent=false;  
      private boolean writeProtect = false;  
      private Context context;  
   @Override  
   public void onCreate(Bundle savedInstanceState) {  
     super.onCreate(savedInstanceState);  
     setContentView(R.layout.activity_main);  
     context = getApplicationContext();  
           mNfcAdapter = NfcAdapter.getDefaultAdapter(this);  
           mNfcPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,  
                     getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP  
                     | Intent.FLAG_ACTIVITY_CLEAR_TOP), 0);  
     IntentFilter discovery=new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);  
     IntentFilter ndefDetected = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);      
     IntentFilter techDetected = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);  
     // Intent filters for writing to a tag  
     mWriteTagFilters = new IntentFilter[] { discovery };  
   }  


Now we come down to 'onResume()' where we get the intent.  We check the NFC adapter, and if it's not enabled, we put a dialog box to take us to our settings to enable it.  Otherwise it fails. 


If NFC is enabled, we execute 'enableForegroundDispatch()', and pass in our pending intent and filters for what kind of tags we want.  Now, in the foreground, with our activity running, we will bypass the OS dispatch system. 


(Note: We can do this from the Manifest to launch our application from the OS level)


   @Override  
   public boolean onCreateOptionsMenu(Menu menu) {  
     getMenuInflater().inflate(R.menu.activity_main, menu);  
     return true;  
   }  
      @Override  
      protected void onResume() {  
           super.onResume();  
           if(mNfcAdapter != null) {  
                if (!mNfcAdapter.isEnabled()){  
            LayoutInflater inflater = getLayoutInflater();  
               View dialoglayout = inflater.inflate(R.layout.nfc_settings_layout,(ViewGroup) findViewById(R.id.nfc_settings_layout));  
            new AlertDialog.Builder(this).setView(dialoglayout)  
                   .setPositiveButton("Update Settings", new DialogInterface.OnClickListener() {  
                        public void onClick(DialogInterface arg0, int arg1) {  
                                      Intent setnfc = new Intent(Settings.ACTION_WIRELESS_SETTINGS);  
                                      startActivity(setnfc);  
                        }  
                   })  
                .setOnCancelListener(new DialogInterface.OnCancelListener() {  
                     public void onCancel(DialogInterface dialog) {  
                          finish(); // exit application if user cancels  
                  }                      
                }).create().show();  
                }  
                mNfcAdapter.enableForegroundDispatch(this, mNfcPendingIntent, mWriteTagFilters, null);  
           } else {  
                Toast.makeText(context, "Sorry, No NFC Adapter found.", Toast.LENGTH_SHORT).show();  
           }  
      }  


At 'onPause()' we disable foreground dispatch.


'onNewIntent()' is the actual intent once we've tapped the tag.  We check to see if the action in the intent matches 'ACTION_TAG_DISCOVERED', and if it is, this is how we get the tag from the reader.


'Tag' is an NFC object, and we can use 'getParceableExtra()' to get its data.  We grab the list of technologies associated with that tag using 'getTechList()' to see if it has the technologies we are trying to support.


In this case, we are checking to see if it is writeable.  If it is, we pass in what we are going to write to the tag, and then we pass in the physical tag to write it.



      @Override  
      protected void onPause() {  
           super.onPause();  
           if(mNfcAdapter != null) mNfcAdapter.disableForegroundDispatch(this);  
      }  
      @Override  
      protected void onNewIntent(Intent intent) {  
           super.onNewIntent(intent);            
           if(NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {  
          // validate that this tag can be written  
       Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
       if(supportedTechs(detectedTag.getTechList())) {  
            // check if tag is writable (to the extent that we can  
            if(writableTag(detectedTag)) {  
                 //writeTag here  
                 WriteResponse wr = writeTag(getTagAsNdef(), detectedTag);  
                 String message = (wr.getStatus() == 1? "Success: " : "Failed: ") + wr.getMessage();  
                 Toast.makeText(context,message,Toast.LENGTH_SHORT).show();  
            } else {  
                 Toast.makeText(context,"This tag is not writable",Toast.LENGTH_SHORT).show();  
                 Sounds.PlayFailed(context, silent);  
            }             
       } else {  
            Toast.makeText(context,"This tag type is not supported",Toast.LENGTH_SHORT).show();  
            Sounds.PlayFailed(context, silent);  
       }  
     }  
      }  

In 'writeTag()', we pass in our NDEF message and find its size.  Then we try to grab the formatted tag.  If the tag is NDEF encoded and formatted, this will come back true and we can connect to it.  

Once we've connected to the tag, we check to see if the tag is writeable.  If it is, we can check how much space it has to see if what we are going to write will fit.  


If the tag has room, we can write our message on it.  If we try to write too much, it will fail as an exception in the try/catch statement. 



   public WriteResponse writeTag(NdefMessage message, Tag tag) {  
     int size = message.toByteArray().length;  
     String mess = "";  
     try {  
       Ndef ndef = Ndef.get(tag);  
       if (ndef != null) {  
         ndef.connect();  
         if (!ndef.isWritable()) {  
           return new WriteResponse(0,"Tag is read-only");  
         }  
         if (ndef.getMaxSize() < size) {  
           mess = "Tag capacity is " + ndef.getMaxSize() + " bytes, message is " + size  
               + " bytes.";  
           return new WriteResponse(0,mess);  
         }  
         ndef.writeNdefMessage(message);  
         if(writeProtect) ndef.makeReadOnly();  
         mess = "Wrote message to pre-formatted tag.";  
         return new WriteResponse(1,mess);  
       } else {  
         NdefFormatable format = NdefFormatable.get(tag);  
         if (format != null) {  
           try {  
             format.connect();  
             format.format(message);  
             mess = "Formatted tag and wrote message";  
             return new WriteResponse(1,mess);  
           } catch (IOException e) {  
             mess = "Failed to format tag.";  
             return new WriteResponse(0,mess);  
           }  
         } else {  
           mess = "Tag doesn't support NDEF.";  
           return new WriteResponse(0,mess);  
         }  
       }  
     } catch (Exception e) {  
       mess = "Failed to write tag";  
       return new WriteResponse(0,mess);  
     }  
   }  
   private class WriteResponse {  
        int status;  
        String message;  
        WriteResponse(int Status, String Message) {  
             this.status = Status;  
             this.message = Message;  
        }  
        public int getStatus() {  
             return status;  
        }  
        public String getMessage() {  
             return message;  
        }  
   }  
      public static boolean supportedTechs(String[] techs) {  
        boolean ultralight=false;  
        boolean nfcA=false;  
        boolean ndef=false;  
        for(String tech:techs) {  
             if(tech.equals("android.nfc.tech.MifareUltralight")) {  
                  ultralight=true;  
             }else if(tech.equals("android.nfc.tech.NfcA")) {   
                  nfcA=true;  
             } else if(tech.equals("android.nfc.tech.Ndef") || tech.equals("android.nfc.tech.NdefFormatable")) {  
                  ndef=true;  
             }  
        }  
     if(ultralight && nfcA && ndef) {  
          return true;  
     } else {  
          return false;  
     }  
      }  
   private boolean writableTag(Tag tag) {  
     try {  
       Ndef ndef = Ndef.get(tag);  
       if (ndef != null) {  
         ndef.connect();  
         if (!ndef.isWritable()) {  
           Toast.makeText(context,"Tag is read-only.",Toast.LENGTH_SHORT).show();  
           Sounds.PlayFailed(context, silent);  
           ndef.close();   
           return false;  
         }  
         ndef.close();  
         return true;  
       }   
     } catch (Exception e) {  
       Toast.makeText(context,"Failed to read tag",Toast.LENGTH_SHORT).show();  
       Sounds.PlayFailed(context, silent);  
     }  
     return false;  
   }  


Here we specify what we are going to write to the tag ('smartwhere.com/nfc.html') and get its bytes and create its payload.  Then we specify the prefix, which is specified by the first character of the payload. This particular one will put 'http://www' in front of the payload.  


Now we create a new NDEF record and wrap it into a message.  In addition to the NDEF record, we also pass the message an AAR.  If 'addAAR' is enabled, it will launch the specified application and deliver our URI. Otherwise we just return the URI record. 

An Android application record (AAR) allows us to circumvent the normal dispatch system and deliver content tag content into a specific application. And if the specified application doesn't exist, Android takes you to the marketplace to get it. 



   private NdefMessage getTagAsNdef() {  
        boolean addAAR = false;  
        String uniqueId = "smartwhere.com/nfc.html";      
     byte[] uriField = uniqueId.getBytes(Charset.forName("US-ASCII"));  
     byte[] payload = new byte[uriField.length + 1];       //add 1 for the URI Prefix  
     payload[0] = 0x01;                        //prefixes http://www. to the URI  
     System.arraycopy(uriField, 0, payload, 1, uriField.length); //appends URI to payload  
     NdefRecord rtdUriRecord = new NdefRecord(  
       NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], payload);  
     if(addAAR) {  
          // note: returns AAR for different app (nfcreadtag)  
          return new NdefMessage(new NdefRecord[] {  
       rtdUriRecord, NdefRecord.createApplicationRecord("com.tapwise.nfcreadtag")  
     });   
     } else {  
          return new NdefMessage(new NdefRecord[] {  
               rtdUriRecord});  
     }  
   }  
 }  

Video: NFC Workshop, July 17, 2012
Location: Seattle Waterfront
Post by: Kelsey W
7

View comments

  1. great!, thanks for the effort and time!!

    ReplyDelete
  2. I was using your sample to write some of my tags. One of them was MIFARE Classic. Does Android support writing them? Your application does not support them for sure but why?

    ReplyDelete
    Replies
    1. Hello ,I am also getting error while writing in MIFARE card.

      Did you get any solution?

      Delete
  3. This example doesn't have manifest or res layouts, It's a great work and is good for me, but maybe not for people that is begining with nft stufs. But thnks in my name! ;)

    ReplyDelete
  4. This blog site is pretty good! How was it made . I view something genuinely interesting about your site so I saved to my bookmarks . You can visit my Exit intent technology

    ReplyDelete
  5. I can't build nfc_settings_layout. Where is nfc_settings_layout? Please help me!

    ReplyDelete
  6. Thanks for sharing information.Here is the information of IDENTIS that manufactures RFID tags:
    NFC Tag

    ReplyDelete

(The "Imagine That" series highlights benefits & conveniences of NFC by looking at differences in every day encounters with and without the technology)

You're walking through the mall with your girlfriend—Lululemon bags in hand from the two grueling hours of shopping you’ve just completed—when, completely unexpectedly, a Dark Knight Rises poster catches your eye.  You have been waiting for this moment for months.  Is there any possible way that Christopher Nolan has outdone himself yet again?  You don’t know—but you’d like to find out.  That’s when it hits you: your newly Lulu-outfitted girlfriend might not go for it.
1

One of the biggest advantages of NFC over other technologies is that it's handled by the operating system.  This means that you don't have to download an application to read NFC tags or worry about whether or not your application functions with the type of tag you are trying to read.

The above footage from our NFC Workshop walks Android developers through code which demonstrates how to read content and parse messages from an NFC tag.

You can follow along below or download the source here.

(Note: It may be beneficial to first read the previous post on writing content to an NFC tag which prefaces material in this post.)

We start by setting up an intent filter and grabbing our default adapter.
6

The above footage from our NFC Workshop walks Android developers through code which demonstrates how to write content to an NFC tag. 

You can follow along below or download the source here. 

We start by coming into our 'onCreate()' and getting the default NFC adapter.

We want to create our pending intent as a 'FLAG_ACTIVITY_SINGLE_TOP' so that as we tap it, we aren't creating multiple instances of the same application.
7

Last week, we held an NFC workshop for the Seattle developer community in association with SEADroid, providing a high-level overview of NFC fundamentals and a hands-on introduction to incorporating NFC functionality into mobile applications. 

In short, it was a great success (admittedly, I was a little disappointed that only three of the over 60 attendees were women--see for yourself above).  We had a good-sized turnout and an awesome crowd of Android-savvy developers.

Isn't it annoying when you go down the street to your favorite coffee shop to get some work done and you end up spending a major chunk of time just getting set up?  You came here to get work done, not spend twenty minutes trying to connect to the WiFi.  It's bad enough that you've already had to wait around for a table to open up--we've all been there--the last thing you need is another time-suck.
1
Labels
Blog Archive
Loading
Dynamic Views theme. Powered by Blogger. Report Abuse.