Web Security's own domain covered the browser's own, fairly limited permission prompts (camera, location, notifications) as something a site requests at the moment it needs them. Mobile's permission model is both more granular and more strictly enforced by the operating system itself — and getting it wrong gets an app rejected, not just annoying to use.
3 min read
import { Camera } from "expo-camera";
const { status } = await Camera.requestCameraPermissionsAsync();
if (status === "granted") {
// proceed to use the camera
} else {
// show a clear explanation, and a path to enable it in Settings
}Every sensitive device capability — camera, location, contacts, microphone, push notifications, photo library access — requires an explicit runtime permission request, and the operating system itself (not just the app) enforces the result: a denied permission means the corresponding native API call simply fails or returns nothing, regardless of what the app's own code tries to do. This is a real, structural enforcement layer beyond what Web Security's own domain covered for browser permissions — the OS, not just the app's own logic, is the actual gatekeeper.
Requesting every permission an app might ever need immediately on first launch — before a user has any context for why a specific permission matters — is both a real app-store-review risk (both Apple and Google explicitly flag this pattern) and a genuine usability problem: a user asked "allow notifications?" before even seeing what the app does has no real basis to say yes, and often reflexively denies it. Requesting a specific permission at the exact moment a feature that needs it is actually used gives the user real context, and both platforms' own review guidelines explicitly favor this pattern over upfront, unexplained bulk requests.
Info.plist and AndroidManifest.xml: declaring WHY, not just WHICH<!-- iOS Info.plist -->
<key>NSCameraUsageDescription</key>
<string>We use your camera to let you scan receipts for expense tracking.</string>iOS specifically requires a human-readable justification string for each sensitive permission, shown to the user directly in the system permission dialog — an app requesting camera access with a vague or missing justification is a real, common app-review rejection reason, not just a best-practice suggestion. Android's manifest declares which permissions an app needs more than why, though modern Android versions increasingly surface runtime context to users in similar ways.
"granted" — can use the capability right now
"denied" — user said no; re-requesting usually just re-shows the SAME
system dialog, or does nothing, depending on platform/history
"undetermined" — never asked yet
A denied permission generally can't be "re-requested" through the same in-app prompt a second time on most platforms — the practical, correct handling is detecting the denied state and guiding the user to the OS's own Settings app to change it manually, with a clear, specific explanation of what they're enabling and why, rather than repeatedly calling a request function that will just silently do nothing.
A browser's own permission prompts are real, but a website typically has a narrower set of sensitive capabilities it can even ask for at all, and a user closing a browser tab entirely sidesteps any lingering access. A mobile app installed on a device has a much deeper potential reach into real personal data and hardware if granted — exactly why the OS-level enforcement, the required justification strings, and the app-store review scrutiny around permission requests are all, deliberately, stricter than anything the web's own permission model requires.
Check your understanding
A quick comprehension check — not tracked, not graded, just for you.
1. How does mobile's permission enforcement differ from a browser's permission prompts?
2. Why do both app stores favor requesting a permission at the moment of need rather than upfront at launch?
3. What should an app do when a permission has already been denied, rather than repeatedly requesting it?
Mobile Development