简体   繁体   中英

React native QR scanner to webview

I converted my app from expo to bare react native. I had a barcode/QR scanner that was working great with the expo module "Expo-bar-code-scanner" I tried to convert from expo bar code scanner to React native qr scanner but I've been running into problems and not sure how to fix. What is expected is to scan a qr code containing a URL and have that opened in a webview. What is happening however since converting is webview failing to open and my overlay is failing to display.

Please help... Thank you:)

Below is my QRscreen.js. URL's are omitted

import React, { useState, useEffect } from 'react';
  import { Text, View, StyleSheet, Button, Modal, TouchableHighlight, Image } from 'react-native';
  import { WebView } from 'react-native-webview';
  import QRCodeScanner from 'react-native-qrcode-scanner';
  import { RNCamera } from 'react-native-camera';

  export default function App(){
    const [hasPermission, setHasPermission] = useState(null);
    const [scanned, setScanned] = useState(true);
    const [modalVisible, setModalVisible] = useState(true);
    const [uri, setUri] = useState('omitted');


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

const handleBarCodeScanned = ({ type, data }) => {
  setScanned(true);
  setModalVisible(true);
    // console.warn("Scan returned " + data);
    setUri({ uri: data })
};



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

return (
  <View
    style={{
      flex: 1,
      flexDirection: 'column'
    }}>
    <Modal
      animationType="slide"
      transparent={false}
      visible={modalVisible}
      onRequestClose={() => {
        setScanned(false);
      }}>
      <View style={{ flex: 1 }}>
        <WebView
          style={{ flex: 1 }}
          source={{uri: uri['uri']}}
        />

        <TouchableHighlight
          style={{
            backgroundColor:'black',
            padding: 15,
            alignItems: 'center'
          }}
          onPress={() => {
            setModalVisible(!modalVisible);
            setScanned(false);
          }}
          underlayColor='slategray'
        >
          <Text style={{ color:'white', fontSize: 15 }}>Re Scan</Text>
        </TouchableHighlight>
      </View>
    </Modal>

    <QRCodeScanner
      onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
      style={{
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
      }}>
      <View style={{ marginBottom: 100 }}>
        <View style={{ alignItems: 'center', marginBottom: 5 }}>
          <Image
            style={{
              width: 100,
              height: 100,
              resizeMode: 'contain',
              marginBottom: 20,
            }}
            source={{ uri: 'omitted' }}
          />
          <Text style={{ color: 'white', fontSize: 20, fontWeight: 'bold', paddingBottom: 10}}>
            QR Code Reader
          </Text>
        </View>
        <View
          style={{
            borderColor: 'white',
            borderTopWidth: 5,
            borderBottomWidth: 5,
            borderLeftWidth: 1,
            borderRightWidth: 1,
            paddingVertical: 80,
            paddingHorizontal: 100,
          }}
        />

        <View style={{ alignItems: 'center', marginTop: 5 }}>
          <Text style={{ color: 'white', fontSize: 15}}>
            QR Scan...
          </Text>
        </View>
      </View>
    </QRCodeScanner>
    </View>
);
        }

You are Setting the Uri state incorrectly as setUri is string by inference provided as "omitted" so how could it will accept {} .

So change

setUri({ uri: data })

to

setUri(data)

assuming you are confirmed that data is a string. Check this by logging it before setting to the setUri .

And also change

source={{uri: uri['uri']}}

with

source={{uri}}

as uri is obliviously not an array.

You are using the WebView component from react-native-webview package to display the scanned URL, but it seems that the uri prop is not being passed correctly to the WebView. You are setting the state for uri with an object containing a single property uri: data , but in your WebView component, you are trying to access the uri property of the uri object, so it should be source={{uri: uri.uri}} instead of source={{uri: uri['uri']}} .

You are using setModalVisible(true) in the handleBarCodeScanned function, but it seems like you want to display the modal only when a QR code is scanned successfully, so you should only set the modal visible when scanned is false.

You should also make sure that the WebView is only rendered when a URL is scanned, otherwise the app will crash when trying to open an empty URL.

Here is an example of how you can modify your code to fix these issues:

const handleBarCodeScanned = ({ type, data }) => {
    setScanned(true);
    setUri({ uri: data });
    if (!scanned) {
        setModalVisible(true);
    }
};

...

return (
    <View style={{ flex: 1, flexDirection: 'column' }}>
        <Modal
            animationType="slide"
            transparent={false}
            visible={modalVisible}
            onRequestClose={() => {
                setScanned(false);
            }}
        >
            <View style={{ flex: 1 }}>
                {uri.uri && <WebView style={{ flex: 1 }} source={{ uri: uri.uri }} />}
                <TouchableHighlight
                    style={{
                        backgroundColor: 'black',
                        padding: 15,
                        alignItems: 'center',
                    }}
                    onPress={() => {
                        setModalVisible(false);
                        setScanned(false);
                    }}
                >
                    <Text style={styles.buttonText}>Re Scan</Text>
                </TouchableHighlight>
            </View>
        </Modal>
        <QRCodeScanner
            onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
            style={{
                flex: 1,
                justifyContent: 'center',
                alignItems: 'center',
            }}
        >
            <View style={{ marginBottom: 100 }}>
                <View style={{ alignItems: 'center', marginBottom: 5 }}>
                    <Image
                        style={{
                            width: 100,
                            height: 100,
                            resizeMode: 'contain',
                            marginBottom: 20,
                        }}
                        source={{ uri: 'omitted' }}
                    />
                    <Text style={{ color: 'white', fontSize: 20, fontWeight: 'bold', paddingBottom: 10 }}>
                        QR Code Reader
                    </Text>
                </View>
                <View
                    style={{
                        borderColor: 'white',
                        borderTopWidth: 5,
                        borderBottomWidth: 5,
                        borderLeftWidth: 1,
                        borderRightWidth: 1,
                        paddingVertical: 80,
                        paddingHorizontal: 100,
                    }}
                />
                <View style={{ alignItems: 'center' }}>
                    <Text style={styles.centerText}>
                        <Text style={styles.textBold}>Scan a QR code</Text> to see the result
                    </Text>
                </View>
            </View>
        </QRCodeScanner>
    </View>
);

Also here a style sheet:

const styles = StyleSheet.create({
centerText: {
flex: 1,
fontSize: 18,
padding: 32,
color: '#777',
},
textBold: {
fontWeight: '500',
color: '#000',
},
buttonText: {
fontSize: 21,
color: 'rgb(0,122,255)',
},
buttonTouchable: {
padding: 16,
},
});

That's my QR scanner is showing up and it is able to scan the QR code. Also, I'm not sure if it's necessary but here is my package.json is as follows:

{
"name": "my_qrscan_app",
"version": "0.0.1",
"private": true,
"scripts": {
  "start": "react-native start",
  "android": "react-native run-android",
  "ios": "react-native run-ios",
  "web": "expo start --web",
  "eject": "react-native eject"
},
"dependencies": {
  "@react-native-community/masked-view": "^1.2.4",
  "@react-navigation/native": "^5.5.1",
  "@react-navigation/stack": "^5.5.1",
  "react": "16.13.1",
  "react-dom": "16.13.1",
  "react-native": "^0.66.0",
  "react-native-gesture-handler": "^1.7.0",
  "react-native-qrcode-scanner": "^1.1.4",
  "react-native-reanimated": "^1.13.0",
  "react-native-web": "^0.13.12",
  "react-native-webview": "^10.8.0",
  "react-navigation": "^4.0.10"
},

The reason for the not expected output is using onBarCodeScanned method to listen the event on scanning success, but as per requirements I can see you are scanning QRCode not BarCode .

Have a try by using below example:

import React, {useState, useEffect, useRef} from 'react';
import {
  Text,
  View,
  StyleSheet,
  Button,
  Modal,
  TouchableHighlight,
  Image,
} from 'react-native';
import {WebView} from 'react-native-webview';
import QRCodeScanner from 'react-native-qrcode-scanner';

export default function App() {
  const [hasPermission, setHasPermission] = useState(null);
  const [modalVisible, setModalVisible] = useState(true);
  const [uri, setUri] = useState('omitted');

  //   useEffect(() => {
  //     (async () => {
  //       const {status} = await QRCodeScanner?.requestPermissionsAsync();
  //       setHasPermission(status === 'granted');
  //     })();
  //   }, []);

  const handleBarCodeScanned = ({type, data}) => {
    ref.current?._setScanning(true);
    setModalVisible(true);
    // console.warn("Scan returned " + data);
    setUri({uri: data});
  };

  const ref = useRef();

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

  return (
    <View
      style={{
        flex: 1,
        flexDirection: 'column',
      }}>
      <Modal animationType="slide" transparent={false} visible={modalVisible}>
        <View style={{flex: 1}}>
          <WebView style={{flex: 1}} source={{uri: uri.uri}} />

          <TouchableHighlight
            style={{
              backgroundColor: 'black',
              padding: 15,
              alignItems: 'center',
            }}
            onPress={() => {
              //   ref.current?._setScanning(true);
              ref.current?._setScanning(false);
              setModalVisible(!modalVisible);
            }}
            underlayColor="slategray">
            <Text style={{color: 'white', fontSize: 15}}>Re Scan</Text>
          </TouchableHighlight>
        </View>
      </Modal>

      <QRCodeScanner
        // onBarCodeScanned={handleBarCodeScanned}
        onRead={handleBarCodeScanned}
        ref={ref}
        style={{
          flex: 1,
          justifyContent: 'center',
          alignItems: 'center',
        }}>
        <View style={{marginBottom: 100}}>
          <View style={{alignItems: 'center', marginBottom: 5}}>
            <Image
              style={{
                width: 100,
                height: 100,
                resizeMode: 'contain',
                marginBottom: 20,
              }}
              source={{uri: 'omitted'}}
            />
            <Text
              style={{
                color: 'white',
                fontSize: 20,
                fontWeight: 'bold',
                paddingBottom: 10,
              }}>
              QR Code Reader
            </Text>
          </View>
          <View
            style={{
              borderColor: 'white',
              borderTopWidth: 5,
              borderBottomWidth: 5,
              borderLeftWidth: 1,
              borderRightWidth: 1,
              paddingVertical: 80,
              paddingHorizontal: 100,
            }}
          />

          <View style={{alignItems: 'center', marginTop: 5}}>
            <Text style={{color: 'white', fontSize: 15}}>QR Scan...</Text>
          </View>
        </View>
      </QRCodeScanner>
    </View>
  );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM