mrousavy / react-native-vision-camera

📸 A powerful, high-performance React Native Camera library.
https://react-native-vision-camera.com
MIT License
7.25k stars 1.06k forks source link

🐛 Scanned value on QR code returns null on Android, works in iOS #2128

Closed pabloguzman20 closed 10 months ago

pabloguzman20 commented 10 months ago

What's happening?

First of all I admire the work and support of the creator as well as the community.

I am working on the process of digitizing the social security number in the institution where I currently work. Initially I tested on iOS and everything worked perfectly.

When testing on Android I realized that the scanned QR always returns null.

Initially I thought it was an implementation or configuration error of mine. But testing with online QR code decoders I realized that several work and others do not.

The format of the scanned QR is as follows:

||Número de Seguridad Social: 05169235823 |Nombre: NAME OF THE PERSON |CURP: XXXXXXX8408343||

Package.json settings : "react-native-vision-camera": "^3.6.4" "react-native": "^0.71.6",

BuildScript ext buildToolsVersion = "33.0.0" minSdkVersion = 26 compileSdkVersion = 33 targetSdkVersion = 33

BuildScript dependencies classpath("com.android.tools.build:gradle:7.3.1")

AndroidManifiest: <meta-data android:name="com.google.mlkit.vision.DEPENDENCIES" android:value="barcode" />

Reproduceable Code

import * as React from 'react';
import { Alert, Image, StyleSheet, View } from 'react-native';
import { useIsFocused } from '@react-navigation/native';
import { NoCameraPermission } from 'src/components/pages';
import { GoBack } from 'src/components/atoms';
import { useBoolean, useCustomNavigation } from 'src/hooks';
import { Camera, useCameraDevice, useCodeScanner } from 'react-native-vision-camera';
import customStyles from 'src/styles';

const QRScanner: React.FC = (): JSX.Element => {
  const { value, toggle } = useBoolean();
  const device = useCameraDevice('back', {
    physicalDevices: ['wide-angle-camera']
  });
  const isFocused = useIsFocused();

  React.useLayoutEffect(() => {
    (async () => {
      const status = await Camera.requestCameraPermission();
      toggle(status === 'granted');
    })();
  }, [value]);

  const codeScanner = useCodeScanner({
    codeTypes: ['qr'],
    onCodeScanned: codes => {
      Alert.alert(codes.length > 0 ? "Has data" : "No data", `Type ${codes[0].type} and value ${codes[0].value}`);
    },
  });

  return device != null && value ? (
    <View style={[customStyles.safeAreaContainer, { paddingTop: insets.top }]}>
      <View style={styles.navigationContainer}>
        <GoBack route="Home" screen="User" />
      </View>
      <View style={[styles.backgroundContainer, customStyles.center]}>
        <Image
          source={require('src/images/qrScan.png')}
          style={styles.backgroundImage}
        />
      </View>
      <View>
        <Camera
          style={styles.camera}
          device={device}
          isActive={isFocused}
          codeScanner={codeScanner}
        />
      </View>
    </View>
  ) : (
    <NoCameraPermission />
  );

};

export default QRScanner;

const styles = StyleSheet.create({
 ...
});

Relevant log output

onCodeScanned value scanned return null only on Android. Works perfectly on iOS

Camera Device

Any camera device

Device

Samsung S21 with Android 12

VisionCamera Version

3.6.4

Can you reproduce this issue in the VisionCamera Example app?

Yes, I can reproduce the same issue in the Example app here

Additional information

OtayNacef commented 10 months ago

Hello I'm experiencing the same Error : unknown/unknown: [unknown/unknown] failed to create thin barcode scanner. Device : S21+

hikaru-w commented 10 months ago

When I also scan the QR code, null enters the value. Is the same. "react-native": "0.72.6", "react-native-vision-camera": "^3.6.4", Device is pixel6a The content of the QR code is Japanese JSON, Shift_JIS. I don't know, but it might be because the software can't decode it. As a side note, it can be read normally on iOS17.0.3, but on iOS17.1 the Japanese QR code cannot be read and a null value is returned. As a stopgap, Android is using react-native-camera to read QR codes.

OtayNacef commented 10 months ago

Hello I'm experiencing the same Error : unknown/unknown: [unknown/unknown] failed to create thin barcode scanner. Device : S21+

i resolved the issue by updating Google Play Services

GolexPrime commented 10 months ago

Had the same problem. Turns out if the code is not in UTF-8 you'll get null as response using Android: https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/common/Barcode#public-string-getrawvalue. Funny thing is my code is in UTF-8 (with special characters) and its still not working 😓

The displayValue on the other hand is working (at least in the scenarios I tested/care-about).

You can apply a patch to CameraView+Events.kt to make it work. Just replace

code.putString("value", barcode.rawValue)

with

code.putString("value", barcode.rawValue ?: barcode.displayValue ?: null)

or any other Shenanigans you want to to do with it. But that might produce unforeseen consequences...

pabloguzman20 commented 10 months ago

@GolexPrime Hey man, you did it! I applied the patch in CameraView+Events.tk and it worked. I think this is either an MLKIT bug or there is something I may be overlooking.

hikaru-w commented 10 months ago

Thank you very much. It worked well too! However, only a small portion of the Japanese was garbled, so it looks like it needs to be fixed. I would be very grateful if you could just tell me what needs to be fixed.

GolexPrime commented 10 months ago

However, only a small portion of the Japanese was garbled, so it looks like it needs to be fixed. I would be very grateful if you could just tell me what needs to be fixed.

Thats the direct output provided by MLKIT - it doesn't seem to like anything fancy in its scanned content 😓

hikaru-w commented 10 months ago

I was able to successfully avoid the garbled characters using the code below.

import java.nio.charset.Charset

val rawqrcode = barcode?.rawBytes
val string = rawqrcode?.let { String(it, Charset.forName("Shift_JIS")) }
DavidHuertasF commented 6 months ago

Had the same problem. Turns out if the code is not in UTF-8 you'll get null as response using Android: https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/common/Barcode#public-string-getrawvalue. Funny thing is my code is in UTF-8 (with special characters) and its still not working 😓

The displayValue on the other hand is working (at least in the scenarios I tested/care-about).

You can apply a patch to CameraView+Events.kt to make it work. Just replace

code.putString("value", barcode.rawValue)

with

code.putString("value", barcode.rawValue ?: barcode.displayValue ?: null)

or any other Shenanigans you want to to do with it. But that might produce unforeseen consequences...

Thank you

olivertylsar commented 3 months ago

Worked for me as well! Thank you.

@mrousavy, would you consider making this fallback to displayValue the default behavior of the library on Android or returning both raw and display values?

I had trouble scanning one particular QR code and thought I would need to use another barcode reader instead of the ML Kit that is used by default. There is a community plugin for the frame processor using the Dynamsoft reader. I tried their demo, and I could scan the QR code. ML Kit can obviously scan it too, but there was no way for me to know until I found this issue, and that took me a while.

Thanks.