androidkotlinnfcndef

Is it possible to read an NFC tag from a card without using an intent?


I am building an Android app using Kotlin. I should be able to read NFC tags by clicking a button. I see no way of doing this in all the documentation I have read.

What normally happens: set NFC token (card, chip, whatever) next to the Android device. Device opens the NFC app automatically. At this moment, the intent will be discovered and the card is read.

But how can I be in an application, have the token near the device, then click 'read' button and ONLY then read the information from the token?


Solution

  • There answer is yes and no, you can read cards without using an intent but that does not help with you reading on a button click but other changes mean you can only read the tag on a button click.

    You don't show your existing code of how you are getting the intent or describe what type of data you are reading, so the answer will be a bit vague.

    One point to clarify is that Tag Detection is always initiated by the Tag coming in to range and this is always the starting point of your code's interaction with the Tag BUT you can separate the reading from Tag Detection.

    So method of "detect and store"

    The first thing to do is use enableReaderMode to get a callback when a Tag is in range.

    e.g.

    public class NFCActivity extends AppCompatActivity implements NfcAdapter.ReaderCallback{
    
    private NfcAdapter mNfcAdapter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_nfc);
    
            mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
    
            // Rest of Activity setup
         }
    
    @Override
        protected void onResume() {
            super.onResume();
    
            if(mNfcAdapter!= null) {
                Bundle options = new Bundle();
                // Work around for some broken Nfc firmware implementations that poll the card too fast
                options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 250);
    
                // Enable ReaderMode for all types of card and disable platform sounds
                mNfcAdapter.enableReaderMode(this,
                        this,
                        NfcAdapter.FLAG_READER_NFC_A |
                                NfcAdapter.FLAG_READER_NFC_B |
                                NfcAdapter.FLAG_READER_NFC_F |
                                NfcAdapter.FLAG_READER_NFC_V |
                                NfcAdapter.FLAG_READER_NFC_BARCODE |
                                NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK |
                                NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS,
                        options);
            }
    
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            if(mNfcAdapter!= null)
                mNfcAdapter.disableReaderMode(this);
        }
    
    

    The sound on Tag detection is turned off and the automatic reading of any NDEF messages by the system is also turned off (so the user does not know about the tag detection)

    Then in onTagDiscovered callback method you just store the Tag object it gives you for later use when you press the button.

    The when you read the Tag, you use the stored Tag object and convert it in to one of the Tag tech types

    e.g.

    Ndef mNdef = Ndef.get(tag);
    
    // Check that it is an Ndef capable card
    if (mNdef!= null) {
     NdefMessage mNdefMessage = mNdef.getNdefMessage();
    }
    
    

    You will also have to handle a number of Exceptions as there is no guarentee the Tag is still in range when you press the button.

    You cannot really delay enabling detection until you click the button, because most likely the system will do something with the Tag instead if you have not asked for your running app to be sent the callback when it is detected.