Permissions
1. Giới thiệu
Phần tiêu đề “1. Giới thiệu”Permissions bảo vệ quyền riêng tư của user bằng cách yêu cầu app xin phép trước khi truy cập sensitive data hoặc hardware.
2. Loại Permissions
Phần tiêu đề “2. Loại Permissions”Normal Permissions
Phần tiêu đề “Normal Permissions”Tự động được cấp, chỉ cần khai báo trong Manifest:
<uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.VIBRATE" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />Dangerous Permissions
Phần tiêu đề “Dangerous Permissions”Cần runtime request:
- CAMERA
- LOCATION
- MICROPHONE
- CONTACTS
- CALENDAR
- STORAGE
- PHONE
3. Khai báo trong Manifest
Phần tiêu đề “3. Khai báo trong Manifest”<uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /><uses-permission android:name="android.permission.READ_CONTACTS" /><uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- Storage permissions --><uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /><uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /><uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />4. Request Permission - Activity
Phần tiêu đề “4. Request Permission - Activity”class MainActivity : ComponentActivity() {
private val requestPermissionLauncher = registerForActivityResult( ActivityResultContracts.RequestPermission() ) { isGranted -> if (isGranted) { openCamera() } else { showPermissionDeniedMessage() } }
private fun checkCameraPermission() { when { checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED -> { openCamera() } shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) -> { showRationaleDialog() } else -> { requestPermissionLauncher.launch(Manifest.permission.CAMERA) } } }}5. Multiple Permissions
Phần tiêu đề “5. Multiple Permissions”private val requestMultiplePermissions = registerForActivityResult( ActivityResultContracts.RequestMultiplePermissions()) { permissions -> val allGranted = permissions.entries.all { it.value }
if (allGranted) { startLocationTracking() } else { // Check which permissions were denied permissions.forEach { (permission, granted) -> if (!granted) { handleDenied(permission) } } }}
private fun requestLocationPermissions() { requestMultiplePermissions.launch( arrayOf( Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION ) )}6. Compose với Accompanist
Phần tiêu đề “6. Compose với Accompanist”implementation("com.google.accompanist:accompanist-permissions:0.34.0")Single Permission
Phần tiêu đề “Single Permission”@OptIn(ExperimentalPermissionsApi::class)@Composablefun CameraScreen() { val cameraPermissionState = rememberPermissionState(Manifest.permission.CAMERA)
when { cameraPermissionState.status.isGranted -> { CameraPreview() } cameraPermissionState.status.shouldShowRationale -> { Column { Text("Camera permission is required for this feature") Button(onClick = { cameraPermissionState.launchPermissionRequest() }) { Text("Grant Permission") } } } else -> { Button(onClick = { cameraPermissionState.launchPermissionRequest() }) { Text("Request Camera Permission") } } }}Multiple Permissions
Phần tiêu đề “Multiple Permissions”@OptIn(ExperimentalPermissionsApi::class)@Composablefun LocationScreen() { val locationPermissions = rememberMultiplePermissionsState( listOf( Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION ) )
when { locationPermissions.allPermissionsGranted -> { LocationContent() } locationPermissions.shouldShowRationale -> { RationaleDialog(onConfirm = { locationPermissions.launchMultiplePermissionRequest() }) } else -> { Button(onClick = { locationPermissions.launchMultiplePermissionRequest() }) { Text("Request Location Permissions") } } }}7. Xử lý “Don’t ask again”
Phần tiêu đề “7. Xử lý “Don’t ask again””if (!shouldShowRequestPermissionRationale(permission) && checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { // User selected "Don't ask again" showSettingsDialog()}
private fun showSettingsDialog() { AlertDialog.Builder(this) .setTitle("Permission Required") .setMessage("Please enable permission in Settings") .setPositiveButton("Settings") { _, _ -> val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) intent.data = Uri.fromParts("package", packageName, null) startActivity(intent) } .setNegativeButton("Cancel", null) .show()}8. Permission Groups (Android 14+)
Phần tiêu đề “8. Permission Groups (Android 14+)”// Photo picker - không cần permissionval pickMedia = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri -> uri?.let { handleSelectedImage(it) }}
pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))9. Best Practices
Phần tiêu đề “9. Best Practices”// ✅ Good: Request khi cầnfun onCameraButtonClick() { requestCameraPermission()}
// ❌ Bad: Request khi app startoverride fun onCreate() { requestAllPermissions() // Don't do this}
// ✅ Good: Explain why@Composablefun PermissionRationale() { Column { Text("We need camera access to take photos for your profile") Button(onClick = { requestPermission() }) { Text("Continue") } }}
// ✅ Good: Graceful degradationif (hasLocationPermission) { showNearbyPlaces()} else { showAllPlaces() // Fallback without location}10. Special Permissions
Phần tiêu đề “10. Special Permissions”// Overlay permissionif (!Settings.canDrawOverlays(this)) { val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION) startActivity(intent)}
// Notification permission (Android 13+)if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)}📝 Tóm tắt
Phần tiêu đề “📝 Tóm tắt”| Type | Request |
|---|---|
| Normal | Manifest only |
| Dangerous | Runtime request |
| Special | Intent to Settings |
| Best Practice | Description |
|---|---|
| Request in context | Khi user cần feature |
| Explain why | Show rationale |
| Handle denial | Graceful degradation |
| Don’t ask again | Link to Settings |