rodgomesc / vision-camera-code-scanner

VisionCamera Frame Processor Plugin to read barcodes using MLKit Vision QrCode Scanning
MIT License
335 stars 221 forks source link

Android: Frame Processor threw an error: undefined is not a function #29

Open mancas opened 2 years ago

mancas commented 2 years ago

Hi! First of all thanks for the lib! I'd like to start moving from the react-native-camera to react-native-vision-camera so the one of my app features is to read a barcode coded in EAN13 so this library fits my needs.

However I'm facing a strange issue, the frame processor is throwing an error all the time Frame Processor threw an error: undefined is not a function. All the configuration (especially the one related to react-reanimated) is done properly. The app is running fine and it compiles without errors.

babel.config.js

module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: [
    [
      'module-resolver',
      {
        root: ['./'],
        extensions: ['.ios.js', '.android.js', '.js', '.ts', '.tsx', '.json'],
        alias: {
          res: './src/res',
        },
      },
    ],
    [
      'react-native-reanimated/plugin',
      {
        globals: ['__scanCodes'],
      },
    ],
  ],
}

Component

import React, { useEffect, useLayoutEffect, useMemo, useState } from 'react'
import { StatusBar } from 'react-native'
import styles from './GrantedPermissionsScreen.style'
import { Camera, useCameraDevices } from 'react-native-vision-camera'
import LoadingView from 'src/components/molecules/loadingView/LoadingView'
import Screen from 'src/components/atoms/screen/Screen'
import HeaderButton from 'src/components/molecules/headerButton/HeaderButton'
import { AvailableColors, colors } from 'res'
import IconFeather from 'react-native-vector-icons/Feather'
import Overlay from './components/overlay/Overlay'
import { CompositeNavigationProp } from '@react-navigation/core'
import { BarcodeFormat, useScanBarcodes } from 'vision-camera-code-scanner'
import { RegisterTubeRoutes, Routes } from 'src/navigators/routes'
import { RegisterTubeNavigationProp } from 'src/navigators/registerTube'
import { RootNavigationProp } from 'src/navigators'

// const ReanimatedCamera = Reanimated.createAnimatedComponent(Camera)

export interface GrantedPermissionsProps {
  navigation: CompositeNavigationProp<
    RegisterTubeNavigationProp<RegisterTubeRoutes.CameraGrantedPermissions>,
    RootNavigationProp<Routes.AddCustomer>
  >
}

const GrantedPermissionsScreen = ({ navigation }: GrantedPermissionsProps) => {
  const [hasPermission, setHasPermission] = useState(false)
  const devices = useCameraDevices()
  const device = useMemo(() => {
    return devices.back
  }, [devices])

  const [frameProcessor, barcodes] = useScanBarcodes([BarcodeFormat.QR_CODE])

  useLayoutEffect(() => {
    navigation.setOptions({
      headerTransparent: true,
      headerBackVisible: false,
      headerRight: () => {
        return (
          <HeaderButton
            variant={AvailableColors.white}
            onPress={navigation.goBack}>
            <IconFeather name="x" size={18} color={colors.white} />
          </HeaderButton>
        )
      },
    })
  }, [navigation])

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

  if (!device || !hasPermission) {
    return <LoadingView />
  }

  return (
    <Screen style={styles.container}>
      <StatusBar barStyle="light-content" />

      <Camera
        style={styles.camera}
        isActive
        device={device}
        frameProcessor={frameProcessor}
        frameProcessorFps={5}
      />

      <Overlay />
    </Screen>
  )
}

export default React.memo(GrantedPermissionsScreen)

Hope someone can help me out to discover what's happening

Thanks!

rodgomescrn commented 2 years ago

can you provide a repo with a react native setup containing this code that throw the same error?

mancas commented 2 years ago

Sure! I've removed the unnecessary stuff. Also I've tried using SDK v31 but with the same results.

https://github.com/mancas/rn-test-app

Kprashanth20 commented 2 years ago

I'm facing the same issue !! any solution for it?

ghost commented 2 years ago

I get the same error after reload JS on Android (From debug menu or CodePush restart) Seem like the global function is not injected to JS runtime after reload. global.setFrameProcessor and global. unsetFrameProcessor is undefined.

This is where the module bind function with the javascript runtime global object: https://github.com/mrousavy/react-native-vision-camera/blob/b10ca27daabeb18ec3652ffc64fbbe0fecb298f5/android/src/main/cpp/FrameProcessorRuntimeManager.cpp#L36 After reload JS bundle, the global object has been reset, that's why we got undefined is not a function. I just think about the solution is check if the function is undefined then we need to call void vision::FrameProcessorRuntimeManager::registerNatives to bind it again.

Bamorem commented 2 years ago

I have the same issue 'TypeError: undefined is not a function, js engine: hermes' the additional error are :

What I noticed is that id i comment out the line 'runOnJS(setQrCodes)(qrcode);' (default example) it works perfectly. if i uncomment the line when the camera is already on, it works as well. but if i let it uncommented and restart the app. i got those errors...

HartWoom commented 2 years ago

Same issue here but only on iOS, works fine on Android.

I've got some additional info comming from xcode debug console, saying this :

Main Thread Checker: UI API called on a background thread: -[UIApplication statusBarOrientation] PID: 1305, TID: 878779, Thread name: (none), Queue name: mrousavy/VisionCamera.main, QoS: 33 Backtrace: 4 TitrePrepayes 0x0000000100ff5698 $s12VisionCamera0B4ViewC17updateOrientationyyFyycfUyycfU + 1328 5 TitrePrepayes 0x0000000100ffa938 $sIeg_IeyB_TR + 20 6 libdispatch.dylib 0x000000010348b6f4 _dispatch_call_block_and_release + 24 7 libdispatch.dylib 0x000000010348cc78 _dispatch_client_callout + 16 8 libdispatch.dylib 0x0000000103494bf4 _dispatch_lane_serial_drain + 712 9 libdispatch.dylib 0x00000001034958b4 _dispatch_lane_invoke + 456 10 libdispatch.dylib 0x000000010349f77c _dispatch_workloop_worker_thread + 1148 11 libsystem_pthread.dylib 0x00000001a303d114 _pthread_wqthread + 304 12 libsystem_pthread.dylib 0x00000001a303fcd4 start_wqthread + 4 2022-01-10 11:24:07.790192+0100 TitrePrepayes[1305:878779] [reports] Main Thread Checker: UI API called on a background thread: -[UIApplication statusBarOrientation]

Followed by the error Frame Processor threw an error: Value is undefined, expected an Object

It seems to come from the react-native-vision-camera lib. When I comment out the frameProcessor props on Camera, I don't get any errors, but of course I can't scan any barcodes anymore.

Is anyone still on this issue ?

HartWoom commented 2 years ago

Some update, I was using react-native-vision-camera v2.11.2. After downgrading to v2.11.1 (because the minor apparently was about device orientation) I do not have the above error anymore.

Although I still have Frame Processor threw an error: Value is undefined, expected an Object ^^

I went through https://mrousavy.com/react-native-vision-camera/docs/guides/troubleshooting, the only thing I haven't done yet was setting my swift version to 5.2. It unfortunately didn't solved anything.

I don't think I'm able to check what's happening inside the native code, I've never done swift before. I might have to search for another library unfortunately...

DiegoQuiros94 commented 2 years ago

I'm having the same issue, I made it work by not using the useScanBarcodes hook and declaring the frameProcessor function:

import React, { memo, useEffect, useState } from 'react';
import 'react-native-reanimated'
import { View } from 'react-native';
import { Camera, useCameraDevices, useFrameProcessor } from 'react-native-vision-camera';
import { BarcodeFormat, scanBarcodes, Barcode } from 'vision-camera-code-scanner';
import { runOnJS } from 'react-native-reanimated';

import styles from './styles';

function QRScanner() {

  const [hasPermission, setHasPermission] = useState(false);
  const devices = useCameraDevices();
  const device = devices.back; 
  const [barcodes, setBarcodes] = useState<Barcode[]>([])

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

  useEffect(() => {
    (async () => {
      let status = await Camera.getCameraPermissionStatus();
      if (status === 'not-determined') {
        status = await Camera.requestCameraPermission();
      }
      setHasPermission(status === 'authorized');
    })();
  }, []);

  useEffect(() => {
    console.log(barcodes);
  }, [barcodes]);

  return (
    <View style={styles.container}>
      {device && hasPermission && <Camera
      style={styles.fill}
      device={device}
      isActive={true}
      frameProcessor={frameProcessor}
      frameProcessorFps={5}
    />}
    </View>
  );
}

export default memo(QRScanner);
anniewey commented 2 years ago

I'm getting the same error, until I realised I need to disable the debugger as stated in troubleshoot

If your Frame Processor is not running, make sure you check the native Android Studio/Logcat logs to find out why. Also make sure you are not using a remote JS debugger such as Google Chrome, since those don't work with JSI.

MihailShab commented 2 years ago

first of all it is recommended to clear the cache npm start -- --reset-cache

fthernan commented 2 years ago

Disabling the debug mode worked for me.

  1. Open the developer menu (pressing "d" on the metro console πŸ‘‡β€‹βŒ¨οΈ, or shaking πŸ‘‹ your phone/device)
  2. Click on "Settings" βš™οΈ
  3. Uncheck "JS Dev Mode" πŸ› (first option)
  4. Reload your app πŸ”ƒ (pressing "r" on metro console πŸ‘‡β€‹βŒ¨οΈ)

Hope it helps πŸ˜‰β€‹

JoseMariaZoe commented 2 years ago

Disabling the debug mode worked for me.

  1. Open the developer menu (pressing "d" on the metro console πŸ‘‡β€‹βŒ¨οΈ, or shaking πŸ‘‹ your phone/device)
  2. Click on "Settings" βš™οΈ
  3. Uncheck "JS Dev Mode" πŸ› (first option)
  4. Reload your app πŸ”ƒ (pressing "r" on metro console πŸ‘‡β€‹βŒ¨οΈ)

Hope it helps πŸ˜‰β€‹

I can confirm that disabling the Debugger in the developer menu in the iPhone works.

Peege151 commented 2 years ago

Hi -- I'm trying to disable the debugger but I don't have that option in the menu when I shake the device, see image.

I think because it's hermes.

Also - pressing D in metro doesn't open the menu... is there any other way to disable? IMG_5837