You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何向单个NFC标签写入双字符串?Android考勤应用开发求助

NFC考勤应用代码修复方案

问题根源

  1. 重复写入会覆盖数据:原代码两次调用write方法,每次写入单独的NDEF消息,第二次写入会完全覆盖第一次的内容,最终标签只保留第二个数据。
  2. 文本记录创建错误:createRecord方法里错误地将语言字节数组复制到文本区域,导致实际写入的文本内容错乱。
  3. 读取逻辑不完整:只读取了第一个NDEF记录,第二个输入框始终显示空值。

修改后的完整代码

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;

import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;


public class writeHome extends AppCompatActivity {

    public static final String Error_Detected = "No NFC Tag Detected!";
    public static final String Write_Success = "Text Written Successfully!";
    public static final String Write_Error = "Error during Writing, Try again!";
    NfcAdapter nfcAdapter;
    PendingIntent pendingIntent;
    IntentFilter[] writingTagFilters;
    boolean writeMode;
    Tag myTag;
    Context context;
    TextView editTextTextPersonName7;
    TextView editTextTextPersonName3;
    Button button2;


    @RequiresApi(api = Build.VERSION_CODES.S)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_write_home);
        editTextTextPersonName7 = findViewById(R.id.editTextTextPersonName7);
        editTextTextPersonName3 = findViewById(R.id.editTextTextPersonName3);
        button2 = findViewById(R.id.button2);
        context = this;

        // 修改:合并两个数据的写入逻辑,避免覆盖
        button2.setOnClickListener(view -> {
            try {
                if(myTag == null) {
                    Toast.makeText(context, Error_Detected, Toast.LENGTH_LONG).show();
                } else {
                    writeTwoRecords(editTextTextPersonName7.getText().toString(),
                            editTextTextPersonName3.getText().toString(), myTag);
                    Toast.makeText(context, Write_Success, Toast.LENGTH_SHORT).show();
                }
            } catch (IOException | 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_SHORT).show();
        }
        readFromIntent(getIntent());
        pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
        IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
        tagDetected.addCategory(Intent.CATEGORY_DEFAULT);
        writingTagFilters = new IntentFilter[] { tagDetected };
    }

    private 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[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
            NdefMessage[] msgs = null;
            if (rawMsgs != null) {
                msgs = new NdefMessage[rawMsgs.length];
                for (int i = 0; i < rawMsgs.length; i++) {
                    msgs[i] = (NdefMessage) rawMsgs[i];
                }
            }
            buildTagViews(msgs);
        }
    }

    // 修改:读取并显示两个NDEF记录
    private void buildTagViews(NdefMessage[] msgs) {
        if (msgs == null || msgs.length == 0) return;

        String text1 = "";
        String text2 = "";

        // 获取第一个消息里的所有记录
        NdefRecord[] records = msgs[0].getRecords();

        // 处理第一个记录
        if (records.length > 0) {
            byte[] payload = records[0].getPayload();
            String textEncoding = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16";
            int languageCodeLength = payload[0] & 51;
            try {
                text1 = new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding);
            } catch (UnsupportedEncodingException e) {
                Log.e("UnsupportedEncoding", e.toString());
            }
        }

        // 处理第二个记录
        if (records.length > 1) {
            byte[] payload = records[1].getPayload();
            String textEncoding = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16";
            int languageCodeLength = payload[0] & 51;
            try {
                text2 = new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding);
            } catch (UnsupportedEncodingException e) {
                Log.e("UnsupportedEncoding", e.toString());
            }
        }

        // 显示到对应输入框
        editTextTextPersonName7.setText(text1);
        editTextTextPersonName3.setText(text2);
    }

    // 新增:一次性写入两个NDEF记录
    private void writeTwoRecords(String text1, String text2, Tag tag) throws IOException, FormatException {
        NdefRecord[] records = { createRecord(text1), createRecord(text2) };
        NdefMessage message = new NdefMessage(records);
        Ndef ndef = Ndef.get(tag);
        ndef.connect();
        ndef.writeNdefMessage(message);
        ndef.close();
    }

    // 修改:修复文本字节复制错误
    private NdefRecord createRecord(String text) {
        String lang = "en";
        byte[] textBytes = text.getBytes(StandardCharsets.UTF_8);
        byte[] langBytes = lang.getBytes(StandardCharsets.US_ASCII);
        int langLength = langBytes.length;
        int textLength = textBytes.length;
        byte[] payload = new byte[1 + langLength + textLength];

        payload[0] = (byte) langLength;

        System.arraycopy(langBytes, 0, payload, 1, langLength);
        // 原错误:复制了langBytes,现在改为复制textBytes
        System.arraycopy(textBytes, 0, payload, 1 + langLength, textLength);

        return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        readFromIntent(intent);
        if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
            myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        WriteModeOff();
    }

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

    private void WriteModeOn() {
        writeMode = true;
        String[][] techList = new String[][] { { android.nfc.tech.Ndef.class.getName() }, { android.nfc.tech.NdefFormatable.class.getName() } };
        nfcAdapter.enableForegroundDispatch(this, pendingIntent, writingTagFilters, techList);
    }

    private void WriteModeOff() {
        writeMode = false;
        nfcAdapter.disableForegroundDispatch(this);
    }
}

关键修改说明

  1. 合并写入逻辑
    新增writeTwoRecords方法,将两个文本分别创建为NDEF记录,打包成一个NDEF消息后一次性写入标签,避免两次写入导致的数据覆盖。同时修改按钮点击事件,调用这个新方法。

  2. 修复记录创建错误
    在createRecord方法中,把错误的System.arraycopy(langBytes, 0, payload, 1+langLength, textLength)改为System.arraycopy(textBytes, 0, payload, 1+langLength, textLength),确保实际写入的是输入的文本内容。

  3. 完善读取逻辑
    修改buildTagViews方法,遍历NDEF消息中的多个记录,分别读取第一个和第二个记录的内容,并显示到对应的输入框中。

内容的提问来源于stack exchange,提问作者Student Progg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 22:30:43