3

After pressing a button the following code is executed:

takePicture = async function() {
    if (this.camera) {
      const options = { quality: 0.5, base64: true }
      const data = await this.camera.takePictureAsync(options)
      CameraRoll.saveToCameraRoll(data.uri)
    }
  }

The debugger shows:

Possible Unhandled Promise Rejection
Error: Permission Denied ...

Apparently CameraRoll requires user's permission to do that, but I already included them in my AndroidManifest.xml file:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.gradualcamera">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
      android:name=".MainApplication"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:allowBackup="false"
      android:theme="@style/AppTheme">
      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
        android:windowSoftInputMode="adjustResize">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
      </activity>
      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
    </application>

</manifest>

The code of the whole component:

import React, {Component} from 'react';
import {StyleSheet, View} from 'react-native'
import { RNCamera } from 'react-native-camera'
import { CameraRoll } from 'react-native'
import ActionButton from 'react-native-action-button'
import Icon from 'react-native-vector-icons/Ionicons'

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  },

  button: {
    height: 200,

    justifyContent: 'flex-end',
    alignItems: 'center'
  },

  actionButtonIcon: {
    fontSize: 20,
    height: 22,
    color: 'white',
  },

});


export default class Cam extends Component {
  constructor() {
    super()
    this.takePicture = this.takePicture.bind(this)
  }

  takePicture = async function() {
    if (this.camera) {
      const options = { quality: 0.5, base64: true }
      const data = await this.camera.takePictureAsync(options)
      CameraRoll.saveToCameraRoll(data.uri)
    }
  }

  render() {
    return (
      <View style={styles.container}>

        <RNCamera
          ref={ref => {this.camera = ref}}
          style={{
            flex: 1,
            width: '100%',
            position: 'relative'
          }}
        >
        </RNCamera>

        <ActionButton size={80} useNativeFeedback={false} buttonColor="rgba(231,76,60,1)">
          <ActionButton.Item useNativeFeedback={false} buttonColor='#9b59b6' title="Settings" onPress={this.props.switchScreen}>
            <Icon name="md-create" style={styles.actionButtonIcon} />
          </ActionButton.Item>
          <ActionButton.Item useNativeFeedback={false} buttonColor='#1abc9c' title="Start" onPress={this.takePicture}>
            <Icon name="md-done-all" style={styles.actionButtonIcon} />
          </ActionButton.Item>

        </ActionButton>

      </View>
    )
  }
}

I already tried to delete the application and restart the Metro server.

I enabled the storage permission manually from the Settings and it works now. However, when I deleted the application and reinstalled it again the storage permissions aren't requested to the user. I have tried to request it with react-native-permissions but it doesn't work:


    componentDidMount() {
      _requestPermission = () => {
        Permissions.request('storage').then(response => {
          // Returns once the user has chosen to 'allow' or to 'not allow' access
          // Response is one of: 'authorized', 'denied', 'restricted', or 'undetermined'
          console.log(response)
        })
      }
    }

Somehow the react-native-permissions method started to work after I removed it out of the onComponentMount method and triggered it with a button.

dclipca
  • 1,739
  • 1
  • 16
  • 51

3 Answers3

4

Just add this line AndroidManifest.xml:

<application tag android:requestLegacyExternalStorage="true"
aboger
  • 2,214
  • 6
  • 33
  • 47
Krishna
  • 297
  • 2
  • 11
1

Take a look to this component and check if the permissions are enabled before to use camera.

https://github.com/yonahforst/react-native-permissions

SmoggeR_js
  • 2,950
  • 4
  • 22
  • 52
  • I checked the permission with this library and it says it's undetermined, which makes sense. However, when I request the permissions using this library the window doesn't show up. Also, I am very confused how React Native Camera seems to have a permission request out of the box. Can you clarify that? Thank you in advance. – dclipca Apr 26 '19 at 11:21
  • The permissions for the camera are enabled, however they're not enabled for the uses of CameraRoll. – dclipca Apr 26 '19 at 11:26
  • Maybe this is happening because you denied the permissions te first time. Go to settings and Go to applications and then search for that app and enter into her permissions. Check what are able there – SmoggeR_js Apr 26 '19 at 11:26
  • I enabled the storage permission manually from the Settings and it works now. However, when I deleted the application and reinstalled it again the storage permissions aren't requested to the user. I have tried to request it with react-native-permissions but it doesn't work (you can see the code in my updated post). – dclipca Apr 26 '19 at 11:34
  • You are requesting storage permissions instead of camera permision! – SmoggeR_js Apr 26 '19 at 11:39
  • 1
    The Camera permission is being requested and it works fine (as I can take pictures and send them in the cache). The problem is in the CameraRoll (which sends the picture to the DCIM folder). I just need to work around react-native-permissions and hopefully request a Storage permission so that CameraRoll will work. – dclipca Apr 26 '19 at 11:41
1

Try this way work both on ios and android

  const pickImage = async () => {

    const permissionResult = await ImagePicker.requestCameraPermissionsAsync();
    if (permissionResult.granted === false) {
      alert('Permission to access camera was denied.');
    }else{
      const result = await ImagePicker.launchCameraAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.Images,
      allowsEditing:true,
      base64:true,
      quality: 0.5,
    });

    if (!result.cancelled) {
      setImage(`data:image/jpeg;base64,${result?.base64}`);
    }

    }
  };