简体   繁体   中英

I have a problem writting NFC Tag in Android

I'm working on an app to write NFC tag in Android Studio. My code:

    public class MainActivity extends AppCompatActivity {

    public static final String Error_dected = "No NFC Tag Detected";
    public static final String Write_Success = "Text Written Succesfully";
    public static final String Write_Error = "Error during writtin, Try again";
    NfcAdapter nfcAdapter;
    PendingIntent pendingIntent;
    IntentFilter writingTagFilters[];
    boolean writeMode;
    Tag myTag;
    Context context;


    EditText edit_message;
    TextView nfc_contents;
    Button ActivateButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        edit_message = (EditText) findViewById(R.id.edit_message);
        nfc_contents = (TextView) findViewById(R.id.nfc_content);
        ActivateButton = (Button) findViewById(R.id.ActivateButton);
        context = this;
        ActivateButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                String mensaje=edit_message.getText().toString();


               try {

                    if (myTag == null) {
                        Toast.makeText(context, Error_dected, Toast.LENGTH_LONG).show();
                    } else {

                        write("PlainText|" + edit_message.getText().toString(), myTag);
                        Toast.makeText(context, Write_Success, Toast.LENGTH_LONG).show();
                    }


                } catch (IOException e) {

                    Toast.makeText(context, Write_Error, Toast.LENGTH_LONG).show();
                    e.printStackTrace();
                } catch (FormatException e) {
                    Toast.makeText(context, Write_Error, Toast.LENGTH_LONG).show();
                    e.printStackTrace();
                }


            }

        });



        nfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (nfcAdapter == null) {
            Toast.makeText(this, "this device does not support NFC", Toast.LENGTH_LONG).show();

        }

        readfromIntent(getIntent());
        pendingIntent = pendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
        IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
        tagDetected.addCategory(Intent.CATEGORY_DEFAULT);
        writingTagFilters = new IntentFilter[]{tagDetected};

    }



    public void readfromIntent(Intent intent) {
        String action = intent.getAction();
        if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)
                || NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)
                || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
            Parcelable[] rawMsg = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
            NdefMessage[] msgs = null;
            if (rawMsg != null) {
                msgs = new NdefMessage[rawMsg.length];
                for (int i = 0; i < rawMsg.length; i++) {
                    msgs[i] = (NdefMessage) rawMsg[i];
                }

                buildTagView(msgs);
            }
        }

    }

    private void buildTagView(NdefMessage[] msgs) {
        if (msgs == null || msgs.length == 0) return;

        String text = "";
        byte[] payload = msgs[0].getRecords()[0].getPayload();
        String textEncodgin = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16"; //Get the text encoding
        int languageCodeLength = payload[0] & 0063;
        try {
            text = new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncodgin);

        } catch (UnsupportedEncodingException e) {
            Log.e("UnsupportedEncoding", e.toString());
        }
        nfc_contents.setText("NFC Content: " + text);

    }

    private void write(String text, Tag tag) throws IOException, FormatException {
        NdefRecord[] records = {createRecord(text)};
        NdefMessage message = new NdefMessage(records);
        //Get an instance os Ndef for the tag
        Ndef ndef = Ndef.get(tag);

        //Enable I/0
        ndef.connect();
        //Write the message
        ndef.writeNdefMessage(message);
        //Clase de connection
        ndef.close();


    }

    private NdefRecord createRecord(String text) throws UnsupportedEncodingException {

    String lang ="en";
    byte[] textBytes=text.getBytes();
    byte[] langBytes=lang.getBytes("US-ASCII");
    int langLength=langBytes.length;
    int textLength=textBytes.length;
    byte[] payload =new byte[1+langLength+textLength];
    //set status byte (see NDEF spec for actual bits

        payload[0]= (byte) langLength;
        //copy langbytes and textbytes into payload

        System.arraycopy(langBytes,0,payload,1,langLength);
        System.arraycopy(textBytes,0,payload,1+langLength,textLength);

        NdefRecord recordNFC =new NdefRecord(NdefRecord.TNF_WELL_KNOWN,NdefRecord.RTD_TEXT,new byte[0],payload);

        return recordNFC;



    }

    @Override
    protected void onNewIntent(Intent intent)
    {
        super.onNewIntent(intent);
        setIntent(intent);
        readfromIntent(intent);
        if(NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()))
        {
            myTag=intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        }
    }
    @Override
    public void onPause()
    {
        super.onPause();
        WriteModeOff();
    }

    @Override
    public void onResume()
    {
        super.onResume();
        WriteModeOn();
    }

    /********ENABLE WRITE*****/
    private void WriteModeOn()
    {
        writeMode=true;
        nfcAdapter.enableForegroundDispatch(this,pendingIntent,writingTagFilters,null);

    }

    /*******DISABLE WRITE*****/
    private void WriteModeOff()
    {
        writeMode=false;
        nfcAdapter.disableForegroundDispatch(this);
    }
}

When I run it and try to write in a NFC tag I always get myTag==null so I'm always here:

if (myTag == null) { Toast.makeText(context, Error_dected, Toast.LENGTH_LONG).show();

I've modified the user-permission in "android.Manifest" Any idea of what is happening? Thank you

The only starting point for any NFC operation is when the System NFC App gives you a Tag object as a starting point to interact with the NFC Tag it has detected.

There are a number of ways to do that and enableForgroundDispatch is one method you are already using, But in real life usage this is very unreliable way to work with NFC and will lead to lots of write errors and corrupted data on NFC Tags.

Much better method is to use the newer API enableReaderMode and an example of that is found at https://stackoverflow.com/a/64921434/2373819 and it explains why it is better.

But for both API's all your interaction with the Tag needs to be done when a Tag is detected and you are notified a Tag has come in to range (for the current API you are using that is in onNewIntent )

So a simple way to handle this when the user clicks the ActivateButton is to set a global boolean to indicate the next time a Tag is detected you should write to it instead of trying to read from it (and you would store the string to write in a global String as well)

Below is some code changes that give you the idea BUT this is a bare bones example as it does not show any UI changes to prompt the user to bring an NFC card in to range and it does not cover any re-tries you might need to successfully write to an NFC card.

public class MainActivity extends AppCompatActivity {

    public static final String Error_dected = "No NFC Tag Detected";
    public static final String Write_Success = "Text Written Succesfully";
    public static final String Write_Error = "Error during writtin, Try again";
    NfcAdapter nfcAdapter;
    PendingIntent pendingIntent;
    IntentFilter writingTagFilters[];
    boolean writeMode;
    Tag myTag;
    Context context;


    EditText edit_message;
    TextView nfc_contents;
    Button ActivateButton;

    //New code below
    boolean someThingToWrite;
    String stringToWrite;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        edit_message = (EditText) findViewById(R.id.edit_message);
        nfc_contents = (TextView) findViewById(R.id.nfc_content);
        ActivateButton = (Button) findViewById(R.id.ActivateButton);
        context = this;
        ActivateButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                //Changed Code
                stringToWrite = edit_message.getText().toString();
                someThingToWrite = true;
        });



        nfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (nfcAdapter == null) {
            Toast.makeText(this, "this device does not support NFC", Toast.LENGTH_LONG).show();

        }

        readfromIntent(getIntent());
        pendingIntent = pendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
        IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
        tagDetected.addCategory(Intent.CATEGORY_DEFAULT);
        writingTagFilters = new IntentFilter[]{tagDetected};

    }



    public void readfromIntent(Intent intent) {
        String action = intent.getAction();
        if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)
                || NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)
                || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
            Parcelable[] rawMsg = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
            NdefMessage[] msgs = null;
            if (rawMsg != null) {
                msgs = new NdefMessage[rawMsg.length];
                for (int i = 0; i < rawMsg.length; i++) {
                    msgs[i] = (NdefMessage) rawMsg[i];
                }

                buildTagView(msgs);
            }
        }

    }

    private void buildTagView(NdefMessage[] msgs) {
        if (msgs == null || msgs.length == 0) return;

        String text = "";
        byte[] payload = msgs[0].getRecords()[0].getPayload();
        String textEncodgin = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16"; //Get the text encoding
        int languageCodeLength = payload[0] & 0063;
        try {
            text = new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncodgin);

        } catch (UnsupportedEncodingException e) {
            Log.e("UnsupportedEncoding", e.toString());
        }
        nfc_contents.setText("NFC Content: " + text);

    }

    private void write(String text, Tag tag) throws IOException, FormatException {
        NdefRecord[] records = {createRecord(text)};
        NdefMessage message = new NdefMessage(records);
        //Get an instance os Ndef for the tag
        Ndef ndef = Ndef.get(tag);

        //Enable I/0
        ndef.connect();
        //Write the message
        ndef.writeNdefMessage(message);
        //Clase de connection
        ndef.close();


    }

    private NdefRecord createRecord(String text) throws UnsupportedEncodingException {

    String lang ="en";
    byte[] textBytes=text.getBytes();
    byte[] langBytes=lang.getBytes("US-ASCII");
    int langLength=langBytes.length;
    int textLength=textBytes.length;
    byte[] payload =new byte[1+langLength+textLength];
    //set status byte (see NDEF spec for actual bits

        payload[0]= (byte) langLength;
        //copy langbytes and textbytes into payload

        System.arraycopy(langBytes,0,payload,1,langLength);
        System.arraycopy(textBytes,0,payload,1+langLength,textLength);

        NdefRecord recordNFC =new NdefRecord(NdefRecord.TNF_WELL_KNOWN,NdefRecord.RTD_TEXT,new byte[0],payload);

        return recordNFC;



    }

    @Override
    protected void onNewIntent(Intent intent)
    {
        super.onNewIntent(intent);

        //New code
        if(someThingToWrite) {
          // Is it an NDEF tag
          if(NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()))
          {
            myTag=intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            write("PlainText|" + stringToWrite, myTag);
            // Don't want to continue with reading so return
            return;
          }
          // Really should handle NDEF formatable tags as well
          // Just in case it's a blank unformatted tag
          // but that is relevant for this example.

        }

        setIntent(intent);
        readfromIntent(intent);
        if(NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()))
        {
            myTag=intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        }
    }
    @Override
    public void onPause()
    {
        super.onPause();
        WriteModeOff();
    }

    @Override
    public void onResume()
    {
        super.onResume();
        WriteModeOn();
    }

    /********ENABLE WRITE*****/
    private void WriteModeOn()
    {
        writeMode=true;
        nfcAdapter.enableForegroundDispatch(this,pendingIntent,writingTagFilters,null);

    }

    /*******DISABLE WRITE*****/
    private void WriteModeOff()
    {
        writeMode=false;
        nfcAdapter.disableForegroundDispatch(this);
    }
}

I quite like instead of setting a flag to say on next Tag detection to write to Tag to actually create a new Activity just to handle the UI and re-try logic and Tag writing, this keeps the logic cleaner and is re-useable in other parts of your App.
Then your ActivateButton.setOnClickListener just starts the new Activity and passes it the string to write via the Intent.

Note I can you you have been copying and pasting code from poor examples on the web because you use the WriteModeOn and WriteModeOff method:-)

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