DEV Community

Leandro Campos
Leandro Campos

Posted on

5 2 2 2 2

Como Utilizar o Leitor NFC ACR122U/ACR122 no Tauri com Rust

Introdução

Neste post, apresento uma solução para integrar o leitor NFC ACR122U em uma aplicação Tauri, utilizando Rust no backend para comunicação com o dispositivo.

O objetivo é demonstrar como obter o UID de um cartão NFC e utilizar essa informação no React (ou qualquer framework suportado pelo Tauri).

Ambiente de desenvolvimento: [windows].

Requisitos

Teste realizado com as seguintes condições:

  • Leitor NFC ACR122U
  • Rust e Cargo
  • Tauri CLI

Configurando o Backend (Rust)

Vamos criar um comando no Tauri para interagir com o leitor NFC.

Dependências

Adicione a dependência pcsc ao seu Cargo.toml:

[dependencies]
pcsc = "2.9.0"
tauri = { version = "2.0", features = [] }
Enter fullscreen mode Exit fullscreen mode

Implementação em Rust

A seguir, o código que configura a leitura do UID do cartão NFC no main.rs:

// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use pcsc::*;

#[tauri::command]
fn read_nfc() -> Result<String, String> {
    // Sets the context
    let ctx = match Context::establish(Scope::User) {
        Ok(ctx) => ctx,
        Err(err) => return Err(format!("Error establishing context: {:?}", err)),
    };

    // Buffer for listing readers
    let mut buffer = [0u8; 1024];
    let readers = match ctx.list_readers(&mut buffer) {
        Ok(readers) => readers,
        Err(err) => return Err(format!("Error listing readers: {:?}", err)),
    };

    // Converts readers into a collection for verification
    let reader_iter = readers.into_iter();
    let reader_vec: Vec<_> = reader_iter.collect();

    // Checks for connected readers
    if reader_vec.is_empty() {
        return Err("No reader connected".to_string());
    }

    // Search for ACR122
    let reader_name = match reader_vec
        .iter()
        .find(|&&r| r.to_str().map(|s| s.contains("ACR122")).unwrap_or(false))
    {
        Some(&reader) => reader,
        None => {
            // List available readers on error
            let available_readers: String = reader_vec
                .iter()
                .map(|r| r.to_str().unwrap_or("Invalid name").to_string())
                .collect::<Vec<String>>()
                .join(", ");
            return Err(format!(
                "ACR122 reader not found. Available readers: {}",
                available_readers
            ));
        }
    };

    // Connects to the reader
    let card = match ctx.connect(reader_name, ShareMode::Shared, Protocols::ANY) {
        Ok(card) => card,
        Err(err) => return Err(format!("Error connecting to reader: {:?}", err)),
    };

    // Send APDU command to read UID
    let apdu = [0xFF, 0xCA, 0x00, 0x00, 0x00];
    let mut buffer = [0u8; 256];
    let response = match card.transmit(&apdu, &mut buffer) {
        Ok(response) => response,
        Err(err) => return Err(format!("Error reading tag: {:?}", err)),
    };

    // Format UUID as hexadecimal string
    let uid = response[..response.len() - 2]
        .iter()
        .map(|b| format!("{:02X}", b))
        .collect::<String>();

    Ok(uid)
}

fn main() {
    tauri::Builder::default()
        .plugin(tauri_plugin_opener::init())
        .invoke_handler(tauri::generate_handler![read_nfc])
        .run(tauri::generate_context!())
        .expect("Erro ao executar aplicação Tauri");
}

Enter fullscreen mode Exit fullscreen mode

No seu Frontend (React/TypeScript)

Implementação do App.tsx

Crie um componente React para chamar a função do backend:

import { invoke } from "@tauri-apps/api/core";
import "./App.css";

function App() {

  async function readNFC() {
    try {
      const uid = await invoke('read_nfc');
      console.log('Card UID =>', uid);
    } catch (error) {
      console.error('Error reading NFC:', error);
    }
  }

  return (
    <main className="container">

      <div>
        <h1>Read NFC!</h1>

        <button id="read-nfc-btn" onClick={readNFC}>read NFC</button>
      </div>

    </main>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Executando a Aplicação

Inicie seu ambiente:

yarn tauri dev
Enter fullscreen mode Exit fullscreen mode

Agora, ao pressionar o botão "Ler NFC", o UID do cartão será capturado e exibido no console.

Cartão Adicionado

Image description

Com sucesso

Image description

Caso cartão não conectado ao leitor

Image description

Caso leitor não conectado

Image description

Conclusão

Com essa solução, conseguimos integrar um leitor NFC ACR122U em um aplicativo Tauri com Rust no backend. Essa abordagem permite que criem aplicações desktop sem executáveis externos que use outras formas dependências de comunicação entre o sistemas e o leitor.

Detalhe

Em meus testes meu leitor ACR122U foi reconhecido no meu Windows como ACR122 com os drivers devidos instalados por conta disso o código foi preparado para listar os leitores disponíveis, caso ainda sim não funcione como o esperado tente verificar qual nome o Windows atribuiu ao seu leitor.

Se tiver alguma dúvida ou sugestão, deixe seu comentário! ✌️

Link repositório: https://github.com/jleandrocampos/tauriReaderNFC

Top comments (3)

Collapse
 
fs_matheus_fs profile image
Matheus Ferreira dos Santos

Bem mastigadinho, do jeitinho que os leigos gostam

Collapse
 
1mourao profile image
Alan Mourão

Top de mais!

Collapse
 
samukadev profile image
Samuel Torres

Bacana demais, quando precisar ja tenho onde vir estudar uma implementação