iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

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…