Get Nfc Tag with Ndef Android Application Record (Aar)

Get NFC tag with NDEF Android Application Record (AAR)

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:

  1. 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.
  2. 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).

How to redirect the AAR on an NFC tag to a new application ID?

No, it's not possible to start your new app with that tag. The whole idea of the Android Application Record (AAR) is to prevent exactly that (see NFC Basics):

[... an AAR] provides a stronger certainty that your application is started when an NFC tag is scanned. [...] AARs are useful if you want to prevent other applications from filtering for the same intent and potentially handling specific tags that you have deployed.

Hence, if you want to launch your app using the NFC tag, the only option is to replace the data on the tag (or the whole tag, in case it's write locked).

However, if you only want to read the tag while your (new) app is already open in the foreground, you could use the foreground dispatch system or reader mode to overrride that behavior and force Android to dispatch the tag discovery event to your (new) app. See Using the Foreground Dispatch System.

How do I write an Android Application Record (AAR) using phonegap?

The answer is to write an TNF_EXTERNAL_TYPE record based on the spec found here

nfc.addNdefListener( function(nfcEvent) {

var tag = nfcEvent.tag, ndefMessage = tag.ndefMessage;

if (tag.isWritable && tag.canMakeReadOnly) {
log( JSON.stringify( tag ) );

var type = "application/com.example.name",
id = 1234,
payload = nfc.stringToBytes( JSON.stringify( { payloadID : 1234 } ) ),
mime = ndef.record( ndef.TNF_MIME_MEDIA, type, id, payload );

var type = "android.com:pkg",
id = "",
payload = nfc.stringToBytes( "com.example.name" ),
aar = ndef.record( ndef.TNF_EXTERNAL_TYPE, type, id, payload);

var message = [ mime, aar ];

nfc.write( message, function() {
alert( "Successfully written to NFC Tag!" )
}, function() {
alert( "Failed to write to NFC Tag!" )
} );
}

}, function() { // success callback
log( "Waiting for NDEF tag" );
}, function(error) { // error callback
alert( "Error adding NDEF listener " + JSON.stringify( error ) );
} );

Android NFC passing single parameter when starting application

Android will automatically read the NDEF message of an NFC tag and process it in order to

  • start registered activities based on the first NDEF record, and
  • start apps based on Android Application Records (AAR) anywhere in the NDEF message.

In order to get your activity started and have Android pass the pre-read NDEF message, you could use the NDEF_DISCOVERED intent filter:

<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="/example.com:mycustomtype"/>
</intent-filter>

Then from within your activity, you could process that NDEF message:

public void onResume() {
super.onResume();
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
NdefMessage[] msgs = null;
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawMsgs != null) {
msgs = new NdefMessage[rawMsgs.length];
for (int i = 0; i < rawMsgs.length; ++i) {
msgs[i] = (NdefMessage)rawMsgs[i];
}
}

if ((msgs != null) && (msgs.length > 0)) {
NdefRecord[] records = msgs[0].getRecords();
NdefRecord firstRecord = records[0];
byte[] payloadData = firstRecord.getPayload();

// do something with the payload (data passed through your NDEF record)
// or process remaining NDEF message

}
}
}

Note that onResume() is run whenever your activity becomes the foreground activity. Hence, it might be run multiple times for the same tag. THerefore, you could either use another life-cycle method or take some precautions that you do not parse the message multiple times.

If you want to drop all further NFC events, once your activity is open, you could follow the approach that I described in response to Android app enable NFC only for one Activity. Hence, you would register for the foreground dispatch (which gives your activity priority in receiving NFC events, and you can then simply drop those events.

public void onResume() {
super.onResume();
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
nfcAdapter.enableForegroundDispatch(this, pendingIntent, null, null);
}

public void onPause() {
super.onPause();
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
nfcAdapter.disableForegroundDispatch(this);
}

public void onNewIntent(Intent intent) {
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
// drop NFC events
}
}

Finally, to create the NDEF message for your NFC tag, you would do something like this:

byte[] payload = ...  // generate your data payload
NdefMessage msg = new NdefMessage(
NdefRecord.createExternal("example.com", "mycustomtype", payload)
)

If you want to make sure that only your app is started by this tag (or if not installed Play Store is opened for your app), you could also add an AAR:

NdefMessage msg = new NdefMessage(
NdefRecord.createExternal("example.com", "mycustomtype", payload),
NdefRecord.createApplicationRecord("com.example.your.app.package")
)

Android NFC start app (using AAR) and read text

To make sure that you also receive the NDEF message, make sure that you have added an Intent filter for the type of message that is on the tag.

How can I get the multiple NFC record after launching the app by AAR

the app which read NFC tag must have two intent-filter sepearately
my intent-filter in Manifest.xml is below

<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.MAIN" />

</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/org.leonehouse.nfc" />
</intent-filter>

Android: NFC: AAR and data: Starting an application with extra data

I have created an NFC Eclipse plugin exactly for this scenario. You will also find an Android boilerplate project in the downloads section for the same project.

You might want to check out NDEF Tools for Android, and do a search on the app store for read and write apps.



Related Topics



Leave a reply



Submit