Unified permissions API for React Native on iOS, Android and Windows platforms
—
Request permissions from the user with optional rationale dialogs. Handles the native permission request flow and user interaction.
Request a single permission from the user, with optional rationale dialog for explanation.
/**
* Request a single permission from the user
* @param permission - The permission to request
* @param rationale - Optional rationale dialog or function for explanation
* @returns Promise resolving to the permission status after user interaction
*/
function request(permission: Permission, rationale?: Rationale): Promise<PermissionStatus>;
type Rationale = RationaleObject | (() => Promise<boolean>);
interface RationaleObject {
title: string;
message: string;
buttonPositive: string;
buttonNegative?: string;
}Usage Examples:
import { request, PERMISSIONS, RESULTS } from "react-native-permissions";
// Basic permission request
const cameraStatus = await request(PERMISSIONS.IOS.CAMERA);
if (cameraStatus === RESULTS.GRANTED) {
console.log("Camera permission granted");
}
// Request with rationale dialog (Android)
const micStatus = await request(PERMISSIONS.ANDROID.RECORD_AUDIO, {
title: "Microphone Permission",
message: "This app needs microphone access to record audio for voice messages.",
buttonPositive: "Grant Access",
buttonNegative: "Not Now"
});
// Request with custom rationale function
const locationStatus = await request(
PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION,
async () => {
// Custom logic to show rationale
const userWantsToGrant = await showCustomRationaleDialog();
return userWantsToGrant;
}
);Request multiple permissions in a single call, with optional rationale for Android.
/**
* Request multiple permissions simultaneously
* @param permissions - Array of permissions to request
* @returns Promise resolving to object mapping each permission to its status
*/
function requestMultiple<P extends Permission[]>(
permissions: P
): Promise<Record<P[number], PermissionStatus>>;Usage Examples:
import { requestMultiple, PERMISSIONS, RESULTS } from "react-native-permissions";
// Request multiple iOS permissions
const statuses = await requestMultiple([
PERMISSIONS.IOS.CAMERA,
PERMISSIONS.IOS.MICROPHONE,
PERMISSIONS.IOS.PHOTO_LIBRARY,
]);
// Check individual results
Object.entries(statuses).forEach(([permission, status]) => {
console.log(`${permission}: ${status}`);
});
// Check if all permissions were granted
const allGranted = Object.values(statuses).every(status => status === RESULTS.GRANTED);
if (allGranted) {
console.log("All permissions granted - ready to proceed");
} else {
console.log("Some permissions were denied");
}
// Request specific Android permissions for media access
const mediaStatuses = await requestMultiple([
PERMISSIONS.ANDROID.CAMERA,
PERMISSIONS.ANDROID.RECORD_AUDIO,
PERMISSIONS.ANDROID.READ_MEDIA_IMAGES,
]);Request full location accuracy from the user when the app has reduced accuracy.
/**
* Request location accuracy upgrade from reduced to full (iOS only)
* @param options - Configuration with purpose key from Info.plist
* @returns Promise resolving to the granted accuracy level
*/
function requestLocationAccuracy(options: LocationAccuracyOptions): Promise<LocationAccuracy>;
interface LocationAccuracyOptions {
purposeKey: string;
}
type LocationAccuracy = 'full' | 'reduced';Usage Examples:
import {
requestLocationAccuracy,
checkLocationAccuracy,
PERMISSIONS,
request
} from "react-native-permissions";
// First ensure location permission is granted
const locationStatus = await request(PERMISSIONS.IOS.LOCATION_WHEN_IN_USE);
if (locationStatus === RESULTS.GRANTED) {
const currentAccuracy = await checkLocationAccuracy();
if (currentAccuracy === 'reduced') {
// Request full accuracy using purpose key from Info.plist
const newAccuracy = await requestLocationAccuracy({
purposeKey: 'NSLocationDefaultAccuracyReduced'
});
if (newAccuracy === 'full') {
console.log("Full location accuracy granted");
} else {
console.log("User chose to keep reduced accuracy");
}
}
}Request notification permissions with specific notification types and optional rationale.
/**
* Request notification permissions with specific options
* @param options - Array of notification types to request
* @param rationale - Optional rationale for Android
* @returns Promise resolving to notification status and detailed settings
*/
function requestNotifications(
options?: NotificationOption[],
rationale?: Rationale
): Promise<NotificationsResponse>;
type NotificationOption =
| 'alert'
| 'badge'
| 'sound'
| 'carPlay'
| 'criticalAlert'
| 'provisional'
| 'providesAppSettings';
interface NotificationsResponse {
status: PermissionStatus;
settings: NotificationSettings;
}Usage Examples:
import { requestNotifications, RESULTS } from "react-native-permissions";
// Request basic notification permissions
const basicNotifications = await requestNotifications(['alert', 'badge', 'sound']);
if (basicNotifications.status === RESULTS.GRANTED) {
console.log("Basic notifications granted");
}
// Request advanced notification permissions (iOS)
const advancedNotifications = await requestNotifications([
'alert',
'badge',
'sound',
'criticalAlert',
'provisional'
]);
console.log("Notification settings:", advancedNotifications.settings);
// Request with rationale (Android)
const androidNotifications = await requestNotifications(
['alert', 'badge'],
{
title: "Enable Notifications",
message: "Get notified about important updates and messages.",
buttonPositive: "Enable",
buttonNegative: "Skip"
}
);
// Check specific notification capabilities
if (advancedNotifications.settings.criticalAlert) {
console.log("Critical alerts are enabled");
}
if (advancedNotifications.settings.provisional) {
console.log("Provisional notifications are enabled");
}The request flow varies by platform:
import { request, check, openSettings, PERMISSIONS, RESULTS } from "react-native-permissions";
async function requestCameraWithFallback() {
// Check current status first
let status = await check(PERMISSIONS.IOS.CAMERA);
if (status === RESULTS.DENIED) {
// Request permission
status = await request(PERMISSIONS.IOS.CAMERA);
}
if (status === RESULTS.BLOCKED) {
// Permission is blocked, direct user to settings
console.log("Camera permission is blocked. Please enable in Settings.");
await openSettings();
}
return status === RESULTS.GRANTED;
}// Good rationale example
const goodRationale = {
title: "Camera Access Required",
message: "Camera access is needed to take photos for your profile and share them with friends.",
buttonPositive: "Grant Access",
buttonNegative: "Not Now"
};
// Poor rationale example - too vague
const poorRationale = {
title: "Permission Required",
message: "This app needs camera permission to work properly.",
buttonPositive: "OK",
buttonNegative: "Cancel"
};Use custom rationale functions for complex logic or custom UI:
import { request, PERMISSIONS } from "react-native-permissions";
const customRationaleFunction = async (): Promise<boolean> => {
// Show custom modal or alert
const result = await showCustomPermissionDialog({
title: "Location Access",
message: "Enable location to find nearby restaurants and get personalized recommendations.",
primaryButton: "Enable Location",
secondaryButton: "Maybe Later"
});
return result.action === 'primary';
};
const locationStatus = await request(
PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION,
customRationaleFunction
);Request functions may throw errors in these cases:
import { request, PERMISSIONS } from "react-native-permissions";
async function safeRequestPermission(permission: Permission) {
try {
const status = await request(permission);
return { success: true, status };
} catch (error) {
console.error("Permission request failed:", error);
return { success: false, error };
}
}
// Usage
const result = await safeRequestPermission(PERMISSIONS.IOS.CAMERA);
if (result.success) {
console.log("Permission status:", result.status);
} else {
console.log("Request failed:", result.error);
}Install with Tessl CLI
npx tessl i tessl/npm-react-native-permissions