Filtering for NFC Intents:
To start your application when an NFC tag that you want to handle is scanned, your application can filter for one, two, or all three of the NFC intents in the Android manifest.
Usually you want to filter for the
ACTION_NDEF_DISCOVERED
intent for the most control of when your application starts.But ACTION_TECH_DISCOVERED
intent is a fallback for ACTION_NDEF_DISCOVERED
when no applications filter for ACTION_NDEF_DISCOVERED
or for when the payload is not NDEF. Filtering for ACTION_TAG_DISCOVERED
is usually too general of a category to filter on. Many applications will filter for ACTION_NDEF_DISCOVERED
or ACTION_TECH_DISCOVERED
before ACTION_TAG_DISCOVERED
, so your application has a low probability of starting. ACTION_TAG_DISCOVERED
is only available as a last resort for applications to filter for in the cases where no other applications are installed to handle the ACTION_NDEF_DISCOVERED
or ACTION_TECH_DISCOVERED
intent.
Because NFC tag deployments vary and are many times not under your control, this is not always possible, which is why you can fallback to the other two intents when necessary. When you have control over the types of tags and data written, it is recommended that you use NDEF to format your tags. The following sections describe how to filter for each type of intent.
ACTION_NDEF_DISCOVERED:
To filter for
ACTION_NDEF_DISCOVERED
intents, declare the intent filter along with the type of data that you want to filter for. The following example filters for ACTION_NDEF_DISCOVERED
intents with a MIME type of text/plain
:<intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain" /> </intent-filter>
The following example filters for a URI in the form of
http://shaikhhamadali.blogspot.com/
p/home.html.<intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED"/> <category android:name="android.intent.category.DEFAULT"/> <data android:scheme="http" android:host="shaikhhamadali.blogspot.com" android:pathPrefix="/p/home.html" /> </intent-filter>
ACTION_TECH_DISCOVERED:
If your activity filters for the
ACTION_TECH_DISCOVERED
intent, you must create an XML resource file that specifies the technologies that your activity supports within a tech-list
set. Your activity is considered a match if a tech-list
set is a subset of the technologies that are supported by the tag, which you can obtain by calling getTechList
()
.
For example, if the tag that is scanned supports MifareClassic, NdefFormatable, and NfcA, your
tech-list
set must specify all three, two, or one of the technologies (and nothing else) in order for your activity to be matched.
so We must specify the technology we are interested in. For this purpose, we create a subfolder called xml in the res folder. In this folder we create the file nfc_filter.xml, in which we specify the technologies.
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <tech-list> <tech>android.nfc.tech.Ndef</tech> <!-- class name --> </tech-list> </resources> <!-- other tags for NFC <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <tech-list> <tech>android.nfc.tech.IsoDep</tech> <tech>android.nfc.tech.NfcA</tech> <tech>android.nfc.tech.NfcB</tech> <tech>android.nfc.tech.NfcF</tech> <tech>android.nfc.tech.NfcV</tech> <tech>android.nfc.tech.Ndef</tech> <tech>android.nfc.tech.NdefFormatable</tech> <tech>android.nfc.tech.MifareClassic</tech> <tech>android.nfc.tech.MifareUltralight</tech> </tech-list> </resources> -->
Basic Application on This NDEF:
OnLaunch
On Tag Read
Create new Android Project
Project Name: NFC
//tested from 2.3.3 to current android sdk
Build Target: Android 2.3.3 //or greater than that
Application Name: NFC
Package Name: com.shaikhhamadali.blogspot.nfc
Create layout file: activity_nfcdetails
Project Name: NFC
//tested from 2.3.3 to current android sdk
Build Target: Android 2.3.3 //or greater than that
Application Name: NFC
Package Name: com.shaikhhamadali.blogspot.nfc
Create layout file: activity_nfcdetails
1.create layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".NFCDetails" > <TextView android:id="@+id/tV_ReadNFC" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="@string/attachNFCToRead" android:textSize="30sp" /> </RelativeLayout>
2.code of activity:
package com.shaikhhamadali.blogspot.nfc; import java.io.UnsupportedEncodingException; import java.util.Arrays; import android.app.Activity; import android.app.PendingIntent; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentFilter.MalformedMimeTypeException; import android.nfc.NdefMessage; import android.nfc.NdefRecord; import android.nfc.NfcAdapter; import android.nfc.Tag; import android.nfc.tech.Ndef; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.widget.TextView; import android.widget.Toast; /** * Activity for reading data from an NDEF Tag. * * @author Hamad Shaikh * */ public class NFCDetails extends Activity { public static final String MIMETYPE_TEXT_PLAIN = "text/plain"; public static final String TAG = "NfcTut"; private TextView tV_ReadNFC; private NfcAdapter nfcAdapt; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_nfcdetails); //initialize control tV_ReadNFC = (TextView) findViewById(R.id.tV_ReadNFC); //initialise nfc adapter nfcAdapt = NfcAdapter.getDefaultAdapter(this); //check is NFC adapter initialized null when device doesn't support NFC if (nfcAdapt == null) { // device deosn't support nfc Toast.makeText(this, "your device doesn't support NFC.", Toast.LENGTH_SHORT).show(); finish(); return; } //check is NFC adapter feature enabled if (!nfcAdapt.isEnabled()) { tV_ReadNFC.setText("NFC is disabled."); } else { tV_ReadNFC.setText(R.string.attachNFCToRead); } handleIntent(getIntent()); } @Override protected void onResume() { super.onResume(); /* * It's important, that the activity is in the foreground (resumed). Otherwise * an IllegalStateException is thrown. */ requestForegroundDispatch(this, nfcAdapt); } @Override protected void onPause() { //Call this before onPause, to avoid an IllegalArgumentException. stopForegroundDispatch(this, nfcAdapt); super.onPause(); } @Override protected void onNewIntent(Intent intent) { /* * This method gets called, when a new Intent gets associated with the current activity instance. * Instead of creating a new activity, onNewIntent will be called. * In our case this method gets called, when the user attaches a Tag to the device. */ handleIntent(intent); } private void handleIntent(Intent intent) { //get action from intent String action = intent.getAction(); //is action matches the NDEF_DISCOVERED if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) { //what is the mime type String type = intent.getType(); //is text plain or not if (MIMETYPE_TEXT_PLAIN.equals(type)) { //create tag instance and retrieve extended data from intent Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); //execute background task new NdefReaderBgTask().execute(tag); } else { Log.d(TAG, "mime type is not text/plain: " + type); } } //is action matches the ACTION_TECH_DISCOVERED else if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) { // In case we would still use the Tech Discovered Intent Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); //get the available technologies String[] techList = tag.getTechList(); //get class name String searchedTech = Ndef.class.getName(); for (String tech : techList) { //tag matched then execute background task if (searchedTech.equals(tech)) { new NdefReaderBgTask().execute(tag); break; } } } } /** * @param act The corresponding {@link Activity} requesting the foreground dispatch. * @param adp The {@link NfcAdapter} used for the foreground dispatch. */ public static void requestForegroundDispatch(final Activity act, NfcAdapter adp) { //create instance of intent final Intent intent = new Intent(act.getApplicationContext(), act.getClass()); //set flags on top intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); //crate instance of pending intent final PendingIntent pendingIntent = PendingIntent.getActivity(act.getApplicationContext(), 0, intent, 0); //create intent filters array IntentFilter[] filters = new IntentFilter[1]; //create 2D array of techlist String String[][] techList = new String[][]{}; // Note: This is the same filter as in our manifest. filters[0] = new IntentFilter(); filters[0].addAction(NfcAdapter.ACTION_NDEF_DISCOVERED); filters[0].addCategory(Intent.CATEGORY_DEFAULT); try { //add data type filters[0].addDataType(MIMETYPE_TEXT_PLAIN); } catch (MalformedMimeTypeException e) { //throw exception on different mime type throw new RuntimeException("Check your mime type."); } //enable foreground dispatch to current activity adp.enableForegroundDispatch(act, pendingIntent, filters, techList); } /** * @param act The corresponding {@link BaseActivity} requesting to stop the foreground dispatch. * @param adp The {@link NfcAdapter} used for the foreground dispatch. */ public static void stopForegroundDispatch(final Activity act, NfcAdapter adp) { adp.disableForegroundDispatch(act); } /** * Background task for reading the data. Do not block the UI thread while reading. * @author Hamad Shaikh * */ private class NdefReaderBgTask extends AsyncTask<Tag, Void, String> { @Override protected String doInBackground(Tag... params) { Tag tag = params[0]; Ndef ndef = Ndef.get(tag); if (ndef == null) { // when NDEF is not supported by this Tag. return null; } //Get the NdefMessage that was read from the tag at discovery time. NdefMessage ndefMessage = ndef.getCachedNdefMessage(); //Get the NDEF Records inside this NDEF Message. NdefRecord[] records = ndefMessage.getRecords(); for (NdefRecord ndefRecord : records) { if (ndefRecord.getTnf() == NdefRecord.TNF_WELL_KNOWN && Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT)) { try { return readNDEFRecordText(ndefRecord); } catch (UnsupportedEncodingException e) { Log.e(TAG, "Unsupported Encoding", e); } } } return null; } private String readNDEFRecordText(NdefRecord record) throws UnsupportedEncodingException { /* * See NFC forum specification for "Text Record Type Definition" at 3.2.1 * * http://www.nfc-forum.org/specs/ * * bit_7 defines encoding * bit_6 reserved for future use, must be 0 * bit_5..0 length of IANA language code */ // get record pay load variable length byte[] payload = record.getPayload(); // Get the Text Encoding String textEncoding = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16"; // Get the Language Code int languageCodeLength = payload[0] & 0063; // String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII"); // e.g. "en" // Get the Text return new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding); } @Override protected void onPostExecute(String result) { if (result != null) { tV_ReadNFC.setText("Content in your TAG: " + result); } } } }
3. Manifest File:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.shaikhhamadali.blogspot.nfc" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="17" /> <uses-permission android:name="android.permission.NFC" /> <uses-feature android:name="android.hardware.nfc" android:required="true" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.shaikhhamadali.blogspot.nfc.NFCDetails" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> </intent-filter> </activity> </application> </manifest>
4. note that:
- you can use this in any way you want.
- you can read other mime types of nfc too.
- about NFC.
5. conclusion:
- Some information about how to Read NFC Tags
- Know how to basic of NFC in my previous post.
- know how to use AsyncTask to avoid UI blocking.
- know the usage of intent filters,permissions and uses-feature and tech-list.
- know what are NFC Intents.
- Some information about how to Read NFC Tags
- Know how to basic of NFC in my previous post.
- know how to use AsyncTask to avoid UI blocking.
- know the usage of intent filters,permissions and uses-feature and tech-list.
- know what are NFC Intents.
6. About the post:
- The code seems to explain itself due to comments, but if you have any questions you can freely ask too!
- Don’t mind to write a comment whatever you like to ask, to know,to suggest or recommend.
- Hope you enjoy it!
7. Source Code:
you can download the source code here
Cheers,
Hamad Ali Shaikh
- The code seems to explain itself due to comments, but if you have any questions you can freely ask too!
- Don’t mind to write a comment whatever you like to ask, to know,to suggest or recommend.
- Hope you enjoy it!
you can download the source code here