Permission Handler adalah komponen aplikasi Android yang bertanggung jawab untuk memeriksa, meminta, dan memproses hasil izin runtime. Menurut Android Developer Guide, 2024, handler izin memusatkan logika checkSelfPermission, requestPermissions, dan shouldShowRequestPermissionRationale dalam satu kelas atau ViewModel. Ini menyederhanakan pemeliharaan kode dan meningkatkan pengujian.
Poin Utama
Permission Handler — adalah pola arsitektur untuk manajemen terpusat izin runtime Android. Alih-alih panggilan ContextCompat.checkSelfPermission dan ActivityCompat.requestPermissions yang tersebar di seluruh kode aplikasi, seluruh logika permintaan dan pemrosesan hasil terkonsentrasi dalam satu kelas. Ini mengurangi duplikasi, menyederhanakan pemeliharaan, dan membuat kode lebih dapat diprediksi.
Kebutuhan akan Permission Handler muncul dengan diperkenalkannya izin runtime di Android 6.0. Sebelumnya, semua izin diminta saat instalasi, dan kode aplikasi dapat menggunakan API apa pun tanpa pemeriksaan. Setelah beralih ke model runtime, setiap penggunaan izin berbahaya memerlukan pemeriksaan tiga langkah: checkSelfPermission, requestPermissions, onRequestPermissionsResult. Penyebaran logika ini di seluruh Activity dan Fragment menyebabkan duplikasi inline dan kesalahan. Menurut data Google I/O 2019, sentralisasi pemrosesan izin mengurangi jumlah bug terkait Permission Denial rata-rata sebesar 60 persen.
Permission Handler yang baik menyediakan antarmuka yang bersih untuk kode pemanggil. Activity atau Fragment tidak perlu mengetahui detail permintaan — mereka memanggil metode seperti requestCamera(callback), dan handler sendiri yang mengelola pemeriksaan status, menampilkan rationale, memanggil dialog sistem, dan mengirimkan hasil ke callback. Ini mengimplementasikan prinsip tanggung jawab tunggal dan memisahkan logika bisnis dari kode platform izin.
Permission Handler menjadi diperlukan ketika aplikasi menggunakan 3 atau lebih izin berbahaya. Untuk aplikasi sederhana dengan satu izin (misalnya, kamera untuk pemindai kode QR), panggilan langsung sudah cukup. Tetapi untuk aplikasi seluler tipikal dengan kamera, geolokasi, notifikasi, dan penyimpanan — handler terpusat wajib untuk pemeliharaan.
Permission Handler tipikal terdiri dari tiga tingkat: antarmuka-kontrak, implementasi dengan ActivityResultLauncher, dan lapisan untuk ViewModel. Antarmuka mendefinisikan metode permintaan untuk setiap izin — requestCamera, requestLocation, requestStorage. Implementasi menghubungkan metode ini dengan kontrak ActivityResultContracts.RequestPermission yang sesuai.
Komponen kunci arsitektur:
Arsitektur ini memungkinkan penggantian implementasi dengan mudah dalam pengujian: alih-alih ActivityResultLauncher nyata, digunakan mock yang mengembalikan hasil yang telah ditentukan tanpa interaksi dengan sistem. Ini sangat penting untuk pengujian unit logika UI, di mana meluncurkan Activity untuk dialog izin tidak mungkin dilakukan.
Permission Handler harus mempertimbangkan siklus hidup Activity dan Fragment. Launcher didaftarkan di ActivityResultRegistry, yang secara otomatis menyimpan dan memulihkan status saat rotasi layar dan pembuatan ulang Activity. Handler tidak boleh menyimpan referensi langsung ke Activity atau Fragment — sebagai gantinya, gunakan WeakReference atau berikan registry melalui konstruktor. Ini mencegah kebocoran memori dan crash saat perubahan konfigurasi.
Implementasi dasar Permission Handler dibangun di atas ActivityResultContracts.RequestPermission. Handler menerima ActivityResultRegistry dari ComponentActivity atau Fragment dan mendaftarkan launcher untuk setiap izin. Setiap launcher menerima lambda-callback yang dipanggil setelah respons pengguna.
sealed class PermissionResult {
object GRANTED : PermissionResult()
data class DENIED(
val shouldShowRationale: Boolean
) : PermissionResult()
}
interface PermissionHandler {
fun requestCamera(
callback: (PermissionResult) -> Unit
)
fun requestLocation(
callback: (PermissionResult) -> Unit
)
fun isPermissionGranted(
permission: String
): Boolean
}
class AndroidPermissionHandler(
private val registry: ActivityResultRegistry,
private val context: Context
) : PermissionHandler {
private var cameraLauncher: ActivityResultLauncher<String>? = null
fun initialize() {
cameraLauncher = registry.register(
"camera_permission",
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
pendingCameraCallback?.invoke(
PermissionResult.GRANTED
)
} else {
val rationale = ActivityCompat.shouldShowRequestPermissionRationale(
context as Activity,
Manifest.permission.CAMERA
)
pendingCameraCallback?.invoke(
PermissionResult.DENIED(rationale)
)
}
}
}
private var pendingCameraCallback:
((PermissionResult) -> Unit)? = null
override fun requestCamera(
callback: (PermissionResult) -> Unit
) {
if (isPermissionGranted(
Manifest.permission.CAMERA
)) {
callback.invoke(PermissionResult.GRANTED)
return
}
pendingCameraCallback = callback
cameraLauncher?.launch(
Manifest.permission.CAMERA
)
}
override fun isPermissionGranted(
permission: String
): Boolean {
return ContextCompat.checkSelfPermission(
context, permission
) == PackageManager.PERMISSION_GRANTED
}
}
Handler diinisialisasi di onCreate Activity melalui registerForActivityResult, yang menyediakan akses ke ActivityResultRegistry. Setelah inisialisasi, handler siap memproses permintaan selama siklus hidup Activity. Penting untuk memanggil initialize sebelum permintaan pertama, jika tidak launcher tidak akan terdaftar.
Integrasi Permission Handler dengan ViewModel adalah pendekatan paling maju. ViewModel mengelola status permintaan, dan Handler hanya melakukan panggilan platform. ViewModel berisi StateFlow<PermissionUiState>, di mana UiState menjelaskan izin mana yang diminta dan hasil apa yang diperoleh. Activity berlangganan StateFlow ini dan mendelegasikan permintaan ke Handler.
class PermissionsViewModel : ViewModel() {
private val _uiState =
MutableStateFlow<PermissionUiState>(
PermissionUiState.Idle
)
val uiState: StateFlow<PermissionUiState> = _uiState.asStateFlow()
fun onCameraRequested() {
_uiState.value = PermissionUiState.RequestingCamera
}
fun onPermissionResult(
permission: String,
result: PermissionResult
) {
when (result) {
PermissionResult.GRANTED -> {
_uiState.value = PermissionUiState.Granted(permission)
}
is PermissionResult.DENIED -> {
_uiState.value = PermissionUiState.Denied(
permission,
result.shouldShowRationale
)
}
}
}
}
sealed class PermissionUiState {
object Idle : PermissionUiState()
object RequestingCamera : PermissionUiState()
data class Granted(val permission: String) : PermissionUiState()
data class Denied(
val permission: String,
val shouldShowRationale: Boolean
) : PermissionUiState()
}
Dalam model ini, Activity memeriksa isPermissionGranted melalui Handler saat startup, dan ViewModel hanya mengelola status. Jika izin tidak diberikan — Activity berlangganan uiState, memanggil requestCamera dari Handler, dan mengirimkan hasil kembali ke ViewModel melalui onPermissionResult. Pemisahan kode platform dan logika bisnis memungkinkan pengujian ViewModel tanpa ketergantungan Android.
Pengujian unit Permission Handler dimungkinkan berkat antarmuka PermissionHandler. Dalam pengujian, dibuat FakePermissionHandler yang mensimulasikan berbagai skenario: izin diberikan, ditolak, Never Ask Again. Setiap skenario diuji secara independen. Ini sangat penting untuk menguji logika UI yang harus bereaksi dengan benar terhadap ketiga hasil.
class FakePermissionHandler : PermissionHandler {
var cameraResult: PermissionResult =
PermissionResult.GRANTED
var grantedPermissions: Set<String> =
setOf(Manifest.permission.CAMERA)
override fun requestCamera(
callback: (PermissionResult) -> Unit
) {
callback.invoke(cameraResult)
}
override fun isPermissionGranted(
permission: String
): Boolean {
return permission in grantedPermissions
}
}
Implementasi Fake memungkinkan pengujian ViewModel tanpa emulator. Cukup atur cameraResult ke nilai yang diinginkan dan periksa apakah ViewModel memperbarui UiState dengan benar. Pengujian integrasi memeriksa PermissionHandler nyata dengan ActivityScenario, tetapi biasanya ada 2-3 pengujian semacam itu untuk seluruh aplikasi — skenario lainnya dicakup oleh pengujian unit dengan fake.
Kesalahan umum saat bekerja dengan Permission Handler meliputi: tidak adanya pemeriksaan checkSelfPermission sebelum setiap panggilan API, mengabaikan shouldShowRequestPermissionRationale, memanggil ulang requestPermissions saat Never Ask Again, dan menyimpan launcher tanpa mempertimbangkan siklus hidup Activity. Mari kita lihat setiap masalah dan solusinya.
Kesalahan paling umum — memanggil API tanpa memeriksa status izin. Pengembang berasumsi bahwa jika izin pernah diberikan, itu akan tetap selamanya. Namun, pengguna dapat mencabutnya kapan saja melalui pengaturan. Permission Handler harus selalu memanggil isPermissionGranted sebelum melakukan operasi sensitif. Kesalahan umum kedua — mengabaikan shouldShowRequestPermissionRationale dan permintaan ulang yang menyebabkan penolakan segera tanpa dialog saat Never Ask Again.
Praktik terbaik meliputi: membuat satu instance Handler untuk seluruh siklus hidup Activity, menggunakan SharedFlow untuk mengirimkan hasil ke ViewModel, mencatat semua permintaan dan penolakan untuk analitik, serta menampilkan dialog rationale kustom sebelum dialog sistem saat penolakan pertama. Mengikuti aturan ini menjamin kerja yang stabil dengan izin di semua versi Android.
Pertanyaan yang Sering Diajukan
Permission Handler — komponen untuk manajemen terpusat izin runtime, mengenkapsulasi checkSelfPermission, requestPermissions, dan shouldShowRequestPermissionRationale. Ini menyederhanakan pemeliharaan kode dan meningkatkan pengujian.
Direkomendasikan ActivityResultContracts.RequestPermission dari pustaka androidx.activity. Ini menggantikan onRequestPermissionsResult yang sudah usang dan menyediakan API callback bersih dengan hasil Boolean.
Untuk satu izin, Handler tidak wajib — Anda dapat menggunakan panggilan langsung RequestPermission launcher di Activity. Handler menjadi diperlukan dengan 3 izin atau lebih untuk menghindari duplikasi kode.
Buat antarmuka PermissionHandler dan implementasi fake-nya untuk pengujian unit. Fake mengembalikan hasil yang telah ditentukan tanpa panggilan sistem. Ini memungkinkan pengujian ViewModel dan logika UI tanpa emulator.
Setelah penolakan, periksa shouldShowRequestPermissionRationale. Jika metode mengembalikan false — mode Never Ask Again aktif. Handler harus mengembalikan PermissionResult.DENIED(false), dan UI harus menampilkan tombol untuk masuk ke Pengaturan.
Kesimpulan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga