androidiosreact-nativeexpo

Expo Camera recordAsync promise not resolving


Im starting to develop a mobile application with expo/react native, but I'm having some problems handling the camera object:

I have a camera object that I start recording (recordAsync) at componentDidMount and I stop it (stopRecording) at componentWillUnmount. however the promise is never resolved (neither the then, catch no finally are called)

am I doing something wrong? here's the code:

import { Camera, Permissions } from 'expo';

import React from 'react';


export default class CameraReaction extends React.Component {
  constructor(props){
    super(props)
    this.takeFilm = this.takeFilm.bind(this)       
    this.isFilming=false
    this.cameraScreenContent = this.renderCamera()
  }

  componentDidMount(){
    if (this.props.shouldrecording && !this.isFilming ){
      this.takeFilm()
    }
  }
  componentWillUnmount(){
    this.camera.stopRecording()
  }

  saveMediaFile = async video => {
    console.log("=======saveMediaFile======="); 
  }

  renderCamera = () => {
    let self = this
    return (
      <View style={{ flex: 1 }}>
        <Camera
          ref={ref => {self.camera=ref}}
          style={styles.camera}
          type='front'
          whiteBalance='off'
          ratio='4:3'
          autoFocus='off'
          >
        </Camera>
      </View>
    );
  }

  takeFilm(){
    let self = this
    try{
      self.camera.recordAsync()
      .then(data => {
        self.saveMediaFile(data),
        self.isFilming=false
      })
      .catch(error => {console.log(error)})
      this.isFilming = true
    }
    catch(e){      
      this.isFilming = false      
    }            
  };

  render() {    
    return <View style={styles.container}>{this.cameraScreenContent}</View>;
  }

}

anyone has any clue of what I'm doing wrong?

thanks in advance


Solution

  • I finally realised that we can't start recording directly when a component is rendered. An by 'directly' I mean without any further action from the user. If I do it in two steps (p.e. waiting for the user to click somewhere), if works perfectly. But I don't see any reference to this behaviour / limitation in the documentation.

    The working code bellow:

    import React from 'react';
    import { StyleSheet, Text, View , TouchableOpacity} from 'react-native';
    import { Camera, Permissions} from 'expo';
    
    export default class App extends React.Component {
      constructor(props){
        super(props)    
        this.camera=undefined
        this.state = {permissionsGranted:false,bcolor:'red'}
        this.takeFilm = this.takeFilm.bind(this)
      }
    
      async componentWillMount() {    
        let cameraResponse = await Permissions.askAsync(Permissions.CAMERA)
        if (cameraResponse.status == 'granted'){
          let audioResponse = await Permissions.askAsync(Permissions.AUDIO_RECORDING);
          if (audioResponse.status == 'granted'){
            this.setState({ permissionsGranted: true });
          }
        }                  
      }
    
      takeFilm(){    
        let self = this;
        if (this.camera){
          this.camera.recordAsync().then(data => self.setState({bcolor:'green'}))
        }    
      }
    
      render() {    
        if (!this.state.permissionsGranted){
          return <View><Text>Camera permissions not granted</Text></View>
        } else {
          return (
            <View style={{flex: 1}}>
              <View style={{ flex: 1 }}>
                <Camera ref={ref => this.camera = ref} style={{flex: 0.3}} ></Camera>
              </View>
              <TouchableOpacity style={{backgroundColor:this.state.bcolor, flex:0.3}} onPress={() => {
    
                if(this.state.cameraIsRecording){
                  this.setState({cameraIsRecording:false})
                  this.camera.stopRecording();
                }
                else{
                  this.setState({cameraIsRecording:true})
                  this.takeFilm();
                }
              }} />
            </View>)
        }
      }
    }