App Permissions
How runtime permissions for camera, location, photos, notifications and more work on iOS and Android, what each answer means (allow, once, deny, don't ask again), what usually breaks, and how to reset and test permissions on every OS version.
You order dinner, and the app wants to send you a photo review prompt. You tap Add photo, and the screen goes black. No camera, no message, no way out. What happened? Three weeks ago, on the very first launch, the app showed three permission pop-ups in a row and you tapped Don’t Allow on all of them, just to get to the menu. The app never recovered from that.
That’s what app permissionsApp permissionsThe user's approval for an app to use things like the camera, location, contacts or notifications.Open in glossary → bugs look like: the feature is fine, the code is fine “on the developer’s phone”, but one answer in a system dialog, given weeks ago, breaks it. Testers find these bugs because they deliberately try every answer, on every OS version, and change their mind in Settings.
How it works
Phones protect sensitive things (camera, microphone, location, photos, contacts) behind runtime permissions: the app must ask the user while it runs, through a system dialog the app can’t change or fake.
- The app declares what it may need. On iOS, each permission needs a purpose string in the app’s settings file (“We use your location to find your delivery address”); it’s shown in the dialog. On Android, the permission is listed in the app’s manifest. Without the declaration, the app can’t ask at all (on iOS it usually crashes when it tries).
- The app checks the current status. Not asked yet, allowed, allowed once, denied, or denied for good. It must check every time it needs the permission, because the user can change it any time in Settings.
- The app asks (if allowed to). Ideally right when the user starts the feature, after a short explanation in the app’s own UI (permission primingPermission primingExplaining in the app why a permission is needed, at the right moment, before the system dialog.Open in glossary →). The OS then shows its dialog.
- The user answers. Allow, allow once, or don’t allow. For location also precise or approximate.
- The app handles every answer. Allowed: the feature works. Denied: the feature explains what’s missing and offers Open Settings (a deep linkDeep linkA link that opens a specific screen inside an app instead of just its home screen.Open in glossary → to the app’s page in system Settings), and the rest of the app keeps working.
- The user changes their mind later. In system Settings, or the OS changes it automatically (one-time grants expire, unused apps lose permissions). The app must notice when it comes back.
The permissions you’ll meet
| Permission | iOS | Android |
|---|---|---|
| Camera, microphone | Allow / Don’t Allow | While using / Only this time / Don’t allow |
| Location | Allow Once / While Using / Don’t Allow, plus Precise on/off. “Always” is a separate, later step. | While using / Only this time / Don’t allow, plus Precise or Approximate. Background (“all the time”) only via Settings. |
| Photos | Limited (selected photos) or Full access | Android 14+: selected photos or all |
| Contacts | Allow, or limited contacts (iOS 18+) | Allow / Don’t allow |
| Notifications | Always needs permission | Needs permission since Android 13 |
| Bluetooth | Permission since iOS 13 | “Nearby devices” since Android 12 |
| Tracking | App Tracking Transparency (iOS 14.5+): “Ask App Not to Track” / “Allow” | No equivalent dialog |
Try the real dialogs
Pick a platform and a permission, then tap the answers to see what each means for the app and for your testing:
Snapbite
Allow “Snapbite” to use your location?
We use your location to find your delivery address.
iOS asks once. The map lets the user switch Precise off, so the app only gets an approximate area.
Allow
“While Using App”: location works whenever the app is in use. “Always” (background location) can only be offered later, in a separate step.
Allow once
Location works for this session only. When the app is no longer in use, the permission goes back to “ask”, and the app may show the dialog again next time.
Don’t allow
The dialog will never appear again for this app. Only the Settings app can change the answer, so the app must explain that and link there.
Tap a button in the dialog to highlight what it means. Exact wording differs a little between OS versions and manufacturers.
Every answer is a test case
| Answer | What the app gets | What to test |
|---|---|---|
| Allow / While using | Access whenever the app is in use | The feature works; still works after restart and update |
| Allow once / Only this time | Access for now; it expires when the app is no longer in use | Next launch: the app checks again and asks again, no silent failure |
| Don’t allow (first time) | No access; Android may ask once more | The app explains and keeps working |
| Denied for good | No access, and the dialog will not appear again | The app shows an explanation with Open Settings, not a dead button |
| Approximate location | An area of a few kilometers | Features that need the street still work (confirm on a map, type the street) |
| Limited photos | Only the photos the user picked | The app shows them and offers a way to pick more |
“Don’t ask again”: when the dialog stops appearing
- iOS shows each permission dialog once. After “Don’t Allow”, asking again does nothing: the OS silently returns “denied”. Only the Settings app can change it.
- Android 11+ lets the app ask again after the first denial (usually after showing an explanation). After the second denial, Android stops showing the dialog and the request fails instantly. (Older Android versions had a “Don’t ask again” checkbox instead.)
So the classic bug is a “Turn on” button that calls the request again: on the developer’s phone it worked once, in real life it does nothing. Once the denial is final, the only working path is Open Settings.
Timing: ask in context
Asking for everything on the first launch is the fastest way to collect “Don’t Allow” answers. Ask when the user starts the feature, and explain the benefit first. The Onboarding lesson has a priming example, and Push Notifications shows why the first moment matters so much for the notification permission.
When permissions change while the app runs
Users can open Settings, change a permission and switch back to the app. What happens next depends on the OS, and it’s a rich source of crashes:
- Android: revoking a runtime permission ends the app’s process. When the user returns, Android recreates the last screen from its saved state (state restorationState restorationBringing the user back to the same screen and data after the OS closed the app in the background.Open in glossary →). If that screen uses the camera or location without checking first, it crashes. Granting a permission does not restart the app.
- iOS: for many privacy permissions (camera, microphone, photos, contacts), turning access off in Settings ends the app, which then starts fresh. Apple barely documents this, but it’s long-standing behavior you’ll see in practice. Location changes are usually reported to the running app instead. Either way, the app must re-check the status when it becomes active.
The OS changes permissions too
- One-time grants expire: iOS “Allow Once” and Android “Only this time” are gone soon after the user leaves the app.
- Auto-reset for unused apps (Android 11+): if an app isn’t opened for a few months, Android removes its runtime permissions. A user returning after a long break meets the dialogs again, or a denied state.
- OS updates add new permissions: an app that worked on Android 12 may need the notification permission on Android 13, or the new photo permissions on Android 13 and 14. That’s why OS versionOS versionWhich version of iOS, Android or another operating system a device runs.Open in glossary → coverage matters here.
Example requirements
What usually goes wrong
| # | Bug | What you see | Typical severity |
|---|---|---|---|
| 1 | Everything asked at launch | Three dialogs in a row before the app appears | High (business) |
| 2 | Blank feature after denial | Black camera view, empty map, endless spinner | High |
| 3 | Dead “Turn on” button | Button requests again; the OS ignores it once denial is final | High |
| 4 | Approximate location breaks it | “Couldn’t find your address” with precise location off | High |
| 5 | Crash after revoking | App crashes when the user returns from Settings | High |
| 6 | “Allow once” treated as forever | Works today, silently fails on the next launch | Medium–High |
| 7 | App state out of sync | In-app switch says “On”, but the OS denied the permission | Medium |
| 8 | Missing purpose string | iOS crashes the moment the app asks for the camera | Critical |
| 9 | New OS version not handled | No notification prompt on Android 13+, no photos on Android 14 with partial access | High |
| 10 | Whole app blocked | “This app needs location” screen with no way to continue without it | Medium–High |
| 11 | Asks too much | Full photo library or background location where less would do | Medium (privacy, store review) |
| 12 | Wrong or vague purpose text | “This app needs camera” or text in the wrong language | Low–Medium |
Find the bug
Snapbite, a food delivery app, has six permission bugs. Next to the phone you control the OS (iOS 18 or Android 15, each switch installs the app fresh), you can close and reopen the app or reinstall it, and you can change permissions in a system Settings panel while the app is open. The device log shows what the app asks the OS.
- Open the app for the first time. What happens before you even see it?
- Try every answer: Allow, Allow once / Only this time, Don’t allow, precise off.
- After denying, try the feature again, and the button that should help.
- Close and reopen the app after “Allow once”. Change permissions in Settings while you’re on the camera screen. Try it on both OS versions.
🐞 Bug hunt: Snapbite permissions
This demo has 6 hidden bugs. Explore it like a tester, then check your findings.
Freshly installed. Tap the icon to open the app for the first time.
Device
Switching OS installs the app fresh on that phone.
Settings › Snapbite
Changing a value here means: leave the app, change it in Settings, come back.
Now: location not asked, camera not asked, notifications not asked.
From the spec
- Ask for each permission only when the user starts the feature that needs it.
- If camera or location is denied, explain why it helps and offer “Open Settings”.
- Approximate location must still work: show the area and let the user confirm the street.
- Check the real permission status every time; a one-time grant means asking again later.
- Changing permissions in Settings must never crash the app.
Device log
- Open the app on the phone…
- 1
Hint: Tap the app icon on a fresh install and count the dialogs.
- 2
Hint: Deny the camera, then tap Add photo.
- 3
Hint: On a fresh install deny location (twice on Android), then tap Use my current location and Turn on location.
- 4
Hint: Allow location with Precise turned off (or Approximate on Android), then tap Use my current location.
- 5
Hint: On Android 15, allow the camera, open Add photo, then set Camera to Don't allow in Settings.
- 6
Hint: Choose Allow Once (or Only this time) for location at launch, use your location, then Close & reopen and try again.
Test scenarios
Functional
- Each feature asks for its permission at the moment it’s needed, after an explanation.
- Allow (or While using): the feature works now, after a restart, after an app update and after an OS update.
- Allow once / Only this time: works now; next launch the app asks again and still works.
- Limited photos and approximate location: the features still work with less access.
- Open Settings buttons land on the app’s own page in system Settings.
- Enabling a permission in Settings and returning: the feature starts working without restarting the app.
Negative
- Don’t allow every permission on first use: the app still opens and the core flow (browse, order, pay) works.
- Denied for good (iOS once, Android twice): the app shows an explanation with Open Settings, never a dead button or a blank screen.
- Revoke each permission in Settings while the app is open, on the screen that uses it, then return.
- Global switches off: Location Services off for the whole phone (iOS Settings › Privacy & Security), Bluetooth off, iOS “Allow Apps to Request to Track” off.
Edge cases
- Fresh install vs update: a user who updates from an old version that never asked must be asked at the right moment, not all at once.
- Auto-reset of unused apps (Android): permissions disappear without the user doing anything.
- OS version boundaries: Android 12 vs 13 (notifications, photos), 13 vs 14 (partial photo access); iOS versions the app supports.
- Manufacturer skins: Samsung and Xiaomi show their own permission and Settings screens (Device Fragmentation).
- Dialog interrupted: a call or notification arrives while the system dialog is open (Interruptions); rotate the phone during the dialog.
- Background location: if the app needs it (delivery drivers, run tracking), check the separate “Always / Allow all the time” step and the reminders the OS shows later.
UI & usability
- The priming screen explains the benefit in one sentence and appears right before the system dialog.
- Purpose strings (iOS) are specific, correct and translated into every supported language.
- Denied states say what is missing, why it helps and how to fix it, with a working button.
- The app never blocks everything because of one optional permission.
Security & privacy
- The app asks for the minimum needed: photo picker instead of full library, approximate instead of precise, foreground instead of background, where possible.
- Data collected with a permission stops being collected when it’s revoked (no cached location sent to the server afterwards).
- On iOS, tracking happens only after “Allow” in the App Tracking Transparency dialog.
- Permission answers are not tied to the user account: a second user on the same phone shares the OS permissions, so the app must not assume anything from the account.
Accessibility
- Priming screens and denied states work with a screen readerScreen readerSoftware that reads the screen aloud for blind and low-vision users, like VoiceOver or TalkBack.Open in glossary →, with clear button labels (“Open Settings”, not “Go”).
- The system dialog gets focus when it appears, and focus returns to a sensible place after it closes.
- Large text doesn’t hide the “Open Settings” button or the explanation.
How to reset and control permissions
You’ll reset permissions constantly: every time you want to see the first-time dialogs again, or test a denied state from scratch.
- Delete and reinstall the app. The simplest reset: all of the app’s permission answers are forgotten. (Keychain data may survive; see Install, Update, Uninstall.)
- Settings › [App]: change camera, photos, location (Never / Ask Next Time Or When I Share / While Using / Always, plus Precise Location) and notifications for one app. “Ask Next Time” lets the app show the location dialog again.
- Reset all apps: Settings › General › Transfer or Reset iPhone › Reset › Reset Location & Privacy. Every app asks again. Useful on a shared test phone, annoying on your own.
- Simulator:
xcrun simctl privacy booted reset all com.example.snapbiteresets the app’s privacy answers, andxcrun simctl privacy booted grant location com.example.snapbitegrants one up front. Device › Erase All Content and Settings starts from zero. Use Features › Location to set a position. - OS versions: install older iOS simulator runtimes in Xcode, and keep at least one real device on the oldest supported version.
- Settings › Apps › [App] › Permissions: set each permission to Allow, Ask every time, or Don’t allow, and toggle Use precise location. Choosing “Ask every time” also clears a final denial.
- With adbadbAndroid Debug Bridge: a command-line tool for installing apps, reading logs and controlling Android devices.Open in glossary →:
adb shell pm revoke com.example.snapbite android.permission.CAMERArevokes one permission (the app’s process is killed, just like in Settings).adb shell pm grant com.example.snapbite android.permission.CAMERAgrants it without a dialog.adb shell pm reset-permissionsresets runtime permissions of all apps on the device.adb shell pm clear com.example.snapbitewipes the app’s data and its permissions.adb install -g snapbite.apkinstalls and grants all runtime permissions (handy for tests that aren’t about permissions).
- Uninstall and reinstall also resets everything.
- OS versions: create emulators for the oldest supported Android, Android 12, 13 and the newest version; each changed permissions. More in ADB basics and Simulators and Emulators.
Example test cases
TC-PERM-001No permission dialogs on first launchpositivehigh
Preconditions
- Fresh install (or permissions reset)
Steps
- Open the app for the first time
- Browse restaurants
Expected result
No system permission dialog appears until the user starts a feature that needs one.
TC-PERM-002Location requested in contextpositivehigh
Steps
- Open Delivery address
- Tap "Use my current location"
- Read the explanation and continue
- Choose While Using the App with Precise on
Expected result
An explanation appears before the system dialog. After allowing, the current street is suggested.
TC-PERM-003Final denial leads to Settings (iOS)negativehigh
Preconditions
- iOS device, location never asked
Steps
- Tap "Use my current location" and choose Don't Allow
- Tap the location button again
Expected result
The app explains that location is off and shows "Open Settings", which opens the app's page in Settings.
TC-PERM-004Second denial on Androidnegativehigh
Preconditions
- Android 11 or newer
Steps
- Deny the camera permission
- Tap Add photo again and read the explanation
- Deny again
- Tap Add photo a third time
Expected result
The dialog appears twice. After the second denial, the app shows an explanation with "Open Settings" instead of a blank camera.
TC-PERM-005Approximate location still helpsedgehigh
Steps
- Allow location with Precise off (iOS) or Approximate (Android)
- Tap "Use my current location"
Expected result
The app shows the approximate area and lets the user confirm or type the street. No error.
TC-PERM-006One-time permission asked again next launchedgemedium
Steps
- Choose "Allow Once" / "Only this time" for location
- Use the feature
- Close the app completely and reopen it
- Use the feature again
Expected result
The app asks again (or explains) and the feature works after allowing. No endless spinner.
TC-PERM-007Revoke camera while the camera screen is opennegativehigh
Preconditions
- Camera allowed
- Run on Android and iOS
Steps
- Open Add photo
- Switch to Settings and set Camera to Don't allow / Off
- Return to the app
Expected result
No crash. The app shows the camera-off explanation or a fresh Home screen.
TC-PERM-008Permission granted in Settings is picked uppositivemedium
Preconditions
- Camera denied for good
Steps
- Tap Add photo, then "Open Settings"
- Allow the camera
- Return to the app and tap Add photo
Expected result
The camera opens without reinstalling or restarting the app.
Tip: click a test case to expand it.
Mobile vs web
- Permissions are per app and live in system Settings; the rules differ between iOS and Android and between OS versions.
- iOS asks once, Android up to twice; after that only Settings helps.
- Revoking can end the app’s process, so test returning from Settings on every screen that uses a permission.
- Build a small device matrixDevice matrixThe list of devices and OS versions a team tests on, chosen to represent real users.Open in glossary → for permissions: oldest supported and newest OS on both platforms, plus Android 12/13/14 for location, notifications and photos.
- Browsers ask too: location, camera, microphone, notifications. The prompt belongs to the browser, and the answer is stored per site.
- Users change it in the site settings (the icon next to the address bar). Test allow, block, and “allow this time” where the browser offers it.
- Browsers may hide or block prompts that appear without a click, and Safari, Chrome and Firefox behave differently. Ask after a user action, never on page load.
- Camera and location only work on HTTPS pages. On a plain HTTP staging site they fail, which is a test environment bug, not a product bug.
- See Cross-Browser Testing for how to cover several browsers.
Checklist
App permissions checklist
0 of 14 checked
Check your understanding
Quick quiz
0/6 answered · 0 correct
1.On iOS a user tapped "Don't Allow" for the camera. What happens when the app requests the camera again?
2.On Android 13, when does the system stop showing the permission dialog for a permission?
3.A user chose "Allow Once" for location yesterday. Today the address spinner never stops. What is the most likely cause?
4.Which is the best way to show the iOS location dialog again on a test phone?
5.On Android you revoke the camera in Settings while the camera screen is open. When you return, the app crashes. Why?
6.A photo app asks for full photo library access just to set a profile picture. What should you suggest?
Key takeaways
- Permissions are asked at runtime through system dialogs. Ask in context, after a short explanation, never all at once on launch.
- Test every answer: allow, allow once, don’t allow, denied for good, approximate location, limited photos.
- iOS asks once, Android up to twice. After that only Open Settings helps; a “Turn on” button that just asks again is a bug.
- Permissions change behind the app’s back: Settings, one-time expiry, auto-reset, OS updates. The app must re-check every time and never crash when the user returns.
- Reset permissions often (reinstall, Settings,
adb shell pm,xcrun simctl privacy) and test on old and new OS versions of both platforms.
Finished this page?Nice work, this page is complete!
Mark it as done to track your progress. It's saved in this browser, no account needed.
Its review cards are now in Bites ⚡