Search code examples
androidandroid-intenttagsnfcndef

Read NDEF message from tag two times with one single touch (without moving phone)


I got everything successfully by reading the NDEF message from NFC tag. And after I read, I move the phone and it can read the tag again.

I'm using the onNewIntent and foregroundDispatch to handle the message.

The problem is: I want to read the same NFC tag twice (for security reasons) without moving the phone (without touching the tag a second time). So for a single touch, I want to read twice.

I try to see the life cycle but it seems if you do not move the phone, it will not issue a new intent again.

private NfcAdapter nfc = null;
private boolean inReadMode = false;
private boolean isNFC_support = false;
private PendingIntent mPendingIntent;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // ignore the unrelevent part of layout
    isNFC_support = true;
    nfc = NfcAdapter.getDefaultAdapter(this);
    if(nfc == null) {
        Toast.makeText(this, "Not support NFC device.", Toast.LENGTH_LONG).show();
        isNFC_support = false;
    }
    if(!nfc.isEnabled()) {
        Toast.makeText(this, "Please go the setting and enable NFC first.", Toast.LENGTH_LONG).show();
        isNFC_support = false;
    }
    if (isNFC_support == true) {
        mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
    }
}

@Override
protected void onNewIntent(Intent intent) {
    Log.i("NFC", "---- onNewIntent called ---- ");
    if (this.inReadMode && NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
        Log.i("NFC", "---- onNewIntent called ---- AND read nfc success!");
        try {
            readFromTag(intent);
        } catch (Exception e) {
            Log.e("NFC", "nfc cmac validate: ", e);
        }
    }
}

@Override
public void onResume() {
    super.onResume();
    Log.i("NFC", "---- onResume called ---- ");
    nfc.enableForegroundDispatch(this, mPendingIntent, null, null);
}


@Override
public void onPause() {
    Log.i("NFC", "---- onPause called ---- ");
    if (nfc != null) {
        nfc.disableForegroundDispatch(this);
    }
    if (isFinishing()) {
        cleanupReadingFromTag();
    }
    super.onPause();
}

private void readFromTag(Intent intent) throws RuntimeException, NoSuchAlgorithmException, IOException {
    Parcelable[] msgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
    // code I handle the message as I get. Not important for read twice I think?
}

So how can I read the tag again a second time?


Solution

  • The NFC intents are only dispatched upon detection of NFC tags. If a tag contains an NDEF message, that message is automatically processed and shared with your app in an intent extra (NfcAdapter.EXTRA_NDEF_MESSAGES).

    If you want to read from the tag again at a later stage (and managed to keep the NFC tag constantly connected), you will need to communicate with the tag directly. You can do this through the tag handle object. This object (class Tag) is also passed to your app upon tag detection (as an intent extra of the NFC intent):

    Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    

    while the tag is connected, you can use that object at any time to initiate communication with your tag. E.g. to freshly read the current NDEF message on the tag, you could use:

    Ndef ndef = Ndef.get(tag);
    if (ndef != null) {
        try {
            ndef.connect();
            NdefMessage msg = ndef.getNdefMessage();
            // do something with the NDEF message
        } catch (IOException e) {
        } finally {
            try {
                ndef.close();
            } catch (Exception e) {}
        }
    }