Search code examples
javascriptgoogle-chromelibusblib-nfcwebnfc

Reading from an NFC reader directly into a desktop web application?


I have LibNFC working from the Linux terminal recognising my ACR122U Reader, and I wanted to know if there was a method for it to work through Chrome on a Linux Desktop as it is really similar to Android Support, with all the NFC device handling done by libnfc and the browser just has to know about this library instead of every type usb or other device than can do NFC.

I have tried using the WebNFC API to connect it :

document.getElementById("scanButton").addEventListener("click", async () => {
    log.innerHTML = "NFC Register started...";

    try {
      const ndef = new NDEFReader();
      await ndef.scan();
      log.innerHTML = ("> Scan started");
  
      ndef.addEventListener("readingerror", () => {
        log.innerHTML = ("Argh! Cannot read data from the NFC tag. Try another one?");
      });
  
      ndef.addEventListener("reading", ({ message, serialNumber }) => {
        log.innerHTML = ("ID  ${serialNumber} logged @" + dt.toLocaleTimeString());   });
    } catch (error) {
      log.innerHTML = (error);
    }
  });

  document.getElementById("stopButton").onclick = function(){
    log.innerHTML = "NFC Register stopped @ " + new Date().toLocaleTimeString();
    }; 

but I'm met with Error: NFC Permission Request denied

and the WebUSB API to connect it:

var usbd = {};
let device;
let deviceEndpoint = 0x02;

let powerUpDevice = new Uint8Array([0x62,0x00, 0x00, 0x00, 0x00,0x00,0x00,0x01,0x00, 0x00]).buffer;
let getCardUID = new Uint8Array([0xff,0xca,0x00,0x00,0x04]).buffer;

(function() {
    'use strict';

    usbd.authorize = function(){
        navigator.usb.requestDevice({ filters: [{ vendorId: 0x072f }] })
            .then(selectedDevice => {
                device = selectedDevice;
                console.log(device.configuration.interfaces[0].interfaceNumber);
                console.log(device.manufacturerName);
                console.log(device.productName);
                console.log(device);
                return device.open()
                    .then(() => {
                        if (device.configuration === null) {
                            return device.selectConfiguration(1);
                        }
                    });
            })
            .then(() => device.claimInterface(0))

but I'm met with Error: ...blocked because it implements a protected interface class i.e. not supported, so that's a no go.

Is there a way to incorporate the libusb/libnfc libraries or any other method to directly connect an NFC reader to read into a web browser/application?


Solution

  • Web NFC is supported on Android only as of February 2021. See https://web.dev/nfc/

    The WebUSB error suggests you're requesting an interface that implements a protected class (among those below):

      // USB Class Codes are defined by the USB-IF:
      // https://www.usb.org/defined-class-codes
      const uint8_t kProtectedClasses[] = {
          0x01,  // Audio
          0x03,  // HID
          0x08,  // Mass Storage
          0x0B,  // Smart Card
          0x0E,  // Video
          0x10,  // Audio/Video
          0xE0,  // Wireless Controller (Bluetooth and Wireless USB)
      };
    

    I wonder if that's a linux thing though as I was able to communicate with the ACR122U and SCL3711 NFC reader USB devices through WebUSB. See https://github.com/beaufortfrancois/chrome-nfc

    Did you give a try to WebHID by any chance first? See https://web.dev/hid