Paramclasses Academy - Blog

Tutorials Details

←
Post 35 of 39
→

React Native Permissions Explained: Camera, Location and Notifications ?

React Native Permissions Explained: Camera, Location and Notifications ?

November 5, 2026

1. Introduction

Modern mobile applications use different device features such as cameras, GPS, photo galleries, microphones, and notifications.

However, applications cannot freely access sensitive device features. They must request permission from users before accessing protected resources.

For example:

  • A camera application needs camera permission.

  • A navigation application needs location permission.

  • A messaging application needs notification permission.

React Native developers must understand how to request, check, and handle these permissions correctly on Android and iOS.

In this tutorial, we will create a practical Permission Manager App using Expo.

What You Will Learn

  • What are mobile app permissions?

  • Why permissions are important

  • Android and iOS permission systems

  • Types of runtime permissions

  • Camera permission

  • Location permission

  • Notification permission

  • Requesting permissions using Expo

  • Checking permission status

  • Handling denied permissions

  • Opening device settings

  • Testing permissions on Android and iOS

  • Permission management best practices

2. What Are App Permissions?

App permissions are authorizations that allow an application to access protected device features or personal information.

For example, when an application wants to use the camera, the operating system asks the user whether access should be allowed.

The user can:

  • Allow access.

  • Deny access.

  • Allow access temporarily, where supported.

  • Change permissions later through device settings.

Permissions help protect user privacy and device security.

3. Why Are Permissions Important?

Permissions are important for several reasons:

  1. Protect personal information.

  2. Prevent unauthorized device access.

  3. Give users control over application features.

  4. Improve application security.

  5. Follow Android and iOS platform requirements.

  6. Provide transparent access to sensitive resources.

Always request only the permissions that your application actually needs.

4. Types of Mobile App Permissions

4.1 Camera Permission

Camera permission allows an application to access the device camera.

Examples:

  • Taking photographs.

  • Scanning QR codes.

  • Recording videos.

  • Capturing documents.

4.2 Location Permission

Location permission allows an application to access the device's geographic location.

Examples:

  • Navigation applications.

  • Delivery applications.

  • Weather applications.

  • Nearby service applications.

Location access may be approximate or precise, depending on the operating system and user selection.

4.3 Notification Permission

Notification permission allows an application to display notifications according to the user's device settings.

Examples:

  • New message alerts.

  • Order updates.

  • Reminder notifications.

  • Important application announcements.

4.4 Other Common Permissions

Other permissions may include:

  • Microphone.

  • Photo library.

  • Contacts.

  • Bluetooth.

  • Calendar.

The required permissions depend on the features used by the application.

5. Understanding Android and iOS Permissions

Android and iOS both provide runtime permission systems, but their interfaces and behavior are different.

Android

Android applications declare required permissions in the application manifest.

Some sensitive permissions must also be requested at runtime.

For example:

  • CAMERA

  • ACCESS_FINE_LOCATION

  • ACCESS_COARSE_LOCATION

  • POST_NOTIFICATIONS

Android 13 and later require notification runtime permission for applications targeting the applicable Android version.

iOS

iOS applications must provide a clear explanation for accessing protected resources.

Examples of permission usage descriptions include:

  • NSCameraUsageDescription

  • NSLocationWhenInUseUsageDescription

  • NSLocationAlwaysAndWhenInUseUsageDescription

The operating system displays its own permission interface.

Important: Permission behavior depends on the operating system version, application configuration, and previous user decisions.

6. Create a React Native Permission Project

First, create a new Expo project.

Open your terminal and execute:

npx create-expo-app@latest PermissionManagerApp --template blank

Open the project:

cd PermissionManagerApp

Start the project:

npx expo start

7. Install Required Packages

We will use three Expo libraries.

Install the camera package:

npx expo install expo-camera

Install the location package:

npx expo install expo-location

Install the notifications package:

npx expo install expo-notifications

These packages provide APIs for requesting and managing camera, location, and notification permissions.

8. Configure Application Permissions

Open your app.json file.

Add the following configuration to your Expo configuration.

{
  "expo": {
    "name": "PermissionManagerApp",
    "slug": "permission-manager-app",
    "plugins": [
      [
        "expo-camera",
        {
          "cameraPermission": "Allow Permission Manager to access your camera.",
          "recordAudioAndroid": false
        }
      ],
      [
        "expo-location",
        {
          "locationWhenInUsePermission": "Allow Permission Manager to access your location while using the app."
        }
      ],
      "expo-notifications"
    ]
  }
}

If your app.json already contains other configuration, merge these settings instead of replacing the complete file.

The configuration provides permission descriptions and native configuration for the application.

For production applications, use permission messages that explain the actual purpose of each feature.

9. Understanding Permission Status

Permissions generally have different states.

Granted

The user has allowed the application to access the requested resource.

Denied

The user has rejected the permission request.

Undetermined

The user has not made a permission decision yet.

Cannot Ask Again

The operating system may no longer display the permission dialog. The user may need to enable the permission manually through device settings.

Always check the current permission state before using a protected feature.

10. Request Camera Permission

First, import the camera permission hook.

import { useCameraPermissions } from 'expo-camera';

Inside your component:

const [
  cameraPermission,
  requestCameraPermission
] = useCameraPermissions();

Check whether permission is granted:

if (cameraPermission?.granted) {
  console.log('Camera permission granted');
}

Request camera permission:

const result = await requestCameraPermission();

if (result.granted) {
  console.log('Camera access allowed');
} else {
  console.log('Camera access denied');
}

Explanation

useCameraPermissions() provides the current permission information and a function to request permission.

The application should only access the camera after permission is granted.

11. Request Location Permission

Import the location package:

import * as Location from 'expo-location';

Create a permission request function:

const requestLocationPermission = async () => {

  const result =
    await Location.requestForegroundPermissionsAsync();

  if (result.granted) {

    console.log('Location permission granted');

    const location =
      await Location.getCurrentPositionAsync({});

    console.log(location.coords.latitude);
    console.log(location.coords.longitude);

  } else {

    console.log('Location permission denied');

  }

};

Explanation

requestForegroundPermissionsAsync() requests location access while the application is in use.

After permission is granted, getCurrentPositionAsync() retrieves the current device location.

Location retrieval may take several seconds depending on GPS availability and accuracy settings.

Foreground and Background Location

Foreground location means the application accesses location while it is in use.

Background location means the application accesses location while it is running in the background.

Background location requires additional platform configuration and permission requests. Request it only when an essential application feature requires it.

12. Request Notification Permission

Import Expo Notifications:

import * as Notifications from 'expo-notifications';

Check current notification permission:

const currentPermission =
  await Notifications.getPermissionsAsync();

console.log(currentPermission.status);

Request notification permission:

const requestNotificationPermission = async () => {

  const result =
    await Notifications.requestPermissionsAsync();

  if (result.granted) {

    console.log('Notification permission granted');

  } else {

    console.log('Notification permission denied');

  }

};

Explanation

getPermissionsAsync() checks the current notification permission status.

requestPermissionsAsync() requests permission from the operating system when required.

Important: Permission to display notifications does not automatically configure remote push notifications. Push notifications also require the appropriate platform credentials, registration, and delivery setup.

13. Create the Permission Manager App

Now we will build a practical application with three permission sections.

The application will include:

  • Camera permission button.

  • Location permission button.

  • Notification permission button.

  • Permission status indicators.

  • Current location coordinates.

  • Error handling.

  • Open Settings option when permission cannot be requested again.

Step 1: Open App.js

Open your project's App.js file.

Remove the existing code and add the following complete application code.

Complete App.js Code

import React, { useState, useEffect } from 'react';

import {
  View,
  Text,
  TouchableOpacity,
  StyleSheet,
  ScrollView,
  Alert,
  Linking,
  ActivityIndicator,
} from 'react-native';

import { useCameraPermissions } from 'expo-camera';

import * as Location from 'expo-location';

import * as Notifications from 'expo-notifications';


export default function App() {

  const [
    cameraPermission,
    requestCameraPermission
  ] = useCameraPermissions();

  const [locationStatus, setLocationStatus] =
    useState('Loading');

  const [notificationStatus, setNotificationStatus] =
    useState('Loading');

  const [coordinates, setCoordinates] =
    useState(null);

  const [loading, setLoading] = useState(false);


  // Load Existing Permission Status

  useEffect(() => {

    loadPermissionStatus();

  }, []);


  const loadPermissionStatus = async () => {

    try {

      const location =
        await Location.getForegroundPermissionsAsync();

      const notification =
        await Notifications.getPermissionsAsync();

      setLocationStatus(location.status);

      setNotificationStatus(notification.status);

    } catch (error) {

      Alert.alert(
        'Error',
        'Unable to load permission status.'
      );

    }

  };


  // Camera Permission

  const handleCameraPermission = async () => {

    try {

      if (cameraPermission?.granted) {

        Alert.alert(
          'Camera',
          'Camera permission is already granted.'
        );

        return;

      }

      if (cameraPermission && !cameraPermission.canAskAgain) {

        Alert.alert(
          'Permission Blocked',
          'Enable camera permission from device settings.',
          [
            { text: 'Cancel', style: 'cancel' },
            {
              text: 'Open Settings',
              onPress: () => Linking.openSettings(),
            },
          ]
        );

        return;

      }

      const result = await requestCameraPermission();

      if (result.granted) {

        Alert.alert(
          'Success',
          'Camera permission granted.'
        );

      } else {

        Alert.alert(
          'Denied',
          'Camera permission was not granted.'
        );

      }

    } catch (error) {

      Alert.alert(
        'Error',
        'Unable to request camera permission.'
      );

    }

  };


  // Location Permission

  const handleLocationPermission = async () => {

    try {

      setLoading(true);

      const result =
        await Location.requestForegroundPermissionsAsync();

      setLocationStatus(result.status);

      if (!result.granted) {

        if (!result.canAskAgain) {

          Alert.alert(
            'Permission Blocked',
            'Enable location permission from device settings.',
            [
              { text: 'Cancel', style: 'cancel' },
              {
                text: 'Open Settings',
                onPress: () => Linking.openSettings(),
              },
            ]
          );

        } else {

          Alert.alert(
            'Denied',
            'Location permission was not granted.'
          );

        }

        return;

      }

      const currentLocation =
        await Location.getCurrentPositionAsync({
          accuracy: Location.Accuracy.Balanced,
        });

      setCoordinates({
        latitude: currentLocation.coords.latitude,
        longitude: currentLocation.coords.longitude,
      });

      Alert.alert(
        'Success',
        'Location permission granted.'
      );

    } catch (error) {

      Alert.alert(
        'Error',
        'Unable to retrieve device location.'
      );

    } finally {

      setLoading(false);

    }

  };


  // Notification Permission

  const handleNotificationPermission = async () => {

    try {

      const current =
        await Notifications.getPermissionsAsync();

      if (current.granted) {

        setNotificationStatus(current.status);

        Alert.alert(
          'Notifications',
          'Notification permission is already granted.'
        );

        return;

      }

      if (!current.canAskAgain) {

        Alert.alert(
          'Permission Blocked',
          'Enable notifications from device settings.',
          [
            { text: 'Cancel', style: 'cancel' },
            {
              text: 'Open Settings',
              onPress: () => Linking.openSettings(),
            },
          ]
        );

        return;

      }

      const result =
        await Notifications.requestPermissionsAsync();

      setNotificationStatus(result.status);

      if (result.granted) {

        Alert.alert(
          'Success',
          'Notification permission granted.'
        );

      } else {

        Alert.alert(
          'Denied',
          'Notification permission was not granted.'
        );

      }

    } catch (error) {

      Alert.alert(
        'Error',
        'Unable to request notification permission.'
      );

    }

  };


  // Permission Card Component

  const PermissionCard = ({
    title,
    description,
    status,
    onPress,
  }) => {

    return (

      <View style={styles.card}>

        <Text style={styles.cardTitle}>
          {title}
        </Text>

        <Text style={styles.description}>
          {description}
        </Text>

        <Text style={styles.status}>
          Status: {status || 'Loading'}
        </Text>

        <TouchableOpacity
          style={styles.button}
          onPress={onPress}
        >

          <Text style={styles.buttonText}>
            Request Access
          </Text>

        </TouchableOpacity>

      </View>

    );

  };


  return (

    <ScrollView
      style={styles.container}
      contentContainerStyle={styles.content}
    >

      <Text style={styles.heading}>
        Permission Manager
      </Text>

      <Text style={styles.subtitle}>
        Manage Device Permissions
      </Text>


      <PermissionCard
        title="Camera Permission"
        description="Allow the application to access your camera."
        status={
          cameraPermission
            ? cameraPermission.status
            : 'Loading'
        }
        onPress={handleCameraPermission}
      />


      <PermissionCard
        title="Location Permission"
        description="Allow the application to access your location while using it."
        status={locationStatus}
        onPress={handleLocationPermission}
      />


      <PermissionCard
        title="Notification Permission"
        description="Allow the application to send notifications."
        status={notificationStatus}
        onPress={handleNotificationPermission}
      />


      {loading && (

        <ActivityIndicator
          size="large"
          color="#2563EB"
        />

      )}


      {coordinates && (

        <View style={styles.locationBox}>

          <Text style={styles.locationTitle}>
            Current Location
          </Text>

          <Text style={styles.coordinate}>
            Latitude: {coordinates.latitude}
          </Text>

          <Text style={styles.coordinate}>
            Longitude: {coordinates.longitude}
          </Text>

        </View>

      )}


      <TouchableOpacity
        style={styles.refreshButton}
        onPress={loadPermissionStatus}
      >

        <Text style={styles.buttonText}>
          Refresh Permission Status
        </Text>

      </TouchableOpacity>


      <Text style={styles.footer}>
        Param Classes | React Native Tutorial
      </Text>

    </ScrollView>

  );

}


// Styles

const styles = StyleSheet.create({

  container: {
    flex: 1,
    backgroundColor: '#F1F5F9',
  },

  content: {
    padding: 20,
    paddingTop: 55,
  },

  heading: {
    fontSize: 27,
    fontWeight: 'bold',
    color: '#102A43',
  },

  subtitle: {
    fontSize: 15,
    color: '#64748B',
    marginTop: 6,
    marginBottom: 22,
  },

  card: {
    backgroundColor: '#FFFFFF',
    padding: 18,
    borderRadius: 14,
    marginBottom: 16,
    elevation: 3,
  },

  cardTitle: {
    fontSize: 19,
    fontWeight: 'bold',
    color: '#1E293B',
  },

  description: {
    fontSize: 13,
    color: '#64748B',
    marginTop: 8,
  },

  status: {
    fontSize: 14,
    color: '#2563EB',
    fontWeight: '600',
    marginTop: 12,
  },

  button: {
    backgroundColor: '#2563EB',
    padding: 13,
    borderRadius: 9,
    marginTop: 15,
    alignItems: 'center',
  },

  buttonText: {
    color: '#FFFFFF',
    fontWeight: 'bold',
    fontSize: 14,
  },

  locationBox: {
    backgroundColor: '#DBEAFE',
    padding: 16,
    borderRadius: 12,
    marginTop: 10,
  },

  locationTitle: {
    fontSize: 17,
    fontWeight: 'bold',
    color: '#1E40AF',
    marginBottom: 10,
  },

  coordinate: {
    fontSize: 13,
    color: '#1E3A8A',
    marginTop: 5,
  },

  refreshButton: {
    backgroundColor: '#0F172A',
    padding: 14,
    borderRadius: 10,
    alignItems: 'center',
    marginTop: 10,
  },

  footer: {
    textAlign: 'center',
    color: '#64748B',
    marginTop: 25,
    marginBottom: 20,
    fontSize: 12,
  },

});

14. Understand the Application Code

Let's understand the important functions.

14.1 useCameraPermissions()

This hook provides the current camera permission state and the function to request camera access.

14.2 requestForegroundPermissionsAsync()

This function requests location permission while the application is in use.

14.3 getCurrentPositionAsync()

This function retrieves the device's current geographic coordinates after permission is granted.

14.4 getPermissionsAsync()

This function checks the current notification permission state.

14.5 requestPermissionsAsync()

This function requests notification permission from the operating system.

14.6 Linking.openSettings()

This function opens the device settings so users can manually change application permissions.

15. Run the Application

Open the terminal.

Execute:

npx expo start

Run the application on an Android emulator, iOS simulator, or physical device.

For actual camera and GPS testing, a physical device is recommended.

16. Test Camera Permission

Follow these steps:

  1. Open Permission Manager.

  2. Find Camera Permission.

  3. Press Request Access.

  4. Read the system permission dialog.

  5. Select Allow.

  6. Return to the application.

  7. Check the camera permission status.

Now deny the permission and test the denied state.

17. Test Location Permission

Follow these steps:

  1. Find Location Permission.

  2. Press Request Access.

  3. Allow location access while using the app.

  4. Wait for the device location.

  5. Check latitude and longitude.

  6. Try denying permission.

  7. Verify the application handles the denied state.

On Android and iOS, users may choose approximate rather than precise location access.

18. Test Notification Permission

Follow these steps:

  1. Find Notification Permission.

  2. Press Request Access.

  3. Read the system notification prompt.

  4. Select Allow.

  5. Return to the application.

  6. Check the notification permission status.

On Android 13 and later, notification permission behavior depends on the application's target SDK and configuration.

19. Handle Denied Permissions Properly

A professional application should never assume that the user will grant every permission.

For example, if the user denies camera permission, the application should display an understandable message.

If the permission cannot be requested again, provide an option to open device settings.

Example:

import { Alert, Linking } from 'react-native';

Alert.alert(
  'Permission Required',
  'Please enable camera access in Settings.',
  [
    {
      text: 'Cancel',
      style: 'cancel',
    },
    {
      text: 'Open Settings',
      onPress: () => Linking.openSettings(),
    },
  ]
);

Never repeatedly display permission requests or block unrelated application features.

20. Test Permissions on Real Devices

Permission behavior should be tested on both Android and iOS.

Test these scenarios:

  • First-time permission request.

  • Permission granted.

  • Permission denied.

  • Permission denied multiple times.

  • Permission changed from device settings.

  • Approximate location access.

  • Precise location access.

  • Notification permission disabled.

  • Application restarted after permission changes.

You may need to uninstall and reinstall the application to reset certain permission states during testing.

21. Important Expo Development Build Notes

Expo Go is useful for learning and testing many permission workflows.

However, Expo Go is a prebuilt host application. Its native configuration is not identical to your standalone application.

For production permission testing:

  1. Configure app.json.

  2. Install the required Expo packages.

  3. Generate or update native configuration.

  4. Create a development or production build.

  5. Test the permission prompts on a device.

Example Android development build:

eas build --platform android --profile development

A new native build is generally required when changing native permission configuration.

22. Permission Management Best Practices

Follow these important practices:

  1. Request permissions only when a feature needs them.

  2. Explain why the permission is required.

  3. Do not request unnecessary permissions.

  4. Handle denied permissions gracefully.

  5. Check permission status before accessing protected resources.

  6. Provide a Settings option when appropriate.

  7. Respect approximate location access.

  8. Avoid unnecessary background location tracking.

  9. Test permissions on different operating system versions.

  10. Protect user information and follow privacy requirements.

23. Final Project Outcome

After completing this tutorial, you will have built a Permission Manager App with:

  • Camera permission management.

  • Location permission management.

  • Notification permission management.

  • Permission status checking.

  • Location coordinate retrieval.

  • Permission denial handling.

  • Device settings navigation.

  • Permission refresh functionality.

You will understand how React Native applications request and manage sensitive device permissions on Android and iOS.

24. Conclusion

Permissions are an essential part of modern mobile application development.

Every React Native developer should understand how to request, check, and manage camera, location, and notification permissions.

Using Expo libraries makes permission management easier, while proper error handling and privacy practices help create secure and reliable applications.

Practice Task: Extend the Permission Manager App by adding microphone permission and photo gallery permission. Display their permission status and handle denied access properly.

25. Frequently Asked Questions

Q1. What are runtime permissions?

Runtime permissions are permissions requested while an application is running, allowing users to control access to sensitive device resources.

Q2. How do I request camera permission in React Native?

You can use the useCameraPermissions() hook from Expo Camera.

Q3. How do I request location permission?

Use Location.requestForegroundPermissionsAsync() from Expo Location.

Q4. How do I request notification permission?

Use Notifications.requestPermissionsAsync() from Expo Notifications.

Q5. What happens if the user denies permission?

The application should handle the denial gracefully and avoid accessing the protected feature. If the operating system no longer allows another prompt, guide the user to device settings.

Q6. Are Android and iOS permissions identical?

No. Both platforms have different permission interfaces, configuration requirements, and access rules.

Q7. Can an application access location in the background?

Yes, but background location requires additional platform configuration and permission approval. It should only be requested when necessary for the application's functionality.

←
Post 35 of 39
→