I am trying to write a simple application to interact with NFC tags, but I cant seem to get my phone to do anything but trigger the default NFC tag app. I really just want to be able to intercept any tag I scan, determine if it has some data on it, and take action accordingly.
Right now my manifest file looks like
<uses-sdk android:minSdkVersion="10" />
<uses-feature android:name="android.hardware.nfc" android:required="true"/>
<uses-permission android:name="android.permission.NFC"/>
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name=".NfcActivity"
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"/>
</intent-filter>
</activity>
</application>
However when scanning an NFC tag, I never see the activity start. Am I missing something here? I tried placing the intent filter inside a BroadcastReceiver and had no luck either...
You cannot have your app started by all NFC tags you scan. Android will determine what the most suitable app is based on how specific the intent filter is. However, if your app is running in the foreground, you can use NFC foreground dispatch to catch all NFC intents.
In onCreate() add:
mAdapter = NfcAdapter.getDefaultAdapter(this);
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
In onResume() add:
mAdapter.enableForegroundDispatch(this, pendingIntent, null, null);
In onPause() add:
mAdapter.disableForegroundDispatch(this);
In onNewIntent you can get at the NFC tag like this:
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
The SDK docs show this as a basic example.
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain" />
</intent-filter>
You are expecting the tags to be defined in NDEF format. So your program will only be launched if the tags being read is in NDEF format.
You can try more generic intent filters like TAG_DISCOVERED or TECH_DISCOVERED.
Android automatically choses the most relevant application to handle the scanned NFC tag. You need to be more specific in your intent-filter, i.e. only listen for TEXT-Tags, URL-Tags, or CONTACT-Tags. This can be done by further specifying the filter, using, your example, <data android:mimeType="text/plain" /> for TEXT-Tags. Otherwise, the default NFC-Tag app will be triggered.
Related
I am working on an NFC-application. To start my app, I am using a NDEF-tag with an AAR NDEF Record inside.
This works fine. But now I want to read the tag content with the app directly. How can I do this?
(It already works, when I remove the tag from the phone and touch it again, but I want to eliminate this step.)
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="nfctagscanner.mobileapps.lt.nfctagscanner" >
<uses-feature android:name="android.hardware.nfc" android:required="true"/>
<uses-permission android:name="android.permission.NFC" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".NFCScanActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="nfctagscanner.mobileapps.lt.nfctagscanner" android:host="ext"
android:pathPrefix="/android.com:pkg" />
</intent-filter>
</activity>
</application>
</manifest>
And I just want to get NDEF_DISCOVERED intent. But I always get action.MAIN/category.LAUNCHER Intent with my debugger.
Any help will be appreciated. I was doing my work based on this: Android / NFC: Get Tag in onCreate() without new Intent
If you want your app to be started by your tag and want to receive the parsed NDEF message, your tag should contain the following:
An NDEF record that you want to filter upon as the first record of the NDEF message (you can only create intent-filters for the very first NDEF record on an NFC tag). Given your own answer, this would be a Text record (or a MIME type record with MIME type text/plain) in your case. However, you might want to consider using an NFC Forum external type record with your custom application-specific type name instead (see here as this would allow your app to better distingush your tags from tags used with other apps. The Text record should only be used if it contains human-readable non-interpreted text.
If you want to make sure that only your app is started with the tag and that your app's Play Store page is automatically opened if the user does not have the app installed, then you should also use an Android Application Record (AAR). This record should be the last record in the NDEF message. (Note that an AAR will be honored regardless of the position in the NDEF message, but using it as the first record will cause the problem described in the post you linked in your question.)
Once, you have your tag containing a proper NDEF message ready, you have to create an appropriate intent filter for the activity that should receive the tag discovery event and the NDEF message that triggered it:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
Or if you used your custom NFC Forum external type:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="vnd.android.nfc"
android:host="ext"
android:pathPrefix="/yourdomain.com:yourtypename"/>
</intent-filter>
If your app does not have an NDEF_DISCOVERED intent filter that matches the first record of the NDEF message on your tag and your tag contains an Android Application Record, the first activity declared in your manifest that has an intent filter for android.intent.action.MAIN and with android.intent.category.LAUNCHER will be started. As that activity, therefore, does not declare to expect an NFC intent it will be passed the android.intent.action.MAIN (which does not contain the NDEF message/tag handle).
I don't know if this is correct answer but I found a fix:
<activity
android:name=".NFCScanActivity"
android:label="#string/app_name" >
<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>
I am working on an NFC-application. To start my app, I am using a NDEF-tag with an AAR NDEF Record inside.
This works fine. But now I want to read the tag content with the app directly. How can I do this?
(It already works, when I remove the tag from the phone and touch it again, but I want to eliminate this step.)
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="nfctagscanner.mobileapps.lt.nfctagscanner" >
<uses-feature android:name="android.hardware.nfc" android:required="true"/>
<uses-permission android:name="android.permission.NFC" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".NFCScanActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="nfctagscanner.mobileapps.lt.nfctagscanner" android:host="ext"
android:pathPrefix="/android.com:pkg" />
</intent-filter>
</activity>
</application>
</manifest>
And I just want to get NDEF_DISCOVERED intent. But I always get action.MAIN/category.LAUNCHER Intent with my debugger.
Any help will be appreciated. I was doing my work based on this: Android / NFC: Get Tag in onCreate() without new Intent
If you want your app to be started by your tag and want to receive the parsed NDEF message, your tag should contain the following:
An NDEF record that you want to filter upon as the first record of the NDEF message (you can only create intent-filters for the very first NDEF record on an NFC tag). Given your own answer, this would be a Text record (or a MIME type record with MIME type text/plain) in your case. However, you might want to consider using an NFC Forum external type record with your custom application-specific type name instead (see here as this would allow your app to better distingush your tags from tags used with other apps. The Text record should only be used if it contains human-readable non-interpreted text.
If you want to make sure that only your app is started with the tag and that your app's Play Store page is automatically opened if the user does not have the app installed, then you should also use an Android Application Record (AAR). This record should be the last record in the NDEF message. (Note that an AAR will be honored regardless of the position in the NDEF message, but using it as the first record will cause the problem described in the post you linked in your question.)
Once, you have your tag containing a proper NDEF message ready, you have to create an appropriate intent filter for the activity that should receive the tag discovery event and the NDEF message that triggered it:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
Or if you used your custom NFC Forum external type:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="vnd.android.nfc"
android:host="ext"
android:pathPrefix="/yourdomain.com:yourtypename"/>
</intent-filter>
If your app does not have an NDEF_DISCOVERED intent filter that matches the first record of the NDEF message on your tag and your tag contains an Android Application Record, the first activity declared in your manifest that has an intent filter for android.intent.action.MAIN and with android.intent.category.LAUNCHER will be started. As that activity, therefore, does not declare to expect an NFC intent it will be passed the android.intent.action.MAIN (which does not contain the NDEF message/tag handle).
I don't know if this is correct answer but I found a fix:
<activity
android:name=".NFCScanActivity"
android:label="#string/app_name" >
<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>
I am developing an application for NFC.
On the tags, we have an application record, what is starting our application, and a text record, what has an id. When my app is reading the textrecord, send a request through the net to our server, get the response, and do things, like show buttons, doesn't matter.
When i started to learn android, i learned, there is a good thing to use a general engine, what has a lot of tool for myself, so when i need a new app, i can reuse my engine functions.
So, i've created this GameEngine class as a separated project.
I tried it without TAG_DISCOVERED filter, also tried when i've give not the text/plain mime type, but my application.
package GameEngine;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public abstract class GameEngine extends Activity {
private final String TAG = "DH GAME ENGINE";
/**************************************************
* Here are the override methods
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "Engine constructor");
super.onCreate(savedInstanceState);
init();
}
public abstract void init();
//MORE overrides here...
}
In my app, i have the init function. Here i set up the layout, set some flags.
In the onNewIntent method, i have this piece of code:
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
Log.d(TAG, "A tag was scanned!");
GEPhone.vibrate(this, 500);
tagSerial = GENFC.getTagId(getIntent());
}
It's works great. After this i read my id and parse it. I am using ndef-tools to parse the NDEF messages, but i think this is does not matter.
My problem is, when i am on the home screen, and my application is not running, when i first tap the NFC with the phone, my application is starting, but sadly, the onNewIntent method does not run.
I tried to search for it, i know, i am not the first who has this problem, and i read everywhere, i shoul add to this to the AndroidManifest.xml:
android:launchMode="singleTop"
No change.
Now, i also tried something else. I outsourced the whole thing from the onNewIntent into a handleIntent method, so my onNewIntent now seems like this:
#Override
public void onNewIntent(Intent intent) {
Log.d(TAG, "onNewIntent");
// Set the intent
setIntent(intent);
handleIntent(intent);
}
And i am also calling the this handleIntent from the init method.
But the result are the same.
If i am calling this handlentent from the init like this:
handleIntent(getIntent());
For some reason, this condition will be false.
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
....
}
What do i wrong?
PS: my other problem is, i can not debug this whole thing, because if i am clicking the debug button in the eclipse, it's starts the application, so i can not simulate, what happens (with breakpoints), when the application starts because of the NFC tag starts it.
Ps2: now logged, what is the action when i start the application and it is:
Main activity(29861): Action is: android.intent.action.MAIN
UPDATE
After some researching, and playing with the settings, now i realized the following:
If i am using this in manifest:
android:launchMode="singleTask"
and this filter:
<category android:name="android.intent.category.DEFAULT" />
<!-- <data android:mimeType="*/*" /> -->
<data android:mimeType="application/hu.sma.htdalpha" />
</intent-filter>
and data type is */*, then everything is work fine, except, all TAG is opening my application, even if there are only a text like "adsdasd".
If i am using my own package, then apllications open, and action will be android.intent.action.MAIN again.
UPDATE 2
As Michael asked, i copy here the AndroidManifest.xml.
The description above is a littlebit confusing. The point of the problem, as i read about it, that something not ok with the intents. The package name is ok, but every time, every where onCreate, onNewIntent, onStart, onResume, everywhere if i Log.d the getIntent().getAction(), will be android.intent.action.MAIN, and android.nfc.action.NDEF_DISCOVERED is never triggered. Only, if the application was started once.
The NDEF seems like this (see image)
The manifest is this.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="hu.sma.htdalpha"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="16" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="hu.sma.htdalpha.MainActivity"
android:label="#string/app_name"
android:launchMode="singleTask" >
<!--
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/hu.sma.htdalpha" />
</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>
<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>
First of all, if you want your app to be started by your tag and want to receive the parsed NDEF message, your tag should contain the following:
An NDEF record that you want to filter upon as the first record of the NDEF message (you can only create intent-filters for the very first NDEF record on an NFC tag). In your case this would be the Text record. However, you might want to consider using an NFC Forum external type record with your custom application-specific type name instead (see here. The Text record should only be used if it contains human-readable non-interpreted text.
If you want to make sure that only your app is started with the tag and that your app's Play Store page is automatically opend if the user does not have the app installed, you can use an Android Application Record (AAR). This record should be the last record in the NDEF message. An AAR will be honored regardless of the position in the NDEF message.
Next, you have to create an appropriate intent filter for the activity that should receive the tag dicovery event and the NDEF message that triggered it:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
Or if you used your custom NFC Forum external type:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="vnd.android.nfc"
android:host="ext"
android:pathPrefix="/yourdomain.com:yourtypename"/>
</intent-filter>
If your app does not have a matching intent filter and your tag contains an Android Application Record, the first activity declared in your manifest that has an intent filter for android.intent.action.MAIN and with android.intent.category.LAUNCHER will be started and as it does not declare to expect an NFC intent it will be passed the android.intent.action.MAIN. That's what happened in your case.
Next, in your activity, you can receive the NFC intent (with getIntent()) in onCreate(), onStart(), etc. and forward it to your handleIntent(...) method. As you filtered for NDEF_DISCOVERED, you will receive an NDEF_DISCOVERED intent. Thus you would use something like this:
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
// do something
}
If you want to receive further NFC intents while your activity is already in the foreground, you can handle them in onNewIntent(). This method will only be called if you added the proper launchMode to your activity). Better yet you can register for the foreground dispatch to give your activity priority for receiving NFC events.
Finally, you should normally not use the TAG_DISCOVERED intent in your manifest. This intent filter is meant as a fallback (if no other app's NFC intent filter matches) and to be backward compatible to the first edition of the NFC API (in Android 2.3). Moreover it is used for the catch-all version of the foreground dispatch.
I'm trying to receive a simple custom intent, based on my wn URI.
Here is my manifest:
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.intenttest.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name="com.example.intenttest.TestReceive"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="testo" />
</intent-filter>
</receiver>
</application>
My receiver is extremely simple:
public class TestReceive extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent arg1) {
Log.d("", "YAY!!!!!");
Toast.makeText(context, "TEST!!!", Toast.LENGTH_LONG).show();
}
}
When I try browsing to testo://blahblah, or fir this intent via URI Launer my receiver is not being fired.
Here is the code to simulate firing the intent from a different app:
String url = "testo://test/test";
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
sendBroadcast( i );
But when I move the <intent-filer> block to the <activity> tag in the manifest, the activity IS being fired.
How can I make my receiver receive the intent?
If you are trying to dynamically register a receiver you should do so programmatically. This example by Eric Nordvik will server you well!
Now, the main reason to do it this way is because it is straight forward. The downside is that you won't be able to receive broadcasts when your application's lifecycle is not currently active (paused, stopped).
Update: As read in the comments, the OP requires to receive broadcasts independent of the lifecycle of the activity. I would urge anyone to rethink his design and only then decide if it is really needed.
As specified by the official documentation, android:name is used to designate the name of the class that implements the BroadcastReceiver. Omitting it in your code means that the Activity itself will receive the broadcast. I believe your issue is that you did not fully qualify it by android:name but referred to it as name. Fixing it should also fix your problem!
Update: The OP has since corrected a typo and this is not the issue. At this point, my best guess is either that the broadcast is generated wrongly or that the reference to the BroadcastReceiver should use the shorthand notation android:name=".NameOfReceiverClass".
OK - This whole issue was probably caused by me taking the wrong approach.
The sample code for sending the intent DOES work and does initiate my receiver.
So it appears that most QR Readers in the market do not fire an intent with the QR-read URI, as in my sample code, but rather look for an Activity that should respond to it and then call it directly.
I have no idea why is this the case.
The solution was to create a silent Activity, that handles what the BroadcastReceiver was supposed to handle.
Oy vey.
I am working on Near Field Communication for reading data from NFC Tags.
I don't have NFC supported Android Mobile and NFC Tags to test the Application i created .
I want to know whether it is possible to Launch my App through intent filter(Should assume NFC tag is detected from my device)
My Manifest Snippet :
<activity
android:name=".ServerActivity"
android:label="#string/app_name"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="abc.com"
android:pathPrefix="/aaap"
android:scheme="http" />
</intent-filter>
</activity>
My Activity Snippet :
#Override
protected void onNewIntent(Intent intent) {
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
Toast.makeText(getApplicationContext(), "ACTION_TAG_DISCOVERED",
Toast.LENGTH_LONG);
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
}
}
I may be completely missing the point here, but from what I understood, you basically want to fire off an intent that will get picked by the receiver you declared in your manifest, right? Have you tried setting up a very simple test app that does exactly this using the sendBroadcast(...) method?
Intent exampleIntent = new Intent("android.nfc.action.NDEF_DISCOVERED");
sendBroadcast(exampleIntent)
You can add any extra data to the Intent per your requirements.
After some research on NFC i found that we can read/write NFC Tags without NFC enabled device.. But answer is so simple.. It's nothing but playing with Intents :
We have to call this snippet for invoking NFC :
final Intent intent = new Intent(NfcAdapter.ACTION_TAG_DISCOVERED);
intent.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, "Custom Messages");
startActivity(intent);
Also we should register our Activity to Android System through Manifest file like below :
Manifest.xml
<activity
android:name="TagViewer" >
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Same way if you have more than one Activity using same action we will be getting chooser from which we can launch our Desired Activity.
Receiving inside Activity :
TagViewer .java
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(getIntent().getAction())) {
Log.v("NFC Launched","NFC Launched");
}
We have this sample in Developer Sample Demo.
Have a look at Open NFC. They have a NFC simulator that migh be useful to attach to your android simulator. Never used it with Android, but I've used it with BlackBerry simulators.
EDIT:
Last version 4.4.1 for Android ICS released.