serratus/quaggaJS

QuaggaJS Barcode scanner not working for Androids

shayanvalaie opened this issue · 1 comments

I have created a barcode scanner in my react component using QuaggaJS. The scanner is meant to be used on mobile devices through the web view. It's working fine on all iPhone devices but is not scanning correctly on androids. I am guessing this is a resolution issue in the constraints but have not found a solution that works.

import { useNavigate } from "react-router-dom";
import Quagga from "@ericblade/quagga2";
import adapter from "webrtc-adapter";
import LogService from "../../services/LogService";
import "./BarcodeScanner.css";

const BarcodeScanner = (props) => {
  const navigate = useNavigate();
  const logService = new LogService();
  let mainCameraDeviceId = "";

  

  useEffect(() => {
    async function getBackDevices() {
      await Quagga.CameraAccess.request();

      let devices = await Quagga.CameraAccess.enumerateVideoDevices()
      .then((devices) => devices)
      .catch((err) => {
        logService.Log("Error", "Error when enumerating video devices", err);
        console.error(`${err.name}: ${err.message}`);
      });

      let backDevices = [];

      devices.forEach((device) => {
        logService.Log("Debug", "Detected Device",device);
        if(device.kind.toLowerCase().includes("videoinput") && device.label.toLowerCase().includes("back")) {
          backDevices.push(device);
          console.log(`${device.kind}: ${device.label} id = ${device.deviceId}`);
        }
      });

      if (backDevices.length == 0 && devices.length == 1) {
        backDevices.push(devices[0]);
      }

      logService.Log("Debug", "Detected back devices", backDevices);
      mainCameraDeviceId = backDevices[backDevices.length-1].deviceId;  
      startQuagga();
    }
    
    getBackDevices();
  }, []);


  function startQuagga() {
    logService.Log("Debug", "Selected camera device", mainCameraDeviceId);

    let customConstraints = {
      focusMode: 'continuous',
      facingMode: "environment",
      zoom: {min: 1.5, max: 2},
      deviceId: mainCameraDeviceId,
      width: 640,
      height: 480
    }
    
    if(props.deviceType == "iPhone") {
      customConstraints.width = { min: 480 };
      customConstraints.height = { min: 1281 };
    }

    

    logService.Log("Debug", "Device Type", props.deviceType);
    logService.Log("Debug", "Quagga constraints", customConstraints);

    try {
      Quagga.init(
        {
          inputStream: {
            name: "Live",
            type: "LiveStream",
            target: document.querySelector("#interactive"),
            constraints: customConstraints
          },
          locate: true,
          decoder: {
            readers: [
              "upc_reader"
            ],
            multiple: false
          },
        },
        function (err) {
          if (err != null) {
            console.log(err);
            props.onError(err);
            stopScanner();
            return;
          }
          console.log("Initialization finished. Ready to start");
          Quagga.start();
        }
      );
    } catch {
      props.onError("Failed to open camera");
    }
  }

  Quagga.onDetected((data) => {
    props.onDetected(data.codeResult.code);
    Quagga.stop();

  });


  const stopScanner = () => {
    console.log("stopping Quagga");
    Quagga.stop();
  };


  return (
    <div
    
      className="barcode-scanner viewport"
      id="interactive"
    >
      
      <div className="box-overlay"></div>
    </div>
  );
};

export default BarcodeScanner;```

my experience is that you can give a camera deviceId or a facingMode as a constraint, but not both. Also, most Androids these days seem to have a camera device that goes to a wide-angle lens, which is useless for barcode scanning because of the fisheye effect. I haven't figured out a good way to filter those devices out, so until/unless s omeone does come up with a good way, it's probably best to let the user supply which camera device works.