<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Leandro Campos</title>
    <description>The latest articles on Forem by Leandro Campos (@leandrocampos).</description>
    <link>https://forem.com/leandrocampos</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F803477%2F4b13aa6a-f1a9-404b-95a4-bdc82f7e78ec.JPG</url>
      <title>Forem: Leandro Campos</title>
      <link>https://forem.com/leandrocampos</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/leandrocampos"/>
    <language>en</language>
    <item>
      <title>Como Utilizar o Leitor NFC ACR122U/ACR122 no Tauri com Rust</title>
      <dc:creator>Leandro Campos</dc:creator>
      <pubDate>Fri, 28 Mar 2025 17:03:34 +0000</pubDate>
      <link>https://forem.com/leandrocampos/como-utilizar-o-leitor-nfc-acr122uacr122-no-tauri-com-rust-4e0c</link>
      <guid>https://forem.com/leandrocampos/como-utilizar-o-leitor-nfc-acr122uacr122-no-tauri-com-rust-4e0c</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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).&lt;/p&gt;

&lt;p&gt;Ambiente de desenvolvimento: [windows].&lt;/p&gt;

&lt;h2&gt;
  
  
  Requisitos
&lt;/h2&gt;

&lt;p&gt;Teste realizado com as seguintes condições: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Leitor NFC ACR122U&lt;/li&gt;
&lt;li&gt;Rust e Cargo&lt;/li&gt;
&lt;li&gt;Tauri CLI&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configurando o Backend (Rust)
&lt;/h2&gt;

&lt;p&gt;Vamos criar um comando no Tauri para interagir com o leitor NFC.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependências
&lt;/h2&gt;

&lt;p&gt;Adicione a dependência pcsc ao seu &lt;code&gt;Cargo.toml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[dependencies]
pcsc = "2.9.0"
tauri = { version = "2.0", features = [] }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Implementação em Rust
&lt;/h2&gt;

&lt;p&gt;A seguir, o código que configura a leitura do UID do cartão NFC no main.rs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// 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() -&amp;gt; Result&amp;lt;String, String&amp;gt; {
    // Sets the context
    let ctx = match Context::establish(Scope::User) {
        Ok(ctx) =&amp;gt; ctx,
        Err(err) =&amp;gt; return Err(format!("Error establishing context: {:?}", err)),
    };

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

    // Converts readers into a collection for verification
    let reader_iter = readers.into_iter();
    let reader_vec: Vec&amp;lt;_&amp;gt; = 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(|&amp;amp;&amp;amp;r| r.to_str().map(|s| s.contains("ACR122")).unwrap_or(false))
    {
        Some(&amp;amp;reader) =&amp;gt; reader,
        None =&amp;gt; {
            // List available readers on error
            let available_readers: String = reader_vec
                .iter()
                .map(|r| r.to_str().unwrap_or("Invalid name").to_string())
                .collect::&amp;lt;Vec&amp;lt;String&amp;gt;&amp;gt;()
                .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) =&amp;gt; card,
        Err(err) =&amp;gt; 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(&amp;amp;apdu, &amp;amp;mut buffer) {
        Ok(response) =&amp;gt; response,
        Err(err) =&amp;gt; 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::&amp;lt;String&amp;gt;();

    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");
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  No seu Frontend (React/TypeScript)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Implementação do App.tsx
&lt;/h3&gt;

&lt;p&gt;Crie um componente React para chamar a função do backend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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 =&amp;gt;', uid);
    } catch (error) {
      console.error('Error reading NFC:', error);
    }
  }

  return (
    &amp;lt;main className="container"&amp;gt;

      &amp;lt;div&amp;gt;
        &amp;lt;h1&amp;gt;Read NFC!&amp;lt;/h1&amp;gt;

        &amp;lt;button id="read-nfc-btn" onClick={readNFC}&amp;gt;read NFC&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;

    &amp;lt;/main&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Executando a Aplicação
&lt;/h2&gt;

&lt;p&gt;Inicie seu ambiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn tauri dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, ao pressionar o botão "Ler NFC", o UID do cartão será capturado e exibido no console.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cartão Adicionado
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flm71wwpdhmsf0r8utogz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flm71wwpdhmsf0r8utogz.jpg" alt=" " width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Com sucesso
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faa64chv5rs4focuu7ihr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faa64chv5rs4focuu7ihr.png" alt=" " width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Caso cartão não conectado ao leitor
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdnkhb9edjlpnvzak8y3b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdnkhb9edjlpnvzak8y3b.png" alt=" " width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Caso leitor não conectado
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fprbjr35mgz3podqzbxow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fprbjr35mgz3podqzbxow.png" alt=" " width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Detalhe
&lt;/h3&gt;

&lt;p&gt;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.  &lt;/p&gt;

&lt;p&gt;Se tiver alguma dúvida ou sugestão, deixe seu comentário! ✌️&lt;/p&gt;

&lt;p&gt;Link repositório: &lt;a href="https://github.com/jleandrocampos/tauriReaderNFC" rel="noopener noreferrer"&gt;https://github.com/jleandrocampos/tauriReaderNFC&lt;/a&gt;&lt;/p&gt;

</description>
      <category>development</category>
      <category>tauri</category>
      <category>react</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
