Permissions
Runtime permissions (camera, location, notifications, microphone, photos) must be requested at the moment of use, not on app launch. Both iOS and Android require a human-readable rationale; iOS reads it from Info.plist, Android from your in-app dialog. react-native-permissions is the cross-platform wrapper that hides the per-platform plumbing.
Check, request, and gracefully degrade
EXAMPLE
import { Platform, Alert, Linking } from 'react-native';
import {
check, request, openSettings,
PERMISSIONS, RESULTS,
} from 'react-native-permissions';
// 1) Pick the right permission key per platform
const CAMERA = Platform.select({
ios: PERMISSIONS.IOS.CAMERA,
android: PERMISSIONS.ANDROID.CAMERA,
})!;
// 2) Helper that handles every RESULTS branch
export async function ensureCamera(): Promise<boolean> {
let status = await check(CAMERA);
if (status === RESULTS.GRANTED) return true;
if (status === RESULTS.DENIED) {
// Show your in-app rationale BEFORE prompting (especially on Android 11+)
const accept = await new Promise<boolean>((resolve) => {
Alert.alert(
'Allow camera access?',
'We use the camera to scan QR codes for sign-in. No images are stored.',
[
{ text: 'Not now', style: 'cancel', onPress: () => resolve(false) },
{ text: 'Allow', onPress: () => resolve(true) },
]
);
});
if (!accept) return false;
status = await request(CAMERA);
return status === RESULTS.GRANTED;
}
if (status === RESULTS.BLOCKED) {
// User said 'never ask again' — only Settings can re-enable
Alert.alert('Camera blocked', 'Enable Camera in Settings to scan.', [
{ text: 'Cancel', style: 'cancel' },
{ text: 'Open Settings', onPress: () => openSettings() },
]);
return false;
}
if (status === RESULTS.UNAVAILABLE) {
Alert.alert('No camera', 'This device does not have a camera.');
return false;
}
return false;
}
// 3) At the call site, fall back gracefully instead of crashing
async function onScanPressed() {
if (await ensureCamera()) {
navigation.navigate('Scanner');
} else {
navigation.navigate('ManualEntry'); // always offer an alternative
}
}
// ----- iOS Info.plist -----
// <key>NSCameraUsageDescription</key>
// <string>We use the camera to scan QR codes for sign-in.</string>
// <key>NSLocationWhenInUseUsageDescription</key>
// <string>...</string>
// ----- AndroidManifest.xml -----
// <uses-permission android:name="android.permission.CAMERA" />
Why it matters
BLOCKED is the only state you cannot recover from with a prompt; the user must change it in Settings. Always pair your permission ask with a fallback path (manual code entry, address input, etc.) so the feature is usable for the people who decline.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
// Each native API has its own permission flow. // Camera, Location, Notifications, Microphone, Media Library, Contacts, Calendar.Try it Yourself »
Discussion
Loading…