react-native-permissions là lib chuẩn cho iOS/Android permission.
API thống nhất:
import { check, request, PERMISSIONS, RESULTS } from 'react-native-permissions'
async function requestCamera() {
const permission = Platform.select({
ios: PERMISSIONS.IOS.CAMERA,
android: PERMISSIONS.ANDROID.CAMERA,
})!
const status = await check(permission)
switch (status) {
case RESULTS.UNAVAILABLE:
// device không có camera
break
case RESULTS.DENIED:
// chưa được hỏi → request lần đầu
const result = await request(permission)
return result === RESULTS.GRANTED
case RESULTS.GRANTED:
return true
case RESULTS.BLOCKED:
// user từ chối permanent → mở Settings
Linking.openSettings()
break
}
}Setup config:
- iOS: Info.plist thêm key NSCameraUsageDescription, NSLocationWhenInUseUsageDescription, ... với mô tả lý do (App Store reject nếu thiếu hoặc generic).
- Android: AndroidManifest.xml thêm <uses-permission>. Android 6+ cần runtime request, lib tự handle.
Pattern UX 2026:
1. Pre-prompt: trước khi popup native, hiển thị custom modal explain why → tăng grant rate.
2. Just-in-time request: chỉ request khi feature cần (vd request camera khi user nhấn "Take photo", không request lúc app start).
3. Graceful fallback: nếu denied, app vẫn hoạt động không crash; chỉ hide feature liên quan.
4. Settings deeplink: với BLOCKED, deep link vào Settings app cho user enable manual.
iOS 14+ specific:
- PERMISSIONS.IOS.LOCATION_WHEN_IN_USE vs LOCATION_ALWAYS — request when-in-use trước, sau đó upgrade lên always khi cần background.
- App Tracking Transparency (PERMISSIONS.IOS.APP_TRACKING_TRANSPARENCY) — bắt buộc nếu dùng IDFA.
react-native-permissions is the standard cross-platform permissions library.
Unified API:
import { check, request, PERMISSIONS, RESULTS } from 'react-native-permissions'
async function requestCamera() {
const permission = Platform.select({
ios: PERMISSIONS.IOS.CAMERA,
android: PERMISSIONS.ANDROID.CAMERA,
})!
const status = await check(permission)
switch (status) {
case RESULTS.UNAVAILABLE:
// device has no camera
break
case RESULTS.DENIED:
// never asked → request for the first time
const result = await request(permission)
return result === RESULTS.GRANTED
case RESULTS.GRANTED:
return true
case RESULTS.BLOCKED:
// user permanently denied → open Settings
Linking.openSettings()
break
}
}Config setup:
- iOS: Info.plist adds keys like NSCameraUsageDescription, NSLocationWhenInUseUsageDescription, with a meaningful reason string (App Store rejects missing or generic ones).
- Android: AndroidManifest.xml adds <uses-permission>. Android 6+ requires runtime requests; the library handles it.
2026 UX pattern:
1. Pre-prompt: before the native popup, show a custom modal explaining why → higher grant rate.
2. Just-in-time request: only request when the feature needs it (e.g. ask for camera when the user taps "Take photo", not at app start).
3. Graceful fallback: if denied, the app keeps working without crashing — just hide the related feature.
4. Settings deep link: for BLOCKED, deep-link into Settings so the user can enable manually.
iOS 14+ specifics:
- PERMISSIONS.IOS.LOCATION_WHEN_IN_USE vs LOCATION_ALWAYS — request when-in-use first, upgrade to always when background work demands it.
- App Tracking Transparency (PERMISSIONS.IOS.APP_TRACKING_TRANSPARENCY) — required if using IDFA.