On this page
A camera app asking for contacts, a flashlight asking for location: users notice, and they uninstall. Google Play also restricts sensitive permissions and requires accurate data disclosures. Good permission design is both better UX and better compliance.
Principles
- Avoid the permission if a privacy-preserving API exists (Photo Picker, document picker, Credential Manager).
- Ask in context, when the user triggers the feature, not at app launch.
- Request the minimum: approximate instead of precise location, and foreground instead of background.
- Degrade gracefully when denied: the rest of the app must keep working.
Requesting permissions in Compose
@Composable
fun CameraFeatureButton(onCameraReady: () -> Unit) {
val context = LocalContext.current
var showRationale by remember { mutableStateOf(false) }
var showSettingsHint by remember { mutableStateOf(false) }
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
if (granted) onCameraReady()
else {
val activity = context.findActivity()
// If the system won't show a rationale after a denial, the user chose "don't ask again".
showSettingsHint = activity != null &&
!ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.CAMERA)
}
}
Button(onClick = {
when {
ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) ==
PackageManager.PERMISSION_GRANTED -> onCameraReady()
else -> showRationale = true
}
}) { Text("Scan receipt") }
if (showRationale) AlertDialog(
onDismissRequest = { showRationale = false },
title = { Text("Camera access") },
text = { Text("We use the camera only to scan receipts. Photos stay on your device unless you choose to upload them.") },
confirmButton = { TextButton(onClick = { showRationale = false; launcher.launch(Manifest.permission.CAMERA) }) { Text("Continue") } },
dismissButton = { TextButton(onClick = { showRationale = false }) { Text("Not now") } },
)
if (showSettingsHint) TextButton(onClick = {
context.startActivity(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", context.packageName, null)))
}) { Text("Enable camera in Settings") }
}
fun Context.findActivity(): Activity? = when (this) {
is Activity -> this
is ContextWrapper -> baseContext.findActivity()
else -> null
}Permission-free alternatives
| Need | Instead of | Use |
|---|---|---|
| Pick photos/videos | Storage or media read permissions | Photo Picker (PickVisualMedia) |
| Open a document | Broad storage access | Storage Access Framework (OpenDocument) |
| Take one photo | CAMERA in your own camera UI (if not needed) | Camera intent (TakePicture) |
| Rough location (weather, city) | ACCESS_FINE_LOCATION | ACCESS_COARSE_LOCATION (approximate) |
| Sign-in with saved credentials | Reading accounts | Credential Manager |
val pickImage = rememberLauncherForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
uri?.let(onImagePicked)
}
// pickImage.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))Sensitive and restricted permissions
Background location, SMS and call log, all-files access, exact alarms, accessibility services and others are restricted by Google Play policy and require declarations or justifications. Use them only when they're core to your app's functionality, and check current Play policy before building features around them.
Disclosure and Data safety
- Your Play Console Data safety form must accurately describe data collection and sharing, including by SDKs.
- Provide a privacy policy that matches actual behaviour.
- Use prominent in-app disclosure before collecting sensitive data where Play policy requires it.
- Audit third-party SDKs: their collection counts as yours.
Examples
Profile photo
The Photo Picker, with no permission at all.
Weather app
Approximate location, requested when the user taps "Use my location", with manual city entry as a fallback.
Delivery notifications
POST_NOTIFICATIONS requested after the first order, not on first launch.
Frequently asked questions
Can I request several permissions at once?
You can, with RequestMultiplePermissions, but users trust focused, contextual requests more. Bundle only those needed for one feature.
What happens if the user selects "Only this time"?
The permission is granted temporarily and revoked later. Always re-check before use.
Do unused apps lose permissions?
Yes. Android can auto-reset permissions for apps that haven't been used for a while, so always check at runtime.
Conclusion
Request fewer, smaller, contextual permissions, explain why before asking, prefer privacy-preserving APIs like the Photo Picker, handle denial gracefully, and keep your Data safety disclosures accurate.
Next step: add strong, convenient authentication with Biometric Authentication on Android.
Official references
๐ฑ Apps built by Yunok Tech
Real Android apps on Google Play, free to download.
NotiVaultNotification history: recover dismissed notificationsGet it โธ
Walzi4K wallpapers for lock and home screenGet it โธ
Ready to build real Android applications?
Security is easiest to get right when it is part of how you build from the first screen. Strengthen the Android fundamentals that secure, privacy-respecting apps are built on.
Move beyond theory and strengthen your Android development skills with Yunoktech's Android course. Learn core concepts, practical implementation, modern Android development techniques, and the reasoning behind building maintainable applications.
Explore the Android course and take your next step as an Android developer.