Two kinds of permissions
- Normal (internet, vibrate) — granted automatically; just declare them in the manifest.
- Dangerous (camera, location, contacts, microphone) — you must declare them and ask the user at runtime.
Declare in the manifest
<uses-permission android:name="android.permission.CAMERA" />
Request at runtime
val requestCamera = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { granted ->
if (granted) openCamera()
else showMessage("Camera permission is needed to take photos")
}
// trigger it (e.g. on button click)
requestCamera.launch(Manifest.permission.CAMERA)
Check before using
val hasCamera = ContextCompat.checkSelfPermission(
this, Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED
Best practices
- Ask in context — request the camera permission when the user taps “Take photo”, not on app launch.
- Explain why — if it helps, show a short rationale before asking.
- Handle denial gracefully — the app should still work, just without that feature.
Common mistakes
- Declaring the permission but forgetting the runtime request (the feature silently fails).
- Requesting everything at startup — users get scared and deny.
- Crashing when a permission is denied instead of degrading gracefully.
Summary: Declare dangerous permissions in the manifest, request them at the moment they’re needed, and always handle the “denied” case.