mrousavy / react-native-vision-camera

๐Ÿ“ธ A powerful, high-performance React Native Camera library.
https://react-native-vision-camera.com
MIT License
6.72k stars 1k forks source link

๐Ÿ› `takePhoto()` doesn't resolve on Android #321

Closed Alih789 closed 2 years ago

Alih789 commented 2 years ago

Question

This is the error I get upon attempting to use takePhoto() on android. This of course is followed by the failure of my promise. I've tried googling the error but I'm not at all finding information a view manager issue (?).

system/view-not-found: [system/view-not-found] The given view (ID 5079) was not found in the view manager.

Below is the code that is producing this


import { useCameraDevices, Camera,} from 'react-native-vision-camera' ;

function CameraElement (props) {
//Ref creation
  const cameraRef = React.useRef();
  const devices = useCameraDevices()
  const device = devices.back

  ....

//Handles Taking photo
const handleCapture = async () => {
  const data = await cameraRef.current.takePhoto({
    enableAutoStabilization: true,
    skipMetadata: true,
    photoCodec: 'jpeg',
    quality: 100,
  });
  console.log(data);
}

  return (

      <View style = {{alignItems:'center',}}>

             ....

//THE RELEVANT PART
        <Modal
        animationType="none"
        transparent = {true}
        visible = {isVisCam}>
          <Camera
            ref = {cameraRef}
            style={{width:styles.windowWidth,height:styles.windowHeight*.9}}
            device={device}
            isActive={true}
            photo = {true}
          />
          <View style = {{height:styles.windowHeight*.1, backgroundColor:"white"}}>
            <TouchableOpacity onPress = {handleCapture}><Image source = {require(....)} style = {[styles.iconDim, {alignSelf:"flex-start", justifyContent:"center", margin: 10}]}/></TouchableOpacity>
          </View>

        </Modal>

//END OF CAMERA Code

      </View>

  );
};

export default CameraElement;

What I tried

No response

VisionCamera Version

2.4.1

Additional information

mrousavy commented 2 years ago

Does it work if it's not inside the Modal? I believe the Modal has it's own view hierarchy...

Alih789 commented 2 years ago

Yeah your suspicion was correct, Modal was causing the problems. Instead now however, After I press to take a picture, I enter the handleCapture function, but don't move past the await statement. One thing to note, the functiontakePhoto() is labeled as 'any' rather than defined by your library in VSC -- should I be importing something. I tried looking for a suitable import statement but found nothing.

Thanks!

mrousavy commented 2 years ago

Maybe an exception is thrown. Try wrapping it with try/catch.

As for the types, you need to pass it to useRef:

const cameraRef = useRef<Camera>(null);
Alih789 commented 2 years ago

Yeah I'll look into that right now. In regards to const cameraRef = useRef<Camera>(null); I'm not using that because I get the error Function Components cannot have string refs. We recommend using useRef() instead. -- Since I'm not really experienced creating Refs I was hoping that wouldn't be a problem, but I'm not really sure what's going on there. Looking here is where I got my fix from https://github.com/jeremybarbet/react-native-modalize/issues/285

////

I've received nothing on the remote debugger. Here is what the new handleCapture looks like

const handleCapture = async () => {
  console.log("IM IN")

  try {
    const img = await cameraRef.current.takePhoto({
      enableAutoStabilization: true,
      skipMetadata: true,
      photoCodec: 'jpeg',
      quality: 100,
    });
    console.log(img);
  } catch (error) {
    console.log("hey")
    console.log({error});
  }

}
mrousavy commented 2 years ago

Why did you create a question and not a bug report for this?

Which phones did you test this on? Does it work on iOS?

Alih789 commented 2 years ago

Apologies, I didn't realize that this was going to be a bug -- thought that maybe I was just missing something. I can't test on iOS but but I've tried this on the following android devices:

Pixel 3 API 30 Pixel 2 API 30

mrousavy commented 2 years ago

Can you somehow manage to ask someone to test it on iOS for you? If it works on iOS and doesn't work on Android then it's definitely an issue on the Android codebase

Alih789 commented 2 years ago

Alright I ended up going off what you said, and just trying a bunch of different emulators and then I went to using a physical phone and that resolved everything. Thank you!

sparebytes commented 2 years ago

I'm having this same issue on Android. iOS works fine.

Devices: Emulator and Pixel 4 SDK Version 30

coolvasanth commented 2 years ago

Hi @mrousavy , I have a requirement to render the camera inside a modal. Is there any way we can overcome this defect and render it inside a modal ?

coolvasanth commented 2 years ago

@mrousavy Following up again, any chance of making vision-camera to work on modals ?

iRootPro commented 2 years ago

I also need the camera to work in a modal window, until I also found a solution, is there any chance? @mrousavy

mrousavy commented 2 years ago

yes with fabric migration

mrousavy commented 2 years ago

I'll work on that as soon as I have some free time ๐Ÿ™

mrousavy commented 2 years ago

again, I just use a normal screen from react-navigation and display it as a modal, that works perfect for me

iRootPro commented 2 years ago

can i have an example? how to use it? i have big app, and many point when used modal for camera, but all call ModalCamera component with code:

`<Modal onRequestClose={onClose}

<Camera onCancel={onClose} onPermissionDenied={onClose} onPicture={onPicture} />

`

how can change this code without modal?

mrousavy commented 2 years ago

move it to it's own screen, don't use <Modal>. You can instead pass presentation="modal" to the screen then

iRootPro commented 2 years ago

move it to it's own screen, don't use <Modal>. You can instead pass presentation="modal" to the screen then

and use navigation? too many places to rewrite it, but if there is no other way...

iRootPro commented 2 years ago

move it to it's own screen, don't use <Modal>. You can instead pass presentation="modal" to the screen then

unfortunately we using navigation 4.4.4 version, 4 version does not support modal presentation (

mrousavy commented 2 years ago

but if there is no other way

there will be when I migrate over to Fabric!

iRootPro commented 2 years ago

Thanks, I really hope it won't be too long :)

neeleshatale commented 2 years ago

I am also facing same issue, unfortunately have requirement of rendering camera in modal. Is there any workaround for now? Thanks

neeleshatale commented 2 years ago

Alright I ended up going off what you said, and just trying a bunch of different emulators and then I went to using a physical phone and that resolved everything. Thank you!

Hello @Alih789 I am also facing same issue, can you share what you did for this? that will be helpful. Thank you

melero2000 commented 2 years ago

Hello, I'm having the same issue. How did you solve it? Thanks you

felansu commented 2 years ago

Same here...

adrianwijaya94 commented 2 years ago

I Have same issue, I solve this issue with add a state for wait camera initialized:

for example: ... const cameraRef = useRef(null); const [isCameraInitialized, setIsCameraInitialized] = useState(false); const devices = useCameraDevices(); const device = devices.back;

const onCameraInitialized = useCallback(() => { console.log('Camera initialized!'); setIsCameraInitialized(true); }, []);

const handleCapture = useCallback(async () => { try { if(cameraRef&&cameraRef.current&&isCameraInitialized){ const img = await cameraRef.current.takePhoto({ enableAutoStabilization: true, skipMetadata: true, photoCodec: 'jpeg', quality: 100, }); console.log(img); } } catch (error) { console.log("hey") console.log({error}); } },[cameraRef, isCameraInitialized])

return( ... <Camera ref={cameraRef} style={{flex: 1}} device={device} isActive={true} onInitialized={onCameraInitialized} // <-- wait camera initialized onError={onError} enableZoomGesture={false} photo={true} orientation="portrait" /> // component to call handleCapture ... ) ...

Buwaneka-Sumanasekara commented 2 years ago

Any update on this issue? In my case, I have to use Modal as a container. (Its working properly on ios and not working on android)

hb-webdev commented 1 year ago

I Have same issue, I solve this issue with add a state for wait camera initialized:

for example: ... const cameraRef = useRef(null); const [isCameraInitialized, setIsCameraInitialized] = useState(false); const devices = useCameraDevices(); const device = devices.back;

const onCameraInitialized = useCallback(() => { console.log('Camera initialized!'); setIsCameraInitialized(true); }, []);

const handleCapture = useCallback(async () => { try { if(cameraRef&&cameraRef.current&&isCameraInitialized){ const img = await cameraRef.current.takePhoto({ enableAutoStabilization: true, skipMetadata: true, photoCodec: 'jpeg', quality: 100, }); console.log(img); } } catch (error) { console.log("hey") console.log({error}); } },[cameraRef, isCameraInitialized])

return( ... <Camera ref={cameraRef} style={{flex: 1}} device={device} isActive={true} onInitialized={onCameraInitialized} // <-- wait camera initialized onError={onError} enableZoomGesture={false} photo={true} orientation="portrait" /> // component to call handleCapture ... ) ...

I could kiss you right now. I already had this function:

const onCameraInitialized = useCallback(() => {
  console.log('Camera initialized!');
  setIsCameraInitialized(true);
}, []);

But setIsCameraInitialized(true) was (only sometimes!!) getting called too early. Therefore, even though the isInitialized prop was triggered, the camera sometimes wasn't truly initialized (apparently), so this randomly (annoyoingly inconsistently) threw the session/camera-not-ready: [session/camera-not-ready] The Camera is not ready yet! Wait for the onInitialized() callback! ๐Ÿ™„:

useUpdateEffect(() => {
  const takeBackgroundPic = async() => {
    picData = Platform.OS === 'android' ? await camera.current?.takeSnapshot() : await camera.current?.takePhoto();
   }
  if(isCameraInitialized==true){
    takeBackgroundPic();
  }
}, [isCameraInitialized])

So in my view, the isInitialized prop is inconsistent.

But thanks to your additional if statements (if(cameraRef && cameraRef.current && isCameraInitialized){}), it works now!!!!! Bless you. I don't know if I ever would have solved this without you.

EDIT: Scratch that...the session/camera-not-ready: [session/camera-not-ready] The Camera is not ready yet! Wait for the onInitialized() callback! error started appearing again. I had to add:

try {
  ...
}
} catch (error) {
  ...
  setIsCameraInitialized(false); <-- Add this
  setIsCameraInitialized(true); <-- Add this
}

...to trigger the useUpdateEffect again in case the camera initialized error appeared.

NikonBugaichuk commented 1 year ago

Alright I ended up going off what you said, and just trying a bunch of different emulators and then I went to using a physical phone and that resolved everything. Thank you!

I don't know if it helps you. But for my emulator, the takePhoto function doesn't work with the back camera. And I just found out why. It happened because the Android emulator by default uses the back camera as a VirtualScene option. I changed it to emulated. And everything works well!

Screenshot 2023-03-03 at 10 18 15
shkibrahim commented 5 months ago

i am getting this error Error taking photo: [capture/photo-not-enabled: [capture/photo-not-enabled] Photo capture is disabled! Pass photo={true} to enable photo capture.] although <Camera style={{ height: 300, marginTop: 150 }} photo={true} device={device} onInitialized={onCameraInitialized} // <-- wait camera initialized

isActive={true}
ref={cameraRef}

/> i have set it to true please some one share something with me to make it correct @mrousavy

alejodiloreto commented 4 months ago

same issue in 2024... ERROR Error taking photo: [capture/photo-not-enabled: [capture/photo-not-enabled] Photo capture is disabled! Pass photo={true} to enable photo capture.]

Only on Android, i have the CameraView in a Modal, thats the problem? Any update on this issue?

mrousavy commented 4 months ago

Maybe try moving it out of a modal? Are you on the latest version (3.7.0)?

alejodiloreto commented 4 months ago

I upgrade to version 3.7.0 and the issue has gone, the camera is showing, but now when isAcitve is in false the frame doesnt stop.

mrousavy commented 4 months ago

@alejodiloreto fixed on main!