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

ACR1255U-J1蓝牙NFC阅读器无法识别Mifare Ultralight卡

问题:ACR1255U-J1蓝牙NFC阅读器无法识别Mifare Ultralight卡

多日尝试使用ACR1255U-J1蓝牙NFC阅读器读取Mifare Ultralight卡,以实现手机打开指定URL的功能,但始终失败。无论阅读器上方是否放置NFC卡,输出日志完全一致。

日志示例

放置NFC卡时的日志:

Running "NFCReaderApp" with {"rootTag":141,"initialProps":{},"fabric":true} NFCReader.js:54 
Connected device: ACR1255U-J1-035094 NFCReader.js:150 
Comando enviado: ff 00 00 00 00 NFCReader.js:150 
Comando enviado: ff 00 00 02 01 NFCReader.js:150 
Comando enviado: ff 00 00 03 01 NFCReader.js:82 
Reader Initialized NFCReader.js:100 
Raw data: 05 00 07 52 00 00 00 00 01 53 07 0a 

未放置NFC卡时的日志:

Running "NFCReaderApp" with {"rootTag":141,"initialProps":{},"fabric":true} NFCReader.js:54 
Connected device: ACR1255U-J1-035094 NFCReader.js:150 
Comando enviado: ff 00 00 00 00 NFCReader.js:150 
Comando enviado: ff 00 00 02 01 NFCReader.js:150 
Comando enviado: ff 00 00 03 01 NFCReader.js:82 
Reader Initialized NFCReader.js:100 
Raw data: 05 00 07 52 00 00 00 00 01 53 07 0a

已排查情况

  • 更换多张Mifare Ultralight卡,输出结果无变化
  • 阅读器连接ACS官方BLETest.apk可正常工作
  • 卡片在手机NFC阅读器上能正常识别

代码实现

import base64 from 'base-64';
import { BleManager } from 'react-native-ble-plx';

class NFCReaderApp {
constructor(onCardStatusChange) {
this.bleManager = new BleManager();
this.SERVICE_UUID = "3c4afff0-4783-3de5-a983-d348718ef133";
this.WRITE_CHARACTERISTIC = "3c4afff1-4783-3de5-a983-d348718ef133";
this.NOTIFY_CHARACTERISTIC = "3c4afff2-4783-3de5-a983-d348718ef133";
this.scanning = false;
this.onDeviceFound = null;
this.onError = null;
this.lastCardStatus = false;
this.onCardStatusChange = onCardStatusChange;
}

    async checkBluetoothState() {
        try {
            const state = await this.bleManager.state();
            return state === 'PoweredOn';
        } catch (error) {
            console.error('Error checking Bluetooth:', error);
            return false;
        }
    }
    
    startScanning() {
        if (this.scanning) return;
        
        this.scanning = true;
        this.bleManager.startDeviceScan(null, null, (error, device) => {
            if (error) {
                this.scanning = false;
                if (this.onError) this.onError('Scanning error: ' + error);
                return;
            }
    
            if (device?.name?.includes('ACR1255U')) {
                this.stopScanning();
                this.connectToDevice(device);
            }
        });
    }
    
    stopScanning() {
        if (this.scanning) {
            this.bleManager.stopDeviceScan();
            this.scanning = false;
        }
    }
    
    async connectToDevice(device) {
        try {
            console.log('Connecting to device:', device.name);
            const connectedDevice = await device.connect();
            await connectedDevice.discoverAllServicesAndCharacteristics();
            
            if (this.onDeviceFound) {
                this.onDeviceFound(device);
            }
    
            await this.initializeReader(connectedDevice);
            await this.setupCardDetection(connectedDevice);
        } catch (error) {
            console.error('Connection error:', error);
            if (this.onError) this.onError('Connection error: ' + error);
        }
    }
    
    async initializeReader(device) {
        try {
            const initCommands = [
                [0xFF, 0x00, 0x00, 0x00, 0x00], // Reset
                [0xFF, 0x00, 0x00, 0x02, 0x01], // Auto polling on
                [0xFF, 0x00, 0x00, 0x03, 0x01]  // Set operation mode
            ];
    
            for (const cmd of initCommands) {
                await this.sendCommand(device, cmd);
                await new Promise(resolve => setTimeout(resolve, 300));
            }
            console.log('Reader Initialized');
        } catch (error) {
            console.error('Error initializing reader:', error);
        }
    }
    
    async setupCardDetection(device) {
        return device.monitorCharacteristicForService(
            this.SERVICE_UUID,
            this.NOTIFY_CHARACTERISTIC,
            (error, characteristic) => {
                if (error) {
                    console.error('Error monitoring characteristic:', error);
                    return;
                }
    
                if (characteristic?.value) {
                    const rawData = this.base64ToArray(characteristic.value);
                    console.log('Raw data:', this.bytesToHex(rawData));
                    this.analyzeResponse(rawData);
                }
            }
        );
    }
    
    analyzeResponse(data) {
        if (!data || data.length === 0) return;
    
        switch(data[0]) {
            case 0x61: // Card status response
                const cardPresent = this.validateCardPresence(data);
                if (cardPresent !== this.lastCardStatus) {
                    this.lastCardStatus = cardPresent;
                    console.log(cardPresent ? '✅ CARD DETECTED' : '❌ NO CARD');
                    if (this.onCardStatusChange) {
                        this.onCardStatusChange(cardPresent);
                    }
                }
                break;
                
            case 0x4E: // No card
                if (this.lastCardStatus) {
                    this.lastCardStatus = false;
                    console.log('❌ NO CARD');
                    if (this.onCardStatusChange) {
                        this.onCardStatusChange(false);
                    }
                }
                break;
        }
    }
    
    validateCardPresence(data) {
        // Specific validation for Mifare Ultralight
        if (data.length < 3) return false;
        
        // Check if there are valid card data
        return data[1] !== 0x00 || data[2] !== 0x00;
    }
    
    async sendCommand(device, command) {
        try {
            const encodedCommand = this.arrayToBase64(command);
            await device.writeCharacteristicWithResponseForService(
                this.SERVICE_UUID,
                this.WRITE_CHARACTERISTIC,
                encodedCommand
            );
            console.log('Comando enviado:', this.bytesToHex(command));
        } catch (error) {
            console.error('Error sending command:', error);
        }
    }
    
    bytesToHex(bytes) {
        return Array.from(bytes)
            .map(byte => byte.toString(16).padStart(2, '0'))
            .join(' ');
    }
    
    arrayToBase64(array) {
        return base64.encode(String.fromCharCode(...array));
    }
    
    base64ToArray(str) {
        return new Uint8Array(base64.decode(str).split('').map(c => c.charCodeAt(0)));
    }
    
    cleanup() {
        this.stopScanning();
        this.bleManager.destroy();
    }

}

export default NFCReaderApp;

可能的原因及解决方案

1. 初始化命令不符合阅读器规范

当前发送的自动轮询命令[0xFF, 0x00, 0x00, 0x02, 0x01]可能无效。根据ACS官方文档,开启持续自动轮询的正确命令应为FF 00 00 02 02,01仅触发单次轮询,无法持续检测卡片状态变化。同时,操作模式命令[0xFF, 0x00, 0x00, 0x03, 0x01]需确认是否兼容Mifare Ultralight所属的ISO 14443 Type A协议。

修正方案:
更新初始化命令数组,参考官方文档调整参数:

const initCommands = [
    [0xFF, 0x00, 0x00, 0x00, 0x00], // 重置阅读器
    [0xFF, 0x00, 0x00, 0x02, 0x02], // 开启持续自动轮询
    [0xFF, 0x00, 0x00, 0x03, 0x00]  // 设置为ISO 14443 Type A兼容模式
];

2. 响应解析逻辑未匹配阅读器返回格式

日志中返回的原始数据开头为0x05,但你的analyzeResponse方法仅处理0x61(卡片状态)和0x4E(无卡)两种响应,导致无论有无卡片都无法触发状态变更。

修正方案:
先打印所有响应的首字节,对照官方文档确认含义,扩展解析逻辑:

analyzeResponse(data) {
    if (!data || data.length === 0) return;

    console.log('响应首字节:', data[0].toString(16));
    
    switch(data[0]) {
        case 0x61: // 卡片状态响应
            const cardPresent = this.validateCardPresence(data);
            if (cardPresent !== this.lastCardStatus) {
                this.lastCardStatus = cardPresent;
                console.log(cardPresent ? '✅ CARD DETECTED' : '❌ NO CARD');
                this.onCardStatusChange?.(cardPresent);
            }
            break;
        case 0x4E: // 无卡
            if (this.lastCardStatus) {
                this.lastCardStatus = false;
                console.log('❌ NO CARD');
                this.onCardStatusChange?.(false);
            }
            break;
        case 0x05: // 阅读器状态通知(需参考文档确认具体含义)
            // 添加对应处理逻辑,比如检查后续字节判断卡片状态
            break;
        default:
            console.log('未识别的响应码:', data[0].toString(16));
    }
}

3. BLE特征UUID可能不准确

虽然能连接设备,但需再次确认SERVICE_UUID、WRITE_CHARACTERISTIC和NOTIFY_CHARACTERISTIC是否与ACR1255U-J1的官方BLE服务UUID完全一致。部分设备可能使用不同的UUID变体,可通过BLE调试工具(如nRF Connect)扫描设备获取准确值。

内容的提问来源于stack exchange,提问作者Adriel García

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 13:32:34