I have a project which uses the React Native Camera library and also CameraRoll from vanilla React Native. When I open the application the app requests Camera permissions, but I don't know why. Is this only because I specified this in my AndroidManifest.xml?

<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.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>


Why when using React Native Camera I don't have to request permissions but when I'm using CameraRoll the permissions aren't granted by default and I have to use the React Native Permissions library.

I am asking this because I want to request those permissions all at once when the user opens the application, and it's hard to implement this as I don't know where the permissions are requested. Right now the user receives requests for Camera 'by default' but not for Storage. Why is that?

import React, {Component} from 'react';
import {StyleSheet, View} from 'react-native'
import { RNCamera } from 'react-native-camera'
import { CameraRoll } from 'react-native'
import Permissions from 'react-native-permissions'
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>
    )
  }
}

1 Answers

1
Farhan On Best Solutions

It is because you are calling react native camera in render method :

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

To solve this, i used ternary operator and state :

import React, { Component } from 'react';
import { StyleSheet, View } from 'react-native';
import { RNCamera } from 'react-native-camera';
import { CameraRoll } from 'react-native';
import Permissions from 'react-native-permissions';
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(props) {
    super(props);
    this.state = {
      takePicture: false
    };
  }

  takePicture = async () => {
    console.log('function was called');
    await this.setState({ takePicture: true });
    // 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}>
        {this.state.takePicture ? (
          <RNCamera
            ref={ref => {
              this.camera = ref;
            }}
            style={{
              flex: 1,
              width: '100%',
              position: 'relative'
            }}
          />
        ) : null}

        <ActionButton size={80} useNativeFeedback={false} buttonColor="rgba(231,76,60,1)">
          <ActionButton.Item useNativeFeedback={false} buttonColor="#9b59b6" title="Settings">
            <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>
    );
  }
}

Also for storage, you don't need to ask for permissions, you just need to write storage permissions in Android xml file. React native camera and Camera roll asks for permission differently is because they have made the library like that only. If you want to asks all permissions simultaneously in the beginning then you can use react native permissions and get all the permissions you want in the beginning(maybe in splashscreen component if you have one). Then when you will use react native camera later it will not ask for permissions again.