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 = [] } 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 { // 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::() .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::(); 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"); } 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 ( Read NFC! read NFC ); } export default App; Executando a Aplicação Inicie seu ambiente: yarn tauri dev Agora, ao pressionar o botão "Ler NFC", o UID do cartão será capturado e exibido no console. Cartão Adicionado Com sucesso Caso cartão não conectado ao leitor Caso leitor não conectado 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! ✌️

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 = [] }
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 {
// 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::>()
.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::();
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");
}
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 (
Read NFC!
);
}
export default App;
Executando a Aplicação
Inicie seu ambiente:
yarn tauri dev
Agora, ao pressionar o botão "Ler NFC", o UID do cartão será capturado e exibido no console.
Cartão Adicionado
Com sucesso
Caso cartão não conectado ao leitor
Caso leitor não conectado
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! ✌️