Search code examples
androidnfcintentfilterndefandroid-beam

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.


Solution

  • 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