React Native Permissions Guide: Android and iOS Declarations, Runtime Prompts, and Release Audits
React NativePermissionsAndroidiOSExpoDevice APIs

React Native Permissions Guide: Android and iOS Declarations, Runtime Prompts, and Release Audits

RReact Native Live Editorial Team
2026-11-10
8 min read

A practical React Native permissions guide covering Android and iOS declarations, runtime prompts, fallback states, Expo configuration, and release audits.

React Native Permissions Guide: Android and iOS Declarations, Runtime Prompts, and Release Audits

Permissions are part of your app’s product flow, not just a manifest setting. This guide shows how to map device features to Android and iOS declarations, request access at the right moment, handle denial and restricted states, and estimate the review and testing work before release.

Overview

A React Native app can access sensitive device capabilities only after satisfying two separate concerns: the platform must know why the capability is needed, and the user must grant access when runtime authorization is required. A permission can therefore fail in several places even when the JavaScript code appears correct.

  • Declaration: Android permissions belong in the application manifest, while iOS usage descriptions and capability-related settings belong in the native project or Expo configuration.
  • Runtime request: The app asks the user for access when the feature is needed, rather than assuming that a declaration grants access.
  • State handling: The feature must respond to granted, denied, blocked, restricted, limited, and unavailable states where the platform or library exposes them.
  • Release review: Store metadata, privacy copy, data collection disclosures, and native configuration should describe the same behavior as the shipped binary.

The exact behavior varies by operating-system version, device settings, permission type, and build configuration. Treat the following as a repeatable implementation framework. Before release, verify the current Android, iOS, Expo, library, and store documentation for the versions your app actually uses.

Permission comparison

CapabilityAndroid considerationsiOS considerationsProduct decision
CameraDeclare camera access and request it before opening the camera feature.Provide a camera usage description and request access before capture.Explain the immediate action: scanning, taking a photo, or recording video.
LocationChoose the least access needed, such as foreground use rather than background use.Separate foreground and background needs and explain when location is used.Do not request continuous access for a one-time lookup.
PhotosMedia access can differ according to the operation and platform version.Photo-library access may support narrower or limited selection flows.Prefer a picker or selected-item flow when full-library access is unnecessary.
ContactsDeclare and request contacts access only if the feature genuinely reads contacts.Provide a contacts usage description and handle a user who declines.Offer manual entry or sharing alternatives.
MicrophoneRequest microphone access before recording or voice capture.Provide a microphone usage description and request access before recording.Make recording state visible and provide a clear stop control.
BluetoothNearby-device and Bluetooth-related access may depend on the operation and Android version.Bluetooth usage descriptions and capability configuration may be required.Explain the device connection purpose rather than saying only “Bluetooth.”
TrackingDo not assume an advertising or analytics identifier is equivalent to device access.Review tracking authorization separately from ordinary app permissions.Request only when the relevant use case exists and provide accurate privacy copy.

How to estimate

Before implementing a permission, estimate the work by scoring five inputs. This does not predict store approval or user acceptance. It gives the team a consistent way to identify integration and release risk.

  1. Count capabilities: list each distinct capability, such as camera, location, microphone, or contacts. Do not count screens; count permissions and access modes.
  2. Count platforms: record whether Android, iOS, or both require configuration and testing.
  3. Classify request timing: mark each permission as first-use, onboarding, background, or optional. First-use requests generally produce a clearer user explanation than a batch prompt during launch.
  4. Count fallback paths: include denied, blocked, restricted, limited, unavailable, and settings-return flows that apply to the feature.
  5. Count build surfaces: include JavaScript, Android manifest or native code, iOS usage descriptions or native code, Expo configuration, automated tests, and release documentation.

A simple planning score is:

Permission work score = capabilities × platforms + fallback paths + build surfaces

Use the score as a comparison tool between feature designs, not as a promise of hours or cost. A design that uses a system picker or one-time access may have a smaller surface than a design that requests broad, persistent access. If the score increases because of background behavior, sensitive data, or a native module, schedule a separate security and privacy review.

A safe first-use workflow

  1. Explain the feature in your own interface before invoking the operating-system prompt.
  2. Request only the permission needed for the action the user just selected.
  3. Read the result and continue only when the required state is granted.
  4. Show a useful fallback when access is denied, such as manual entry, a picker, or a read-only mode.
  5. If the permission is blocked or cannot be requested again, explain how to change it in system settings without implying that access is mandatory.
  6. Re-check the state when the app returns to the foreground, because users can change access outside the app.

Inputs and assumptions

Keep a permission inventory in the repository. For every capability, record the feature owner, platform declarations, request library, user-facing rationale, data destination, retention behavior, fallback, and test cases. This turns permission work into an auditable input rather than a last-minute native configuration task.

Android

Review the merged manifest, not only the source manifest. A dependency may contribute a permission that your team did not add directly. Confirm that each declared permission is tied to a real feature, that runtime requests match the declarations, and that the app behaves correctly when a user denies access. When targeting a newer Android version, re-check whether the permission is grouped, split, limited, or subject to a different access model.

iOS

Review every usage description in the built application, including wording, capitalization, and whether the explanation matches the actual feature. An empty or missing description can prevent a request from working as intended. Also review capability settings, privacy manifests or related declarations where applicable to the SDKs and OS versions in your release, and the privacy details supplied during submission.

Expo and permission libraries

With Expo, configuration often belongs in the app configuration and may be applied during a native build rather than through a JavaScript-only update. Confirm that the installed modules, config plugins, development build, and production build use the same configuration. With a permissions library, centralize checks and requests behind a small application service instead of scattering platform constants throughout screens.

async function ensureCameraAccess() {
  const current = await permissions.checkCamera();

  if (current === 'granted') return true;
  if (current === 'blocked' || current === 'restricted') return false;

  const result = await permissions.requestCamera();
  return result === 'granted';
}

The API names differ by library. The important design is the state transition: check, explain, request, interpret the result, and provide a fallback. Do not treat any non-error return value as permission granted.

Worked examples

Example 1: Receipt scanner

A receipt scanner needs camera access on Android and iOS. Assume two platforms, one capability, a first-use request, two fallback states (denied and blocked), and four build surfaces (JavaScript, native declarations, tests, and release documentation).

Score: 1 × 2 + 2 + 4 = 8. The implementation should show a short explanation when the user taps “Scan receipt,” request camera access, and offer manual upload or entry if access is unavailable. Test a fresh install, denial, repeated use, settings changes, and a production build.

Example 2: Delivery tracking

A delivery app needs foreground location while a user views an active delivery. Assume one capability, two platforms, first-use timing, three fallback paths (denied, restricted, and unavailable), and five build surfaces because background behavior is explicitly excluded but location-specific configuration requires extra review.

Score: 1 × 2 + 3 + 5 = 10. The product should not request background access merely because the app may add it later. If background tracking becomes a requirement, recalculate the inventory and review the rationale, data handling, battery impact, platform declarations, and store disclosures as a new feature.

Example 3: Profile import

A profile import flow needs contacts access but can also accept a manually entered email address. Assume one capability, two platforms, optional first-use timing, three fallback paths, and four build surfaces.

Score: 1 × 2 + 3 + 4 = 9. Because a fallback exists, the app can explain the benefit and let the user continue without contacts access. The permission should be requested only after the user chooses contact import, not during account creation.

When to recalculate

Revisit the permission inventory whenever a device feature, native dependency, build target, or privacy disclosure changes. In particular, recalculate before adding a new platform, changing from foreground to background access, replacing a system picker with direct library access, or upgrading React Native, Expo, an operating-system target, or a permissions library.

Use this release audit before creating a candidate build:

  • List every device capability used by the JavaScript and native layers.
  • Compare the list with the merged Android manifest, iOS usage descriptions, Expo configuration, and native capability settings.
  • Test fresh installs on representative Android and iOS devices, not only an existing development installation.
  • Test granted, denied, blocked, restricted, limited, unavailable, and settings-return states where relevant.
  • Confirm that rationale text describes the real action, data use, and fallback.
  • Check that analytics and crash reports do not accidentally record sensitive permission-related data.
  • Compare in-app privacy language, store disclosures, and the shipped behavior.
  • Record the OS versions, device conditions, build profile, and permission results so a future change can be compared.

Permission behavior is easy to overlook because it sits between product UX, JavaScript, native configuration, and release policy. A small inventory and repeatable score make that boundary visible. Recalculate when the inputs change, then verify the result on clean installs before shipping.

Related Topics

#React Native#Permissions#Android#iOS#Expo#Device APIs
R

React Native Live Editorial Team

React Native Development Editors

Senior editor and content strategist. Writing about technology, design, and the future of digital media. Follow along for deep dives into the industry's moving parts.