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

Android应用写入NTAG215 NFC标签异常报错求助

NFC标签写入崩溃问题分析与解决方案

问题原因分析

  • 空指针异常未捕获:当NTAG215未被NDEF格式化时,Ndef.get(tag)会返回null,后续调用ndef.connect()会抛出NullPointerException,但你的代码只捕获了IOException和FormatException,导致应用直接崩溃,无法触发错误提示Toast。
  • ForegroundDispatch过滤优先级低:ACTION_TAG_DISCOVERED是NFC Intent中优先级最低的,系统可能优先触发其他应用的NFC处理逻辑,导致myTag无法被正确赋值。
  • 写入逻辑不完善:没有检查标签的NDEF支持状态,也未处理标签连接失败、写入中断等边缘情况。

代码优化建议

核心修改点

  1. 增加NullPointerException捕获,处理NDEF不可用的标签
  2. 替换enableForegroundDispatch为更可靠的enableReaderMode,避免Intent优先级问题
  3. 完善写入逻辑,支持格式化未NDEF初始化的标签
  4. 使用try-with-resources确保NFC资源正确释放
  5. 优化Toast显示的线程安全性

修改后的完整代码

NfcAdapter adapter;
Tag myTag;
Context ctx;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ctx = this;
    Button btnWrite = findViewById(R.id.button);
    final TextView name = findViewById(R.id.name);

    btnWrite.setOnClickListener(v -> {
        try {
            if (myTag == null) {
                showToast(getString(R.string.error_detected));
                return;
            }
            write(name.getText().toString(), myTag);
            showToast(getString(R.string.ok_writing));
        } catch (NullPointerException e) {
            showToast(getString(R.string.error_ndef_not_supported));
            e.printStackTrace();
        } catch (IOException e) {
            showToast(getString(R.string.error_writing));
            e.printStackTrace();
        } catch (FormatException e) {
            showToast(getString(R.string.error_writing));
            e.printStackTrace();
        }
    });

    adapter = NfcAdapter.getDefaultAdapter(this);
}

private void write(String text, Tag tag) throws IOException, FormatException {
    Ndef ndef = Ndef.get(tag);
    if (ndef != null) {
        // 处理已NDEF格式化的标签
        ndef.connect();
        try (ndef) { // try-with-resources自动关闭连接
            NdefMessage message = new NdefMessage(new NdefRecord[]{createRecord(text)});
            if (!ndef.isWritable()) {
                throw new IOException("Tag is not writable");
            }
            if (ndef.getMaxSize() < message.toByteArray().length) {
                throw new IOException("Text too long for tag");
            }
            ndef.writeNdefMessage(message);
        }
    } else {
        // 格式化未NDEF初始化的标签并写入
        NdefFormatable formatable = NdefFormatable.get(tag);
        if (formatable != null) {
            formatable.connect();
            try (formatable) {
                NdefMessage message = new NdefMessage(new NdefRecord[]{createRecord(text)});
                formatable.format(message);
            }
        } else {
            throw new NullPointerException("Tag does not support NDEF");
        }
    }
}

private NdefRecord createRecord(String text) throws UnsupportedEncodingException {
    String lang = "en";
    byte[] textBytes = text.getBytes("UTF-8"); // 改用UTF-8支持多语言字符
    byte[] langBytes = lang.getBytes("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);
    System.arraycopy(textBytes, 0, payload, 1 + langLength, textLength);

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

// 使用enableReaderMode替代ForegroundDispatch,逻辑更稳定
@Override
protected void onResume() {
    super.onResume();
    if (adapter != null) {
        adapter.enableReaderMode(this, tag -> {
            myTag = tag;
            runOnUiThread(() -> showToast(getString(R.string.ok_detection) + tag.toString()));
        }, NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, null);
    }
}

@Override
protected void onPause() {
    super.onPause();
    if (adapter != null) {
        adapter.disableReaderMode(this);
    }
}

private void showToast(String message) {
    runOnUiThread(() -> Toast.makeText(ctx, message, Toast.LENGTH_LONG).show());
}

优化说明

  • enableReaderMode优势:直接通过回调获取Tag,避免Intent分发的优先级问题,逻辑更简洁可靠
  • 兼容未格式化标签:新增NdefFormatable处理逻辑,支持对未初始化的NTAG215进行格式化写入
  • 完善异常覆盖:新增空指针、标签不可写、内容过长等异常处理,确保崩溃场景都能触发错误提示
  • 资源安全释放:使用try-with-resources自动关闭NFC连接,避免资源泄漏
  • 多语言支持:文本编码改用UTF-8,支持中文、特殊字符等非ASCII内容

适配标签技术推荐

  • NTAG215:当前选择完全适配,504字节容量足够存储文本、URL等轻量数据,成本低,是入门NFC开发的首选
  • NTAG216:如果需要更大存储(888字节),可以升级,适合存储多行文本、小型JSON等内容
  • MIFARE Ultralight C:带有UID加密功能,适合需要简单防伪的场景,同样支持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.06 03:50:21