expo-barcode-scanner 仅适用于 react-native 版本 0.64.2 和 expo 43.0.0

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

因为 Google Play,我不得不将我的一个旧项目更新到最新的 expo 版本(确切地说是 43.0.0 版)。这个想法是让应用程序简单地扫描二维码并处理数据。但是,expo-barcode-scanner 只能工作一次,之后我需要关闭并再次打开该应用程序才能工作。有没有人遇到过这个问题和(或)知道如何解决? 下面是我的代码:

{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}

和图书馆规格:

"@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"

欢迎@Backup Gov18,

这是一个 documented 问题。

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.

有一个解决方法。

您可以在另一个专用屏幕组件中渲染它,而不是有条件地渲染 <BarcodeScanner /> 组件。

这样,在这个新屏幕读取条形码后,您可以导航回您的第一个屏幕。向后导航可能会卸载这个新屏幕。如果需要,您可以强制卸载。

因为你正在使用react-navigation,你最好使用.pop()而不是goBack()


备选方案

您也可以使用 expo-camera 代替 expo-barcode-scannerexpo-camera 没有这个问题。它还提供更多选项,例如 flashlight/torch 和切换相机。

找到了这个解决方法:

编辑文件BarCodeScannerViewFinder.kt 位于: [您的项目]\node_modules\expo-barcode-scanner\android\src\main\java\expo\modules\barcodescanner 在声明部分(第 44 行左右)添加以下两行:

@volatile 私有变量 barCodeScannerTaskLock = false

对我来说很好。

expo-camera 完美配合。

1)- 安装 expo-camera : expo install expo-camera

这是它的代码:

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;

我遇到了同样的问题,因为这是我不能没有的功能,所以我坚持并找到了适合我的解决方案。

因为只支持一个活动的 BarCodeScanner 预览,所以我去反应导航并找到了一种方法 re-render 条形码扫描仪只要屏幕处于焦点。

从“@react-navigation/native”导入{useIsFocused}; useIsFocused returns 当带有条形码扫描仪的屏幕处于焦点时为真。

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

https://reactnavigation.org/docs/use-is-focused 上阅读更多内容。

完整示例:

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',
  },
});