Android NFC设置NTAG216密码遇Transceive failed异常求助
问题描述
我是Android NFC开发新手,尝试为NTAG216 Mifare Ultralight标签设置密码时卡壳多日。使用的是空白标签,确认当前无保护,但设置命令执行失败。更换不同设备测试,仍出现相同错误。目前writePage和readPages方法可正常工作,transceive方法执行get_version、fast_read命令也正常,但设置密码和PACK时失败。
相关代码
package com.lancine.nfcapp; import android.annotation.SuppressLint; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.nfc.NfcAdapter; import android.nfc.Tag; import android.nfc.tech.NfcA; import android.os.Build; import android.os.Bundle; import android.os.VibrationEffect; import android.os.Vibrator; import android.util.Log; import androidx.appcompat.app.AppCompatActivity; import androidx.navigation.ui.AppBarConfiguration; import com.lancine.nfcapp.databinding.ActivityMainBinding; import java.io.IOException; import java.util.Arrays; public class MainActivity extends AppCompatActivity implements NfcAdapter.ReaderCallback { private AppBarConfiguration appBarConfiguration; private ActivityMainBinding binding; NfcAdapter mAdapter; PendingIntent pendingIntent; Tag tag; @SuppressLint("UnspecifiedImmutableFlag") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_MUTABLE); } else { pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_ONE_SHOT); } mAdapter = NfcAdapter.getDefaultAdapter(this); } @Override protected void onResume() { super.onResume(); //mAdapter.enableForegroundDispatch(this, pendingIntent, null, null); if (mAdapter != null) { Bundle options = new Bundle(); options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 250); mAdapter.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_NO_PLATFORM_SOUNDS, options); } } @Override public void onTagDiscovered(Tag tag) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { ((Vibrator) getSystemService(VIBRATOR_SERVICE)).vibrate(VibrationEffect.createOneShot(150, 10)); } else { Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); v.vibrate(200); } this.setPassword(tag); } @Override protected void onPause() { super.onPause(); if (mAdapter != null) { mAdapter.disableReaderMode(this); } } public void setPassword(Tag tag) { (new Thread(() -> { NfcA nfcA = null; try { nfcA = NfcA.get(tag); if(nfcA != null) { nfcA.connect(); byte[] data = nfcA.transceive(new byte[] { (byte)0xA2, // WRITE (byte)(229 & 0x0ff), // block address (byte)0x34, (byte)0x36, (byte)0x37, (byte)0x32 }); System.out.println("Comment" + Arrays.toString(data)); nfcA.close(); } } catch (IOException e) { Log.e("TAG", "IOException", e); e.printStackTrace(); } })).start(); } }
错误栈信息
W/System.err: java.io.IOException: Transceive failed
W/System.err: at android.nfc.TransceiveResult.getResponseOrThrow(TransceiveResult.java:52)
W/System.err: at android.nfc.tech.BasicTagTechnology.transceive(BasicTagTechnology.java:151)
W/System.err: at android.nfc.tech.MifareUltralight.transceive(MifareUltralight.java:215)
W/System.err: at com.lancine.nfcapp.MainActivity.lambda$nfcCommand$0$com-lancine-nfcapp-MainActivity(MainActivity.java:153)
W/System.err: at com.lancine.nfcapp.MainActivity$$ExternalSyntheticLambda0.run(D8$$SyntheticClass)
W/System.err: at java.lang.Thread.run(Thread.java:761)
NXP TagInfo读取的标签信息
详细协议信息:
ID: 04:DE:58:42:EC:64:80
ATQA: 0x4400
SAK: 0x00
# Memory content: [00] * 04:DE:58 0A (UID0-UID2, BCC0) [01] * 42:EC:64:80 (UID3-UID6) [02] . 4A 48 00 00 (BCC1, INT, LOCK0-LOCK1) [03] . E1:11:6D:00 (OTP0-OTP3) [04] . 03 0B D1 01 |....| [05] . 07 54 02 66 |.T.f| [06] . 72 59 65 6F |rYeo| [07] . 79 FE 00 00 |y...| [08] . 32 22 2C 22 |2","| [09] . 63 61 72 74 |cart| [0A] . 5F 69 64 22 |_id"| [0B] . 3A 22 31 30 |:"10| [0C] . 30 30 30 30 |0000| [0D] . 30 30 22 2C |00",| [0E] . 22 65 74 61 |"eta| [0F] . 62 5F 69 64 |b_id| [10] . 22 3A 22 31 |":"1| [11] . 30 30 30 30 |0000| [12] . 30 30 22 2C |00",| [13] . 22 65 74 61 |"eta| [14] . 62 5F 6E 6F |b_no| [15] . 6D 22 3A 22 |m":"| [16] . 4C 59 43 45 |LYCE| [E1] .r 00 00 00 00 |....| [E2] .r 00 00 00 BD (LOCK2-LOCK4, CHK) [E3] .r 04 00 00 E1 (CFG, MIRROR, AUTH0) [E4] .r 00 05 -- -- (ACCESS) [E5] +P XX XX XX XX (PWD0-PWD3) [E6] +P XX XX -- -- (PACK0-PACK1) *:locked & blocked, x:locked, +:blocked, .:un(b)locked, ?:unknown r:readable (write-protected), p:password protected, -:write-only P:password protected write-only
问题分析与解决
核心问题定位
从TagInfo输出看,标签的AUTH0配置为0xE1,这意味着从页0xE1开始的所有存储区都需要密码验证才能读写。你尝试直接写入密码页0xE5,但未先完成密码验证,导致命令被拒绝。修正步骤
- 先使用默认密码(全0x00)完成验证,获得写入权限
- 改用
MifareUltralight类操作,更适配Mifare Ultralight系列标签 - 写入密码后可按需配置PACK(密码验证响应码)
修正后的代码示例
public void setPassword(Tag tag) { new Thread(() -> { MifareUltralight mifare = null; try { mifare = MifareUltralight.get(tag); if(mifare != null) { mifare.connect(); // 用默认全0密码验证 byte[] authResp = mifare.transceive(new byte[]{(byte)0x1B, 0x00, 0x00, 0x00, 0x00}); Log.d("TAG", "验证响应: " + Arrays.toString(authResp)); // 写入新密码到0xE5页 byte[] pwdResp = mifare.transceive(new byte[]{ (byte)0xA2, (byte)0xE5, (byte)0x34, (byte)0x36, (byte)0x37, (byte)0x32 }); Log.d("TAG", "密码写入响应: " + Arrays.toString(pwdResp)); // 写入PACK到0xE6页(前2字节有效,后2字节无意义) byte[] packResp = mifare.transceive(new byte[]{ (byte)0xA2, (byte)0xE6, (byte)0xAB, (byte)0xCD, 0x00, 0x00 }); Log.d("TAG", "PACK写入响应: " + Arrays.toString(packResp)); mifare.close(); } } catch (IOException e) { Log.e("TAG", "操作失败", e); } }).start(); }
- 额外注意事项
- 若后续不需要密码保护,需将
AUTH0页(0xE3最后1字节)改为0xFF,否则写入密码后所有0xE1及之后的页都需要验证密码才能访问 - 确保标签未被物理锁死,从LOCK2-LOCK4的状态看,当前配置区未被锁死,可正常修改
- 若后续不需要密码保护,需将
内容的提问来源于stack exchange,提问作者Lancine Yeo

