React Native guide
Mastering Permissions in React Native with react-native-permissions
Permissions look simple until the first production edge case: Android behaves differently from iOS, blocked states need a settings path, one-time permissions expire, and app stores care about why you ask. This guide shows how to handle permissions with `react-native-permissions` without turning your codebase into scattered platform checks.
Why Use react-native-permissions?
Mobile apps rarely stay inside pure UI. They need camera, photos, location, microphone, notifications, Bluetooth, motion, contacts, or biometrics. Each of those features crosses a trust boundary, so iOS and Android force the app to ask clearly and handle the user's answer correctly.
`react-native-permissions` gives React Native teams a shared vocabulary for that flow: `check`, `request`, `RESULTS`, `PERMISSIONS`, notification helpers, and settings links. It does not remove platform rules, but it makes them easier to centralize.
Installation and Platform Setup
The package supports current React Native releases and provides platform-specific setup for iOS, Android, Expo, and Windows. Keep the configuration narrow: only add permissions the product actually uses.
Install the package
Install the library first. Recent React Native versions support autolinking, so manual linking is rarely needed.
npm install react-native-permissions
# or
yarn add react-native-permissionsConfigure iOS permissions
On iOS, only enable the permission handlers your app actually uses, then run pod install and add matching usage descriptions in Info.plist.
setup_permissions([
'Camera',
'LocationWhenInUse',
'Microphone',
]);Configure Android permissions
On Android, declare required permissions in AndroidManifest.xml. Runtime prompts still need to be handled in app code for dangerous permissions.
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />Configure Expo apps
For Expo projects, configure permissions through app.json or app.config.ts instead of manually editing native files.
plugins: [
['react-native-permissions', { iosPermissions: ['Camera'] }],
],
android: {
permissions: ['android.permission.CAMERA'],
}Understanding Permission Statuses
The most important part is not the permission constant; it is the state machine. Good permission handling reacts differently to unavailable, denied, blocked, granted, and limited states.
RESULTS.UNAVAILABLE
The feature is not available on this device or platform.
RESULTS.DENIED
The permission has not been granted, but it can still be requested.
RESULTS.BLOCKED
The user denied the permission in a way that requires app settings.
RESULTS.GRANTED
The permission is available and the feature can run.
RESULTS.LIMITED
The permission is partially granted, such as limited photo access on iOS.
A Practical Permission Flow
In production, avoid asking again and again. Check first. If it is granted, continue. If it is denied, ask at the right moment. If it is blocked, explain the issue and open app settings.
import {check, openSettings, request, RESULTS} from 'react-native-permissions';
async function ensurePermission(permission) {
const status = await check(permission);
if (status === RESULTS.GRANTED || status === RESULTS.LIMITED) {
return status;
}
if (status === RESULTS.BLOCKED) {
await openSettings('application');
return status;
}
if (status === RESULTS.DENIED) {
return request(permission);
}
return status;
}Camera Permission Example
Camera access is a good first abstraction because it exists on both platforms and commonly appears in profiles, KYC, delivery, social, healthcare, and ecommerce apps.
import {Platform} from 'react-native';
import {PERMISSIONS, RESULTS, check, openSettings, request} from 'react-native-permissions';
const cameraPermission = Platform.select({
ios: PERMISSIONS.IOS.CAMERA,
android: PERMISSIONS.ANDROID.CAMERA,
});
export async function requestCameraPermission() {
if (!cameraPermission) return RESULTS.UNAVAILABLE;
const current = await check(cameraPermission);
if (current === RESULTS.GRANTED) return current;
if (current === RESULTS.BLOCKED) {
await openSettings('application');
return current;
}
return request(cameraPermission);
}Location Permission Example
Location needs extra care. On iOS, decide whether `LOCATION_WHEN_IN_USE` is enough before considering background location. On Android 11+, one-time permissions can be revoked after the app is backgrounded or closed.
import {Platform} from 'react-native';
import {PERMISSIONS, check, request} from 'react-native-permissions';
const locationPermission = Platform.select({
ios: PERMISSIONS.IOS.LOCATION_WHEN_IN_USE,
android: PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION,
});
export async function ensureLocationPermission() {
if (!locationPermission) return 'unavailable';
const status = await check(locationPermission);
return status === 'denied' ? request(locationPermission) : status;
}Using the Permission Service in a Component
Keep UI components focused on user actions. The component should not know every platform detail; it should call a small service and react to the final status.
function ExampleScreen() {
const handleCamera = React.useCallback(async () => {
const status = await requestCameraPermission();
if (status === 'granted') {
// Open camera flow here
}
}, []);
return <Button title="Use camera" onPress={handleCamera} />;
}Notifications, Settings, and Multiple Permissions
Notifications deserve a separate flow because platform rules keep changing. On Android 13+, runtime notification permission applies when targeting SDK 33 or later. On iOS, you can request options such as alert and sound. For blocked or disabled settings, use `openSettings` and guide the user instead of trapping them in a dead end.
For screens that need more than one permission, use `checkMultiple` for visibility and `requestMultiple` when the user chooses to continue. Do not request a bundle of unrelated permissions at app launch.
Best Practices for Production Apps
Ask for permission at the moment the user understands why it is needed.
Keep iOS Info.plist descriptions specific, human, and tied to the feature.
Declare only Android permissions the app actually uses.
Handle blocked permissions with a settings path instead of repeatedly prompting.
Test one-time permissions on Android 11+ and notification behavior on Android 13+.
Mock react-native-permissions in Jest so tests do not depend on native modules.
Testing Permissions with Jest
Native modules are not available in normal Jest runs. The package provides a mock entry, so add it to your Jest setup file and test your permission branches without relying on a device prompt.
jest.mock('react-native-permissions', () => require('react-native-permissions/mock'));Common Mistakes to Avoid
- Requesting every permission during onboarding.
- Adding vague iOS usage descriptions such as “needed”.
- Forgetting to rerun `pod install` after iOS setup changes.
- Expecting Android `check` to behave exactly like iOS.
- Ignoring limited photo access and blocked settings states.
- Testing only on simulators and missing real-device behavior.
Frequently Asked Questions
What is react-native-permissions used for?
react-native-permissions provides a unified API for checking and requesting permissions across React Native apps on iOS, Android, and Windows.
Do I still need Info.plist and AndroidManifest.xml?
Yes. The library handles runtime permission flow, but iOS still needs usage descriptions and enabled handlers, while Android still needs declared permissions in AndroidManifest.xml.
Why does Android check not always return blocked?
On Android, blocked status is usually known after calling request. That is why permission flows should be tested on actual Android devices and not only inferred from check.
Can I use react-native-permissions with Expo?
Yes. Expo projects should configure permissions in app.json or app.config.ts using the library plugin and platform-specific permission values.
Should I request all permissions when the app opens?
No. Request permissions when the user reaches the feature that needs them. This improves trust, conversion, and platform-review outcomes.
Conclusion
Mastering permissions in React Native is less about memorizing constants and more about designing a respectful flow. Ask only when the feature needs it, explain the value clearly, handle blocked and limited states, and centralize the logic so the rest of the app stays clean.
Need Help with React Native Permissions?
Dev Entity builds and audits React Native apps for iOS and Android. We can help with permission flows, native modules, app-store readiness, testing, and long-term app maintenance.
Technical references used: official react-native-permissions package documentation and React Native PermissionsAndroid documentation.