Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

expo-barcode-scanner only works once with react-native version 0.64.2 and expo 43.0.0

Because of Google Play, I had to update an old project of mine to the latest expo versions (version 43.0.0 to be exact). The idea is for the app to scan a QRCode and process the data, simply. However, expo-barcode-scanner only works once and after that I need to close and open the app again to work. Has anyone encountered this problem and (or) knows how to solve it? Below is my code:

{escaneando ? (
                        <BarCodeScanner
                            barCodeTypes={[
                                BarCodeScanner.Constants.BarCodeType.ean13,
                                BarCodeScanner.Constants.BarCodeType.ean8,
                                BarCodeScanner.Constants.BarCodeType.upc_a,
                                BarCodeScanner.Constants.BarCodeType.upc_e,
                            ]}
                            onBarCodeScanned={this.handleBarCode.bind(this)}
                            style={[StyleSheet.absoluteFillObject, styles.barscan]}
                        />
                    ) : null}

And library specifications:

"@react-native-community/masked-view": "^0.1.11",
    "@react-native-community/netinfo": "^6.0.5",
    "@react-navigation/native": "^6.0.6",
    "@react-navigation/stack": "^6.0.11",
    "expo": "~43.0.0",
    "expo-av": "^10.1.3",
    "expo-barcode-scanner": "^11.1.2",
    "expo-status-bar": "~1.1.0",
    "lodash": "^4.17.21",
    "react": "17.0.1",
    "react-dom": "17.0.1",
    "react-native": "^0.64.2",
    "react-native-dropdownalert": "^4.3.0",
    "react-native-elements": "^3.4.2",
    "react-native-gesture-handler": "^1.10.3",
    "react-native-in-app-notification": "^3.2.0",
    "react-native-offline": "^6.0.0",
    "react-native-paper": "^4.10.0",
    "react-native-reanimated": "^2.2.3",
    "react-native-safe-area-context": "^3.3.2",
    "react-native-screens": "^3.9.0",
    "react-native-web": "0.17.1",
    "react-navigation": "^4.4.4",
    "react-redux": "^7.2.6",
    "redux": "^4.1.2",
    "redux-thunk": "^2.4.0",
    "reselect": "^4.1.2"
like image 642
Backup Gov18 Avatar asked Nov 05 '21 17:11

Backup Gov18


3 Answers

with expo-camera it works perfectly.

1)- install expo-camera : expo install expo-camera

this is the code for it :

import React, { useState, useEffect } from 'react';
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import { Camera } from 'expo-camera';

const QrcodeReader = ({navigation}) =>  {

  const [hasPermission, setHasPermission] = useState(null);
  const [type, setType] = useState(Camera.Constants.Type.back);

  useEffect(() => {
    (async () => {
      const { status } = await Camera.requestCameraPermissionsAsync();
      setHasPermission(status === 'granted');
    })();
  }, []);

  if (hasPermission === null) {
    return <View />;
  }
  if (hasPermission === false) {
    return <Text>No access to camera</Text>;
  }
  return(
  <View style={styles.container}>
      <Camera
        onBarCodeScanned={(...args) => {
          const data = args[0].data;
          result = JSON.stringify(result);
          console.log(result);
          navigation.navigate('your_next_screen',{result});
          );
        }}
        barCodeScannerSettings={{
          barCodeTypes: ['qr'],
        }}
        style={{ flex: 1 }}
      />
    </View>
  );
}
  
const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  camera: {
    flex: 1,
  },
  buttonContainer: {
    flex: 1,
    backgroundColor: 'transparent',
    flexDirection: 'row',
    margin: 20,
  },
  button: {
    flex: 0.1,
    alignSelf: 'flex-end',
    alignItems: 'center',
  },
  text: {
    fontSize: 18,
    color: 'white',
  },
});

export default QrcodeReader;
like image 142
chikabala Avatar answered Nov 15 '22 08:11

chikabala


Welcome @Backup Gov18,

This is a documented issue.

Note: Only one active BarCodeScanner preview is supported currently. When using navigation, the best practice is to unmount any previously rendered BarCodeScanner component so the following screens can use without issues.

There is a workaround.

Instead of conditionally rendering the <BarcodeScanner /> component, you could render it inside another dedicated screen component.

This way, after this new screen reads the barcode, you could navigate back to your first screen. Navigating back may unmount this new screen. You can force unmount if you need to.

As you are using react-navigation, you had better use .pop() instead of goBack().


Alternative

You can also use expo-camera instead of expo-barcode-scanner. expo-camera does not have this issue. It also offers more options like flashlight/torch and switching cameras.

like image 31
ofundefined Avatar answered Nov 15 '22 09:11

ofundefined


I faced the same problem and because it was a feature i couldnt work without, i persisted and found a solution that worked for me.

Because Only one active BarCodeScanner preview is supported, I went to react navigation and found a way to re-render the barcode scanner whenever the screen is in focus.

import { useIsFocused } from '@react-navigation/native'; useIsFocused returns true when a screen with the barcode scanner is the one in focus.

 {isFocused ? (
    <BarCodeScanner
      onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
      style={StyleSheet.absoluteFillObject}
    />) : null}

Read more on https://reactnavigation.org/docs/use-is-focused.

Full Example:

import React, { useState, useEffect } from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import { BarCodeScanner } from 'expo-barcode-scanner';
import { useIsFocused } from '@react-navigation/native';

export default function App() {
  const [hasPermission, setHasPermission] = useState(null);
  const [scanned, setScanned] = useState(false);

  console.log(hasPermission, scanned);
  const isFocused = useIsFocused();

  useEffect(() => {
    (async () => {
      setScanned(false);
      const { status } = await BarCodeScanner.requestPermissionsAsync();
      setHasPermission(status === 'granted');
    })();
  }, []);

  const handleBarCodeScanned = ({ type, data }) => {
    setScanned(true);
    alert(`Bar code with type ${type} and data ${data} has been scanned!`);
  };

  if (hasPermission === null) {
    return <Text>Requesting for camera permission</Text>;
  }
  if (hasPermission === false) {
    return <Text>No access to camera</Text>;
  }

  return (
    <View style={styles.container}>
      {isFocused ? (
        <BarCodeScanner
          onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
          style={StyleSheet.absoluteFillObject}
        />
      ) : null}
      {scanned && (
        <Button title={'Tap to Scan Again'} onPress={() => setScanned(false)} />
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    justifyContent: 'center',
  },
});
like image 32
nkangi jafari Avatar answered Nov 15 '22 09:11

nkangi jafari