Reputation: 31649
I'm dealing with an Android NFC equiped device, just trying to read a tag and receive the information from an Activity. The tag is of the type MifareUltralight
. Just reading about that case in the Android docs it seems that I firstly have to register the Intent to launch my Activity in the manifest file and later on I'll be able to receive the NFC Intent from it. That's how my manifest file looks like:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mycompany.android">
<uses-feature android:name="android.hardware.nfc" android:required="false" />
<uses-permission android:name="android.permission.NFC" />
<application
android:allowBackup="true"
android:label="Test">
<activity
android:name="com.mycompany.android.activities.NfcTestActivity"
android:launchMode="singleTop"
android:label="Test">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED"/>
</intent-filter>
<meta-data android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/nfc_tech_filter" />
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I set the nfc feature as not required because is not essential for my app to work. Regarding to the NFC tech filters, that's my nfc_tech_filter.xml file:
<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>
Well, having configured that, it seems that my NfcTestActivity
should be able to receive NFC Intents. That's how I implement it:
public class NfcTestActivity extends Activity {
final String TAG = NfcTestActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "IntentAction (onCreate): " + getIntent().getAction());
NfcManager manager = (NfcManager) getSystemService(Context.NFC_SERVICE);
NfcAdapter adapter = manager.getDefaultAdapter();
if (adapter != null && adapter.isEnabled()) {
Log.i(TAG, "NFC adapter is enabled");
} else {
Log.i(TAG, "NFC adapter is disabled");
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.i(TAG, "IntentAction (onNewIntent): " + getIntent().getAction());
}
@Override
public void onResume() {
super.onResume();
Log.i(TAG, "IntentAction (onResume): " + getIntent().getAction());
}
}
When I start the application I get the following logs:
05-28 10:41:52.044 31182-31182/com.mycompany.android I/NfcTestActivity? IntentAction (onCreate): android.intent.action.MAIN
05-28 10:41:52.054 31182-31182/com.mycompany.android I/NfcTestActivity? NFC adapter is enabled
05-28 10:41:52.054 31182-31182/com.mycompany.android I/NfcTestActivity? IntentAction (onResume): android.intent.action.MAIN
Later on, I read my tag and this log is shown:
05-28 10:41:59.661 31182-31182/com.mycompany.android I/NfcTestActivity? IntentAction (onResume): android.intent.action.MAIN
This means the Activity#onResume
method being called when the tag is read, as the documentation says, however, what I get here is an android.intent.action.MAIN
instead of the NFC one (ACTION_NDEF_DISCOVERED
, ACTION_TECH_DISCOVERED
or ACTION_TAG_DISCOVERED
).
Moreover, as a clue, when I remove this code piece from my Activity declaration, no onResume
log appears when I read the tag:
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
</intent-filter>
So it seems the TAG_DISCOVERED
action is definitelly launched in some way, not the other ones, but I cannot properly catch it from the Activity.
Does anybody know about that?
Upvotes: 2
Views: 708
Reputation: 40831
First of all, your nfc_tech_filter.xml is not correct. The filter
<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>
means that you want to match a tag that is IsoDep
and NfcA
and NfcB
and NfcF
and ... However, the NfcX
tag technologies are mutually exclusive to each other (so are Ndef
and NdefFormatable
), so the filter will not match any tag. What you would actually want is something like that:
<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>
Which would just match any tag technology. Or if you want to only match MifareUltralight
, you could simply use:
<tech-list>
<tech>android.nfc.tech.MifareUltralight</tech>
</tech-list>
Using the TAG_DISCOVERED intent filter is generally not a good idea. It is only meant as a fallback and for backward compatibility with the first Android NFC API.
When you want to receive NFC intents while your app is in the foreground, it is generally better to register for the foreground dispatch system, instead of relying on intent filters in the app's manifest. This will assure that your activity receives the events and that no activity chooser is shown even if another app also has intent filters for these events.
Upvotes: 1
Reputation: 31649
After some brainstorming, I've realized that defaulting android.nfc.action.TAG_DISCOVERED
instead of android.nfc.action.NDEF_DISCOVERED
does the work for me:
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
I still don't know why I should go with TAG_DISCOVERED
when my tag type is covered by TECH_DISCOVERED
, which is preferable to use. Anyway, that's the code I use to get the tag id later on:
@Override
public void onResume() {
super.onResume();
Log.d(TAG, "onResume: action-"+getIntent().getAction());
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(getIntent().getAction())) {
Tag tag = getIntent().getParcelableExtra(NfcAdapter.EXTRA_TAG);
String tagId = bytesToHexString(tag.getId());
Log.i(TAG, "NFC tag: " + tagId);
}
}
See also:
Upvotes: 2