From the code that you posted in your question, I assume that you did not register your application to send a specific NDEF message. In that case, if your app is open on one device, Android will automatically Beam an NDEF message containing a URI record with the Play Store link of your app and an Android Application Record (AAR) to the other device.
So your second device will receive the following NDEF message:
+---------------------------------------------------------------------------------------+
| WKT:URI | http://play.google.com/store/apps/details?id=your.package.name&feature=beam |
+---------------------------------------------------------------------------------------+
| EXT:android:com:pkg | your.package.name |
+---------------------------------------------------------------------------------------+
What happens now if your app is not already open on the second device is, that the Android Application Record (second record) will force your app to be started. However, looking at your manifest, you do not have an intent filter that matches the first record of this NDEF message (the Play Store URL). Consequently, Android thinks that you do not expect an NDEF message and uses the standard android.intent.action.MAIN
(with category android.intent.category.LAUNCHER
) to start your app (or rather the first activity of your app that has an intent filter for action MAIN
with category LAUNCHER
).
In order to receive an NFC intent together with the whole NDEF message in your app, you would need to define a proper intent filter that matches the first record in the above NDEF message:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http"
android:host="play.google.com"
android:pathPrefix="/store/apps/details?id=your.package.name" />
</intent-filter>
Now, Android will recognize that your app/activity is ready to receive an NFC intent and pass the NDEF_DISCOVERED
intent to your activity. Note that you still won't receive that intent through onNewIntent()
if your app is not already running. Instead you can get the intent that started your activity with the activity's getIntent()
method. E.g. in onCreate
/onStart
/onResume
, you could use
Intent intent = getIntent();
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
NdefMessage ndefMessage = null;
Parcelable[] rawMessages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if ((rawMessages != null) && (rawMessages.length > 0)) {
ndefMessage = (NdefMessage)rawMessages[0];
}
// TODO: do something with the received NDEF message
}
to get the intent and the NDEF message.
Regarding the intent filters you already have in your manifest:
NDEF_DISCOVERED
:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
An NDEF_DISCOVERED
intent filter without a <data ... />
tag will never trigger on many NFC devices. You should always define what specific data you expect to be present in the launching NDEF record.
TECH_DISCOVERED
:
<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" />
You should only use this intent filter if you wan't you application to be started upon detection of a certain NFC tag technology (you define the specific technologies in the nfc_tech_filter.xml
file. For your Beam scenario, you would not use such an intent filter. Btw. the <category ...>
tag is not used for this intent filter.
TAG_DISCOVERED
:
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
This intent filter should normally not be used in the manifest. It is meant as a fallback that triggers if no other app could possibly handle a detected NFC tag. Using this can lead to bad user-experience (e.g. your app being started for tags it can't or does not actually want to handle). It is primarily available for backward compatibility with API level 9 (?).
In order to also catch the NFC intents if your activity is already started, you could register for the foreground dispatch like this (in the onResume
method):
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
nfcAdapter.enableForegroundDispatch(this, pendingIntent, null, null);
That way, you will receive any NFC discovery events that occur while your activity is in the foreground in your activity's onNewIntent
method. They will be dispatched through an ACTION_TAG_DISCOVERED
intent.