Android NFC passing single parameter when starting application
Asked Answered
S

1

5

I would like to start an application using an NFC tag. I got that part working using an android application record (AAR) as described in Start Android application from NFC-tag with extra data or by using NDEF_DISCOVERED / TECH_DISCOVERED intent filters. But how do I pass data from the NFC tag (e.g. some text) to my activity upon starting it through the NFC event?

I've read through NFC Basics, but as far as I understand that it seems to want to implement a mechanism for reading the tag, when I really do not want to re-read the tag once the app is opened by the tag, but instead I just want the data passed in at the same time.

Moreover, these mechanisms seem to allow the app to read the tag after it has been started by the tag. In other words, I am worried that if someone hits the tag later when the app is already opened that tag will be read again (which is what I do not want).

Second, how do I create such NDEF message?

Sodom answered 15/6, 2015 at 4:33 Comment(10)
Where should the data für your app come from? From the NFC tag or somewhere else?Prevention
Did you read developer.android.com/guide/topics/connectivity/nfc/nfc.html?Cauca
corvairjo - The data will come from the NFC tag. So I want the NFC tag to start the app (which is fairly easy) and then pass in a string (which is what I find confusing).Sodom
@MichaelRoland - Yes, did read it. My problem with it (probably my misunderstanding) is that it seems to want to implement a mechanism for reading the tag, when I really do not want to re-read the tag once the app is opened by the tag - I just want the data passed in at the same time. In other words I am worried that if someone hits the tag later when the app is already opened that tag will be triggered again (which I do NOT want).Sodom
@StephenMcCormick So for the first part (getting a data parameter from the tag), you want to do what is described in Obtaining information from intents. That processes the NDEF message that was read by Android and that was passed to your app in the intent.Cauca
@StephenMcCormick Regarding the second part (stop receiving NFC events once your activity is open/in the foreground), you would want to read my answer to this question.Cauca
@MichaelRoland Awesome! Think I am almost there...but will this restrict usage of NFC everywhere else in the app? I do have a control that allows the user to provide NFC text (sort of like reading a barcode) later in the application...they enter that "field" and it then performs the scan of the NFC looking for text. Sorry - sounds like I want my cake and to eat too! :)Sodom
You would need to use that "foreground dispatch -> drop" approach on every activity in your app where tags should not be detected.Cauca
@MichaelRoland. Thanks. That should work perfectly since I only have those one place where I am attempting to read NFC tags. Appreciate the insights!Sodom
@StephenMcCormick I modified your question based on your comments, please check and edit if I missed anything.Cauca
C
8

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")
)
Cauca answered 16/6, 2015 at 5:58 Comment(2)
Perfect! Probably be implementing this next week and will update with what I find out. Thanks for the help!Sodom
@Michael Roland "..onResume() is run whenever your activity becomes the foreground activity...." How can we handle it i spend a lot of hours to figure it out? any idea ?Blouson

© 2022 - 2024 — McMap. All rights reserved.