How to use NFC ACTIONS
Asked Answered
M

5

5

I am trying to register a receiver programmatically to get notified once an NFC tag is detected. As shown in my code I registered for the desired action and I created the broadcast receiver programmatically. I also added the required permission in the manifest file but the problem is that onReceive is never called.

Please let me know what I am doing wrong and how to fix it.

IntentFilter intentFilter1 = new IntentFilter();
intentFilter1.addAction("android.nfc.action.TAG_DISCOVERED");
registerReceiver(mBCR_TAG_DISCOVERED, intentFilter1);

private BroadcastReceiver mBCR_TAG_DISCOVERED = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        mTv.setText("mBCR_TAG_DISCOVERED");
    }
};

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="example.com.myapplication">

<uses-permission android:name="android.permission.NFC" />

<uses-feature
    android:name="android.hardware.nfc"
    android:required="true" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>

    </activity>
</application>

</manifest>
Merthiolate answered 13/1, 2017 at 10:45 Comment(8)
did u registered this in your Activity?Housekeeper
@Housekeeper yes as shown in my code above i registeredMerthiolate
in your Activity means in your onCreate() ?Housekeeper
@Housekeeper yes the registeration is done in oncreateMerthiolate
any log trace u getting ?Housekeeper
You are using intentFilter0 for the action..but using intentFilter1 for registering..?Terti
@AninditaPani no no it was a typo..i corrected itMerthiolate
@user2121 try my code.Housekeeper
B
14

The intent android.nfc.action.TAG_DISCOVERED, just as all NFC intents, is an activity intent and not a broadcast intent. It's simply not possible to register a broadcast receiver for it. What you can instead do is register an activity to receive NFC intents. This can be either done through the manifest, through the NFC foreground dispatch system, or on Android 4.4+ through the NFC reader mode API.

1. Manifest

Depending on what data is on your tag you would either want to register for the NDEF_DISCOVERED intent (if there is NDEF structured data on the tag) or for the TECH_DISCOVERED intent (if your just want to listen for certain tag technologies regardless of the data on the tags). You typically do not want to register for the TAG_DISCOVERED intent filter since that is only meant as a fallback mechanism (to catch events not handled by any other app) when used through the AndroidManifest.xml.

E.g. if your tag contains a URL http://www.example.com/, you could use the following intent filter:

<activity android:name=".MainActivity">
    ...
    <intent-filter>
        <action android:name="android.nfc.action.NDEF_DISCOVERED" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:scheme="http" android:host="www.example.com" />
    </intent-filter>
</activity>

If your tag does not contain any specific data and may be of any tag technology, you could use the following intent filter:

<activity android:name=".MainActivity">
    ...
    <intent-filter>
        <action android:name="android.nfc.action.TECH_DISCOVERED" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
    <meta-data android:name="android.nfc.action.TECH_DISCOVERED"
               android:resource="@xml/nfc_tech_filter" />
</activity>

For this intent filter to work, you will aslo need an XML resource xml/nfc_tech_filter.xml inside the res/ directory of your app. If the tech filter should match just any tag, that file would contain this:

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.NfcA</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcB</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcF</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcV</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcBarcode</tech>
    </tech-list>
</resources>

Once your activity is registered to receive those events, you can receive these intents within your activity through either onCreate() (if your activity is started by an NFC event) or through onNewIntent() (if your activity receives a subsequent NFC intent while open):

@Override
public void onCreate(Bundle savedInstanceState) {

    [...]

    Intent startIntent = getIntent();
    if ((startIntent != null) &&
        (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(startIntent.getAction()) ||
        NfcAdapter.ACTION_TECH_DISCOVERED.equals(startIntent.getAction()))) {
        // TODO: process intent
    }
}

@Override
protected void onNewIntent(Intent intent) {
    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()) ||
        NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {
        // TODO: process intent
    }
}

2. Foreground Dispatch System

If you are only interested in receiving NFC discovery intents while your activity is visible in the foreground, you are better off using the NFC foreground dispatch system instead of registering to receive NFC events through the manifest. You do this by registering your activity during onResume():

@Override
public void onResume() {
    super.onResume();

    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
    NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
    nfcAdapter.enableForegroundDispatch(this, pendingIntent, null, null);
}

You also have to make sure to unregister during onPause():

@Override
public void onPause() {
    super.onPause();
    NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
    nfcAdapter.disableForegroundDispatch(this);
}

You will then receive NFC events as TAG_DISCOVERED intents through onNewIntent():

@Override
public void onNewIntent(Intent intent) {
    if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
        // TODO: process intent
    }
}

3. Reader Mode API

If you are only interested in detecting NFC tags and only while your activity is visible in the foreground and you only need to target Android 4.4+, the best method is probably to use the NFC reader mode API. You do this by registering your activity during onStart():

@Override
public void onStart() {
    super.onStart();

    NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
    nfcAdapter.enableReaderMode(this, new NfcAdapter.ReaderCallback() {
        @Override
        public void onTagDiscovered(Tag tag) {
            // TODO: use NFC tag
        }
    }, NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_NFC_B | NfcAdapter.FLAG_READER_NFC_F | NfcAdapter.FLAG_READER_NFC_V | NfcAdapter.FLAG_READER_NFC_BARCODE, null);
}

You also should make sure to unregister during onStop():

@Override
public void onStop() {
    super.onStop();
    NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
    nfcAdapter.disableReaderMode(this);
}

You receive discovered tag handles through the onTagDiscovered(Tag tag) callback method.

Bunyan answered 13/1, 2017 at 15:18 Comment(2)
thanks a lot..i will study your answer and i will inform..regardsMerthiolate
Dear Michael, I'm using your solution for "any tag technology", but when I getTag I got the error of "no tech request available"Elum
S
0

In your onCreate method you can register a receiver like this:

 private BroadcastReceiver receiver;

@Override
public void onCreate(Bundle savedInstanceState){

 // your oncreate code should be

 IntentFilter filter = new IntentFilter();
 filter.addAction("SOME_ACTION");
filter.addAction("SOME_OTHER_ACTION");

 receiver = new BroadcastReceiver() {
 @Override
  public void onReceive(Context context, Intent intent) {
   //do something based on the intent's action
 }
 };
  registerReceiver(receiver, filter);
  }

Remember to run this in the onDestroy method:

 @Override
protected void onDestroy() {
if (receiver != null) {
 unregisterReceiver(receiver);
 receiver = null;
}
super.onDestroy();
}
Shannanshannen answered 13/1, 2017 at 10:58 Comment(1)
are u serious dude, u initializing reciever inside onCreate ?Housekeeper
E
0

You need to register your receiver in manifest also.You need not add action with receiver in menifest

Engage answered 13/1, 2017 at 10:58 Comment(1)
how can i do it pleaseMerthiolate
H
0

UPDATED

Add in your manifest:

<activity android:name=".MainActivity">
    <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.TECH_DISCOVERED" />
        <action android:name="android.nfc.action.TAG_DISCOVERED" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
Housekeeper answered 13/1, 2017 at 11:11 Comment(1)
still not wprkingMerthiolate
M
0

I guess you have a mistake : you are using intentFilter1 without action because the action is added to the intentFilter0 , try add the action to the intentFilter1 and run it.

Manheim answered 13/1, 2017 at 11:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.