简体   繁体   中英

Should I tap NFC tag every time I want to write in it?

I'm an android developer

I have an idea to develop an application that writes on NFC tags data. (Only writing) I have an Edit Text and a button and when I click on the button I write on the NFC the data written in the field I searched a lot and tried several codes The only problem is my NFC tags sticks in the back of the phone and the code i'm using tells me I have to tap/tag the NFC tag to write in it Is there another way to detect the NFC tag sticked on the back of the phone when clicking the button?

I have two activities main activity that will call methods from my NFCManager I will share below the NFCManager class NFCManager class:

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.nfc.tech.NdefFormatable;

import java.io.ByteArrayOutputStream;
import java.util.Locale;

public class NFCManager {
    private Activity activity;
    private NfcAdapter nfcAdpt;

    public NFCManager(Activity activity) {
        this.activity = activity;
    }

    public void verifyNFC() throws NFCNotSupported, NFCNotEnabled {

        nfcAdpt = NfcAdapter.getDefaultAdapter(activity);

        if (nfcAdpt == null)
            throw new NFCNotSupported();

        if (!nfcAdpt.isEnabled())
            throw new NFCNotEnabled();

    }

    public void enableDispatch() {
        Intent nfcIntent = new Intent(activity, getClass());
        nfcIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(activity, 0, nfcIntent, 0);
        IntentFilter[] intentFiltersArray = new IntentFilter[] {};
        String[][] techList = new String[][] { { android.nfc.tech.Ndef.class.getName() }, { android.nfc.tech.NdefFormatable.class.getName() } };


        nfcAdpt.enableForegroundDispatch(activity, pendingIntent, intentFiltersArray, techList);
    }

    public void disableDispatch() {
        nfcAdpt.disableForegroundDispatch(activity);
    }

    public static class NFCNotSupported extends Exception {

        public NFCNotSupported() {
            super();
        }
    }

    public static class NFCNotEnabled extends Exception {

        public NFCNotEnabled() {
            super();
        }
    }


    public void writeTag(Tag tag, NdefMessage message)  {
        if (tag != null) {
            try {
                Ndef ndefTag = Ndef.get(tag);

                if (ndefTag == null) {
                    // Let's try to format the Tag in NDEF
                    NdefFormatable nForm = NdefFormatable.get(tag);
                    if (nForm != null) {
                        nForm.connect();
                        nForm.format(message);
                        nForm.close();
                    }
                }
                else {
                    ndefTag.connect();
                    ndefTag.writeNdefMessage(message);
                    ndefTag.close();
                }
            }
            catch(Exception e) {
                e.printStackTrace();
            }
        }
    }

    public NdefMessage createUriMessage(String content, String type) {
        NdefRecord record = NdefRecord.createUri(type + content);
        NdefMessage msg = new NdefMessage(new NdefRecord[]{record});
        return msg;

    }

    public NdefMessage createTextMessage(String content) {
        try {
            // Get UTF-8 byte
            byte[] lang = Locale.getDefault().getLanguage().getBytes("UTF-8");
            byte[] text = content.getBytes("UTF-8"); // Content in UTF-8

            int langSize = lang.length;
            int textLength = text.length;

            ByteArrayOutputStream payload = new ByteArrayOutputStream(1 + langSize + textLength);
            payload.write((byte) (langSize & 0x1F));
            payload.write(lang, 0, langSize);
            payload.write(text, 0, textLength);
            NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload.toByteArray());
            return new NdefMessage(new NdefRecord[]{record});
        }
        catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public NdefMessage createExternalMessage(String content) {
        NdefRecord externalRecord = NdefRecord.createExternal("com.survivingwithandroid", "data", content.getBytes());

        NdefMessage ndefMessage = new NdefMessage(new NdefRecord[] { externalRecord });

        return ndefMessage;
    }
}

Methods from my MainActivity:

@Override
protected void onResume() {
    super.onResume();

    try {
        nfcMger.verifyNFC();
        //nfcMger.enableDispatch();

        Intent nfcIntent = new Intent(this, getClass());
        nfcIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, nfcIntent, 0);
        IntentFilter[] intentFiltersArray = new IntentFilter[] {};
        String[][] techList = new String[][] { { android.nfc.tech.Ndef.class.getName() }, { android.nfc.tech.NdefFormatable.class.getName() } };
        NfcAdapter nfcAdpt = NfcAdapter.getDefaultAdapter(this);
        nfcAdpt.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techList);
    }
    catch(NFCManager.NFCNotSupported nfcnsup) {
        Snackbar.make(v, "NFC not supported", Snackbar.LENGTH_LONG).show();
    }
    catch(NFCManager.NFCNotEnabled nfcnEn) {
        Snackbar.make(v, "NFC Not enabled", Snackbar.LENGTH_LONG).show();
    }

}


@Override
protected void onPause() {
    super.onPause();
    nfcMger.disableDispatch();
}

@Override
public void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    Log.d("Nfc", "New intent");
    // It is the time to write the tag
    currentTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    if (message != null) {
        nfcMger.writeTag(currentTag, message);
        dialog.dismiss();
        Snackbar.make(v, "Tag written", Snackbar.LENGTH_LONG).show();

    } else {
        // Handle intent

    }
}

There is another and much better way to get notified that a Tag comes in to range especially if you are writing to a Tag, this is called enableReaderMode but you use case is strange.

I'm not sure why you would want an NFC tag stuck on the back of a phone because then it would act like very slow and small sized permanent storage when a file on the phones memory would be far better.

Remember once the Tag comes in to range you get notified via enableForegroundDispatch or enableReaderMode that a Tag has come in to range and get given a Tag object. As long as that Tag does not go out of range and you have stored the Tag object in the global scope of the activity then you can write to it as many times you like and for as long as you like.

Therefore it should be possible if complicated to do what you wand and write (or read) when even the user click a button.

I've not tested whether a Tag object is usable after your App is put in to the background and brought to the foreground again, but I think it is unlikely because a background App might be closed and closure would definitely invalid the Tag object.

But there are 2 problems with your code.

  1. Really calling connect and write to your Tag should never be done on the UI thread as it is IO blocking and could be cancelled which would cause the Tag to be taken out of range and brought back in to range again. Luckily if you use enableReaderMode then you get notified in a separate thread.

  2. You should only call close on the Tag when you no longer want to write to it, at the moment you are calling close after you have written once to it.

So the following will probably work for you but with the limitation that the Tag has to come in to range the first time after the App has started.

Use enableReaderMode to get notified that the Tag initially comes in to range, Store the Tag object in the global Activity scope and connect to it once in the enableReaderMode callback thread.

The from the UI when the button is press, start a new Thread to write to the tag.

Never call close on the Tag Object.

Note I've not tested this as it is a very strange use case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM