react-qr-reader icon indicating copy to clipboard operation
react-qr-reader copied to clipboard

iOS doesn't rerender component after grant permissions [BUG]

Open WebTravel opened this issue 3 years ago • 0 comments

So, I noticed the difference behavior in chrome android and safari iOS browsers. I have the next code

export const QRCodeScanner = ({ onDecode, onClose, onDecodeError }) => {
    const status = useCameraPermission();

    const handleResult = useCallback(
        (result, error) => {
            result && onDecode(result.getText());
        },
        [onDecode, onDecodeError],
    );

    return (
        <div>
            {status === "granted" && (
                <QrReader
                    onResult={handleResult}
                    constraints={{
                        aspectRatio: 1,
                        facingMode: "environment",
                    }}
                    videoId="react-qr-reader"
                />
            )}
        </div>
    );
};

And it works for safari because QrReader component appears to page only AFTER user allows permission, pressing the button "Allow camera" in prompt window in safari IOS browser. And this works great! But the same code doesn't work in chrome in android browser, because the prompt window doesn't appear and user can't to allow permission. I suppose the prompt window in safari browser works outside the component while the prompt window in chrome android works inside it.

So, the next code will works in chrome android but doesn't work in safari IOS. After user allow use the camera and status updated doesn't happen anything.

export const QRCodeScanner = ({ onDecode, onClose, onDecodeError }) => {
    const status = useCameraPermission();

    const handleResult = useCallback(
        (result, error) => {
            result && onDecode(result.getText());
        },
        [onDecode, onDecodeError],
    );

    return (
        <div>
                <QrReader
                    onResult={handleResult}
                    constraints={{
                        aspectRatio: 1,
                        facingMode: "environment",
                    }}
                    videoId="react-qr-reader"
                />
        </div>
    );
};

And I reproduce the hook code. I wrote it, because I can check permissions before the QrReader will render to my page. And really needed functionality.

export const useCameraPermission = () => {
    const [status, setStatus] = useState<PermissionState>();

    const checkPermission = useCallback(() => {
        !window.navigator && setStatus("granted");
        window?.navigator?.permissions
            ? window.navigator.permissions
                  .query({ name: "camera" })
                  .then((status) => {
                      setStatus(status.state);
                  })
                  .catch((err) => err.name === "NotAllowedError" && setStatus("denied"))
            : window?.navigator?.mediaDevices
                  .getUserMedia({ video: true })
                  .then((stream) => {
                      stream.active && setStatus("granted");
                  })
                  .catch((err) => {
                      err.name === "NotAllowedError" && setStatus("denied");
                  });
    }, []);

    useEffect(checkPermission, [checkPermission]);

    return status;
};

Any workaround for solving this?

WebTravel avatar Sep 05 '21 09:09 WebTravel