programmerboy programmerboy - 4 months ago 20
Android Question

Launch Specific App when NFC is discovered

I am using NFC in my app and it is working fine. However I want to make sure that only my app is launched and no other App is there to handle the intent. Following is the code for it in my Manifest file:

<activity android:name="com.mypackage.name.BeamActivity">
<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>


I have another sample app on my phone which is detecting NFC Intent and providing me Intent Chooser. Following is the code for it in Manifest file.

<activity android:name="com.package2.name.NFCStickyNotesActivity" android:label="Sticky Notes" >
<!-- Handle notes detected from outside our application -->
<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>


I would like my App to be the only app to handle the particular NFC Intent when my App push it across from another device.

I am not sure whether I have to do something specific in the manifest file or in the code. Any help is appreciated.

Answer

The reason why you get an intent chooser is that multiple activities are registered for the data type text/plain. This is a rather common case and you should therefore avoid using such generic data types for the NDEF record that should launch your activity. You have two options to overcome this problem:

  1. Use an NFC Forum external type for your NDEF record (this is what ThomasRS already mentioned). With this method you create a custom record type that is meaningful to your application only. You can create such a record (to write it to your tag or to send over Beam) with something like this:

    NdefRecord extRecord = NdefRecord.createExternal(
            "yourdomain.com",  // your domain name
            "yourtype",        // your type name
            textBytes);        // payload
    

    You can then register your activity to launch upon this record like this:

    <activity ...>
        <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:yourtype" />
        </intent-filter>
    </activity>
    
  2. Use an Android Application Record (AAR). An AAR will make sure that the NDEF_DISCOVERED intent is delivered to an app with a specific package name only. You can create such a record (to write it to your tag or to send over Beam) with something like this:

    NdefRecord appRecord = NdefRecord.createApplicationRecord(
            "com.yourdomain.yourapp");
    NdefRecord textRecord = NdefRecord.createTextRecord(
            "en",       // language code
            "yourtext"  // human-readable text);
    NdefMessage msg = new NdefMessage(
            textRecord,
            appRecord);  // use the AAR as the *last* record in your NDEF message