React Native NFC Manager无法用默认密钥认证Mifare Classic扇区0
解决React Native中react-native-nfc-manager读取Mifare Classic认证失败问题
问题核心原因
你的认证命令缺少卡片UID参数。Mifare Classic的Auth A指令要求完整的命令结构为:0x60(AuthA) + 块地址 + 6字节密钥 + 4字节卡片UID,你的代码中仅构造了前三个部分,缺少UID导致认证失败。
修改方案
1. 转换卡片UID为字节数组
在读取到tag后,将tag.id(十六进制字符串格式)转换为Uint8Array格式的UID字节数组。
2. 补全认证命令参数
修改认证函数,将UID加入到认证命令中;同时建议使用扇区的控制块(每个扇区的最后一个块)进行认证,这是Mifare Classic的标准做法。
3. 优化错误调试
在catch中打印具体错误信息,便于排查问题。
修改后的完整代码
NFCManagerService.ts
import NfcManager, { NfcTech } from 'react-native-nfc-manager'; class NFCManagerService { private static instance: NFCManagerService; private readonly CMD = { AUTH_A: 0x60, // Authenticate with Key A READ: 0x30, // Read block }; private constructor() { } public static getInstance(): NFCManagerService { if (!NFCManagerService.instance) { NFCManagerService.instance = new NFCManagerService(); } return NFCManagerService.instance; } public async readSectorZero(logCallback: (message: string) => void): Promise<void> { try { logCallback('Initializing NFC...'); await NfcManager.requestTechnology(NfcTech.MifareClassic); logCallback('NFC initialized.'); const tag = await NfcManager.getTag(); if (!tag || !tag.id) { throw new Error('No tag detected or tag ID missing.'); } logCallback(`Tag detected: ${tag.id}`); // 将十六进制字符串格式的UID转换为字节数组 const uidBytes = Uint8Array.from( tag.id.match(/.{1,2}/g)!.map(byte => parseInt(byte, 16)) ); const key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; const keyHex = key.map(b => b.toString(16).padStart(2, '0')).join(''); logCallback(`Attempting Auth A Sector 0 with key: ${keyHex}`); if (await this.authenticateSector(0, key, uidBytes, logCallback)) { logCallback(`✓ Auth A Sector 0 succeeded with key: ${keyHex}`); const data = await this.readBlock(0); if (data) { logCallback(`Data from Block 0: ${Array.from(data).map(b => b.toString(16).padStart(2, '0')).join(' ')}`); } else { logCallback('Failed to read data from Block 0.'); } } else { logCallback(`✗ Auth A Sector 0 failed with key: ${keyHex}`); } } catch (error) { logCallback(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`); } finally { await NfcManager.cancelTechnologyRequest(); logCallback('NFC released.'); } } private async authenticateSector(sector: number, key: number[], uid: Uint8Array, logCallback: (message: string) => void): Promise<boolean> { try { // 使用扇区的控制块(每个扇区最后一个块)进行认证,扇区0的控制块是3 const blockIndex = sector * 4 + 3; const authCommand = [this.CMD.AUTH_A, blockIndex, ...key, ...uid]; const response = await NfcManager.transceive(authCommand); logCallback(`Auth response: ${Array.from(response).map(b => b.toString(16).padStart(2, '0')).join(' ')}`); return true; } catch (error) { logCallback(`Auth error details: ${JSON.stringify(error)}`); return false; } } private async readBlock(blockIndex: number): Promise<Uint8Array | null> { try { const readCommand = [this.CMD.READ, blockIndex]; const response = await NfcManager.transceive(readCommand); return new Uint8Array(response); } catch (error) { console.error('Read block error:', error); return null; } } } export default NFCManagerService;
额外排查点
- 权限配置:确保AndroidManifest.xml中添加了NFC权限及相关intent-filter,iOS的Info.plist中配置了NFCUsageDescription。
- UID字节序:部分设备返回的tag.id字节序可能与卡片实际UID相反,可对比Mifare Classic Tool中的UID,调整转换逻辑。
- 库版本:确保react-native-nfc-manager为最新稳定版,避免库本身的兼容性问题。
内容的提问来源于stack exchange,提问作者Sonycsl
相关产品推荐
相关产品推荐

