mrousavy / react-native-vision-camera

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

❓ [iOS][V3] Request for Assistance: Removing 'vision-camera-code-scanner' and Configuring 'react-native-vision-camera' #1954

Closed ferencIOS closed 1 year ago

ferencIOS commented 1 year ago

Question

Hello,

I am currently working on a React Native project, and I need assistance with removing the 'vision-camera-code-scanner' package and properly configuring 'react-native-vision-camera' in my project.

What I tried

Steps Taken So Far

  1. I have removed the 'vision-camera-code-scanner' package from my project's dependencies.

Challenges

I am encountering challenges in understanding how to configure 'react-native-vision-camera' directly. Specifically, I need guidance on:

Request for Assistance

I kindly request assistance or guidance from the community in successfully removing 'vision-camera-code-scanner' and configuring 'react-native-vision-camera' in my React Native project. Any code examples, documentation links, or step-by-step instructions would be greatly appreciated.

index.js

import 'react-native-worklets-core/src'
import 'react-native-reanimated'

import { AppRegistry } from 'react-native'
import { name as appName } from './app.json'
import App from './App/Containers/App'

AppRegistry.registerComponent(appName, () => App)

babel.config.js

const presets = ['module:metro-react-native-babel-preset']
const plugins = ['react-native-worklets-core/plugin']

presets.push(
  ['babel-preset-expo']
)
plugins.push([
  'react-native-reanimated/plugin',
  {
    globals: ['__scanCodes'],
  },
])
module.exports = {
  presets,
  plugins
}

QrCodeScannerScreen.js

import React, { useState, useEffect } from 'react'
import { View, Alert } from 'react-native'
import {
  Camera,
  useCameraDevices,
  useFrameProcessor,
} from 'react-native-vision-camera'
import {
  // useScanBarcodes,
  scanBarcodes,
  BarcodeFormat,
} from 'vision-camera-code-scanner'
import { useDispatch, useSelector } from 'react-redux'
import { runOnJS } from 'react-native-reanimated'
import { getMetaDataFromUrl, validateQrCodeUrl } from '../Utils/UrlUtils'
import I18n from '../I18n/I18n'
import DeepLinkNotificationActions from '../Redux/DeepLinkNotificationRedux'
import UserActions, { UserSelectors } from '../Redux/UserRedux'
import styles from './Styles/QrCodeScannerScreenStyle'
import DebugConfig from '../Config/DebugConfig'

/**
 * Get an array of barcodes, and check validity of the first one
 * @param {Object[]} barcodes - Array of barcodes object, result of vision-camera-code-scanner scan
 * @returns {boolean} True if the first element in array is a valid identify link
 */
function checkBarcodesValidity(barcodes) {
  if (barcodes == null || barcodes.length < 1) {
    return false
  }
  const barcode = barcodes[0]
  const url = barcode?.content?.data?.url
  try {
    return validateQrCodeUrl(url)
  } catch (error) {
    console.error(error)
    return false
  }
}

/**
  Camera scan a qr code and store his value in "barcodes" state
*/
export default function QrCodeScannerScreen(props) {
  const [hasPermission, setHasPermission] = useState(false)
  const [barcodes, setBarcodes] = useState([])
  const [isUrlAlreadyOpen, setIsUrlAlreadyOpen] = useState(false)
  const [isAlertOpen, setIsAlertOpen] = useState(false)
  const barcode = barcodes != null && barcodes.length > 0 ? barcodes[0] : null
  const dispatch = useDispatch()
  const isLoggedIn = useSelector(UserSelectors.getIsLoggedIn)

  const devices = useCameraDevices()
  const device = devices.back

  const frameProcessor = useFrameProcessor(frame => {
    'worklet'
    const detectedBarcodes = scanBarcodes(frame, [BarcodeFormat.QR_CODE], {
      checkInverted: true,
    })
    runOnJS(setBarcodes)(detectedBarcodes)
  }, [])

  if (barcodes?.length > 0) {
    console.log({ barcodes })
  }
  const isValidCode = checkBarcodesValidity(barcodes)

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

  useEffect(() => {
    if (
      barcode != null &&
      barcode?.content?.data?.url != null &&
      !isUrlAlreadyOpen &&
      isValidCode
    ) {
      const url = barcode?.content?.data?.url
      if (!isLoggedIn) {
        const { username } = getMetaDataFromUrl(url)
        dispatch(UserActions.userSetCredentials(username, null))
      }
      dispatch(DeepLinkNotificationActions.deepLinkNotificationReceive(url))
      setIsUrlAlreadyOpen(true)
      props.navigation.goBack()
    }
  }, [
    barcode,
    isUrlAlreadyOpen,
    dispatch,
    isValidCode,
    props.navigation,
    isLoggedIn,
  ])

  if (!isValidCode && barcode && !isAlertOpen) {
    setIsAlertOpen(true)
    Alert.alert(
      I18n.t('alert.errorTitle'),
      I18n.t('qrCode.invalidUrl'),
      [
        {
          text: I18n.t('alert.ok'),
          onPress: () => {
            props.navigation.goBack()
          },
        },
      ],
      { cancelable: false }
    )
  }

  return (
    device != null &&
    hasPermission && (
      <View style={styles.root}>
        <Camera
          style={styles.camera}
          device={device}
          isActive={true}
          frameProcessor={frameProcessor}
          frameProcessorFps={5}>
          {/* {barcode != null && (
            <View style={styles.recognizedView}>
              {isValidCode ? (
                <Icon
                  name="md-checkmark-circle"
                  size={60}
                  color={Colors.stepCorrect}
                />
              ) : (
                <Icon
                  name="md-close-circle"
                  size={60}
                  color={Colors.stepWrong}
                />
              )}
            </View>
          )} */}
        </Camera>
      </View>
    )
  )
}

QrCodeScannerScreen.navigationOptions = () => {
  return {
    headerTitle: I18n.t('qrCode.title'),
  }
}

Something else: Cocoapods?

VisionCamera Version

3.3.1

Additional information

ferencIOS commented 1 year ago

I tried to personally address the issue by migrating to the latest version of the plugin, and here's the code I got:

import React, { useState, useEffect } from 'react';
import { View, Alert } from 'react-native';
import { Camera, useCodeScanner } from 'react-native-vision-camera';
import { useDispatch, useSelector } from 'react-redux';
import { getMetaDataFromUrl, validateQrCodeUrl } from '../Utils/UrlUtils';
import I18n from '../I18n/I18n';
import DeepLinkNotificationActions from '../Redux/DeepLinkNotificationRedux';
import UserActions, { UserSelectors } from '../Redux/UserRedux';
import styles from './Styles/QrCodeScannerScreenStyle';

export default function QrCodeScannerScreen(props) {
  const [hasPermission, setHasPermission] = useState(false);
  const [barcodes, setBarcodes] = useState([]);
  const [isUrlAlreadyOpen, setIsUrlAlreadyOpen] = useState(false);
  const [isAlertOpen, setIsAlertOpen] = useState(false);
  const barcode = barcodes && barcodes.length > 0 ? barcodes[0] : null;
  const dispatch = useDispatch();
  const isLoggedIn = useSelector(UserSelectors.getIsLoggedIn);

  const codeScanner = useCodeScanner({
    codeTypes: ['qr', 'ean-13'], 
    onCodeScanned: (codes) => {
      console.log(`Scanned ${codes.length} codes!`);
      setBarcodes(codes);
    }
  });

  useEffect(() => {
    (async () => {
      const status = await Camera.requestCameraPermission();
      console.log(`Camera permission status ${status}`);
      setHasPermission(status === 'authorized');
    })();
  }, []);

  useEffect(() => {
    if (barcode && barcode?.content?.data?.url && !isUrlAlreadyOpen && validateQrCodeUrl(barcode?.content?.data?.url)) {
      const url = barcode?.content?.data?.url;
      if (!isLoggedIn) {
        const { username } = getMetaDataFromUrl(url);
        dispatch(UserActions.userSetCredentials(username, null));
      }
      dispatch(DeepLinkNotificationActions.deepLinkNotificationReceive(url));
      setIsUrlAlreadyOpen(true);
      props.navigation.goBack();
    }
  }, [barcode, isUrlAlreadyOpen, dispatch, props.navigation, isLoggedIn]);

  if (barcode && !validateQrCodeUrl(barcode?.content?.data?.url) && !isAlertOpen) {
    setIsAlertOpen(true);
    Alert.alert(
      I18n.t('alert.errorTitle'),
      I18n.t('qrCode.invalidUrl'),
      [
        {
          text: I18n.t('alert.ok'),
          onPress: () => {
            props.navigation.goBack();
          },
        },
      ],
      { cancelable: false }
    );
  }

  console.log(`codeScanner ${codeScanner.codeTypes}`);

 // Render the camera view
  return  (
  codeScanner != null 
  && hasPermission && 
  <Camera style={styles.camera} isActive={true} codeScanner={codeScanner} />
  )
  // return (
  //   hasPermission && (
  //     <View style={styles.root}>
  //       <Camera
  //         style={styles.camera}
  //         isActive={true}
  //         codeScanner={codeScanner}
  //       />
  //     </View>
  //   )
  // )
}

QrCodeScannerScreen.navigationOptions = () => {
  return {
    headerTitle: I18n.t('qrCode.title'),
  };
};

However, the camera doesn't activate. I just get a blank page! Where am I going wrong?

Screenshot 2023-10-09 at 17 09 57

From the logs:

LOG  codeScanner qr,ean-13
LOG  Camera permission status granted

There don't appear to be any evident errors. Can anyone provide some insights?

Skizu commented 1 year ago

vision-camera-code-scanner does not support react-native-vision-camera v3.

react-native-vision-camera v3 does have a built in QR scanner, see the code scanning guide. Note that currently there are large performance issues with this on Android.

ferencIOS commented 1 year ago

Thanks @Skizu for your help. I followed the guide but the result is a blank screen so I am doing something wrongly

ferencIOS commented 1 year ago

Hi @mrousavy ,

I'm not a React/JS developer, but I've been trying to update the dependency to get React Native Vision Camera to work on iOS 17 with Xcode 15, based on the code provided here: https://github.com/mrousavy/react-native-vision-camera/issues/1954#issuecomment-1753198632.

However, I'm facing difficulties as the camera doesn't seem to activate. I'm wondering if there might be something I'm missing or doing incorrectly in the code or configuration.

If anyone has experience with this specific issue or any insights into what could be causing the camera not to activate on iOS 17 with Xcode 15, I would greatly appreciate your help and guidance.

Thank you in advance!

zzz08900 commented 1 year ago

Thanks @Skizu for your help. I followed the guide but the result is a blank screen so I am doing something wrongly

The code sample was too long so I didn't really read that but camera view usually requires a height attribute passed to its styles to work properly. You can just set height to 100% for testing purpose.

Also note that camera device selection works different from v2 to v3 so you might need to accommodate with that.

For details, go read the docs for v3 :)

mrousavy commented 1 year ago

exactly what @zzz08900 said ☝️ 😄