Permission Handler Android tətbiqinin runtime icazələrini yoxlamaq, sorğulamaq və nəticələrini emal etmək üçün cavabdeh olan komponentidir. Android Developer Guide, 2024-ə görə, icazə işləyicisi checkSelfPermission, requestPermissions və shouldShowRequestPermissionRationale məntiqini vahid sinifdə və ya ViewModel-də mərkəzləşdirir. Bu kodun saxlanmasını asanlaşdırır və testləri yaxşılaşdırır.
Əsas məqamlar
Permission Handler — Android runtime icazələrinin mərkəzləşdirilmiş idarə edilməsi üçün memarlıq nümunəsidir. Tətbiq kodu boyunca səpələnmiş ContextCompat.checkSelfPermission və ActivityCompat.requestPermissions çağırışları əvəzinə, bütün sorğu və nəticə emalı məntiqi bir sinifdə cəmləşir. Bu təkrarlanmanı azaldır, saxlanmanı asanlaşdırır və kodu daha proqnozlaşdırılan edir.
Permission Handler ehtiyacı Android 6.0-da runtime icazələrinin tətbiqi ilə yarandı. Bundan əvvəl bütün icazələr quraşdırma zamanı sorğulanırdı və tətbiq kodu heç bir yoxlama olmadan istənilən API-dən istifadə edə bilirdi. Runtime modelinə keçiddən sonra hər bir təhlükəli icazənin istifadəsi üç mərhələli yoxlama tələb edir: checkSelfPermission, requestPermissions, onRequestPermissionsResult. Bu məntiqin Activity və Fragment arasında yayılması inline təkrarlanmaya və səhvlərə gətirib çıxarır. Google I/O 2019 məlumatlarına görə, icazələrin işlənməsinin mərkəzləşdirilməsi Permission Denial ilə bağlı səhvlərin sayını orta hesabla 60 faiz azaldır.
Yaxşı Permission Handler çağıran kod üçün təmiz interfeys təmin edir. Activity və ya Fragment sorğunun təfərrüatlarını bilməməlidir — onlar requestCamera(callback) tipli metodu çağırır, handler isə status yoxlaması, rationale göstərilməsi, sistem dialoqunun çağırılması və nəticənin callback-ə ötürülməsini özü idarə edir. Bu, vahid məsuliyyət prinsipini həyata keçirir və biznes məntiqini icazələrin platforma kodundan ayırır.
Permission Handler tətbiq 3 və ya daha çox təhlükəli icazədən istifadə etdikdə zəruri olur. Bir icazəli sadə tətbiqlər üçün (məsələn, QR kod skaneri üçün kamera) birbaşa çağırışla keçinə bilərsiniz. Lakin kamera, geolokasiya, bildirişlər və yaddaş olan tipik mobil tətbiq üçün mərkəzləşdirilmiş handler saxlanma üçün məcburidir.
Tipik Permission Handler üç səviyyədən ibarətdir: interfeys-kontrakt, ActivityResultLauncher ilə tətbiq və ViewModel üçün təbəqə. İnterfeys hər bir icazə üçün sorğu metodlarını müəyyən edir — requestCamera, requestLocation, requestStorage. Tətbiq bu metodları müvafiq ActivityResultContracts.RequestPermission kontraktları ilə əlaqələndirir.
Arxitekturanın əsas komponentləri:
Belə arxitektura testlərdə tətbiqi asanlıqla əvəz etməyə imkan verir: real ActivityResultLauncher əvəzinə sistemlə qarşılıqlı əlaqə olmadan əvvəlcədən müəyyən edilmiş nəticəni qaytaran mock istifadə olunur. Bu, icazə dialoqu üçün Activity-nin işə salınmasının mümkün olmadığı UI məntiqinin vahid testləri üçün kritik əhəmiyyət kəsb edir.
Permission Handler Activity və Fragment-in həyat dövrünü nəzərə almalıdır. Launcherlər ActivityResultRegistry-də qeydiyyatdan keçirilir ki, bu da ekranın döndərilməsi və Activity-nin yenidən yaradılması zamanı vəziyyəti avtomatik saxlayır və bərpa edir. Handler Activity və ya Fragment-ə birbaşa istinadlar saxlamamalıdır — bunun əvəzinə WeakReference istifadə edin və ya registry-ni konstruktor vasitəsilə ötürün. Bu, yaddaş sızmalarının və konfiqurasiya dəyişiklikləri zamanı crash-lərin qarşısını alır.
Əsas tətbiq Permission Handler ActivityResultContracts.RequestPermission üzərində qurulur. Handler ComponentActivity və ya Fragment-dən ActivityResultRegistry alır və hər bir icazə üçün launcher-ləri qeydiyyatdan keçirir. Hər bir launcher istifadəçinin cavabından sonra çağırılan lambda callback qəbul edir.
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 Activity-nin onCreate metodunda registerForActivityResult vasitəsilə inisiallaşdırılır ki, bu da ActivityResultRegistry-ə girişi təmin edir. İnisiallaşdırmadan sonra handler Activity-nin bütün həyat dövrü ərzində sorğuları emal etməyə hazırdır. İlk sorğudan əvvəl initialize-i çağırmaq vacibdir, əks halda launcher qeydiyyatdan keçməyəcək.
Permission Handler inteqrasiyası ViewModel ilə ən qabaqcıl yanaşmadır. ViewModel sorğuların vəziyyətini idarə edir, Handler isə yalnız platforma çağırışlarını yerinə yetirir. ViewModel-də StateFlow<PermissionUiState> var, burada UiState hansı icazənin sorğulandığını və hansı nəticənin alındığını təsvir edir. Activity bu StateFlow-a abunə olur və sorğunu Handler-ə həvalə edir.
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()
}
Bu modeldə Activity başlanğıcda Handler vasitəsilə isPermissionGranted-i yoxlayır, ViewModel isə yalnız vəziyyəti idarə edir. İcazə verilməyibsə — Activity uiState-ə abunə olur, Handler-dən requestCamera-nı çağırır və nəticəni onPermissionResult vasitəsilə ViewModel-ə qaytarır. Platforma kodunun və biznes məntiqinin ayrılması ViewModel-i Android asılılıqları olmadan test etməyə imkan verir.
Vahid testləri PermissionHandler interfeysi sayəsində mümkündür. Testlərdə müxtəlif ssenariləri simulyasiya edən FakePermissionHandler yaradılır: icazə verilib, rədd edilib, Never Ask Again. Hər bir ssenari müstəqil şəkildə yoxlanılır. Bu, hər üç nəticəyə düzgün reaksiya verməli olan UI məntiqinin test edilməsi üçün xüsusilə vacibdir.
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
}
}
Fake tətbiq ViewModel-i emulyator olmadan test etməyə imkan verir. Sadəcə cameraResult-u lazımi dəyərə təyin etmək və ViewModel-in UiState-i düzgün yenilədiyini yoxlamaq kifayətdir. İnteqrasiya testləri real PermissionHandler-i ActivityScenario ilə yoxlayır, lakin adətən bütün tətbiq üçün 2-3 belə test olur — qalan ssenarilər fake-lərlə vahid testləri ilə əhatə olunur.
Ümumi səhvlər Permission Handler ilə işləyərkən: hər API çağırışından əvvəl checkSelfPermission yoxlamasının olmaması, shouldShowRequestPermissionRationale-ın nəzərə alınmaması, Never Ask Again vəziyyətində requestPermissions-in təkrar çağırılması və launcher-lərin Activity həyat dövrü nəzərə alınmadan saxlanması. Hər bir problemi və həllini nəzərdən keçirək.
Ən çox yayılmış səhv — icazə statusunu yoxlamadan API çağırışı etməkdir. Tərtibatçılar güman edirlər ki, icazə bir dəfə verilibsə, əbədi qalacaq. Lakin istifadəçi onu istənilən vaxt parametrlərdən geri ala bilər. Permission Handler həssas əməliyyatı yerinə yetirməzdən əvvəl həmişə isPermissionGranted çağırmalıdır. İkinci məşhur səhv — shouldShowRequestPermissionRationale-ın nəzərə alınmaması və Never Ask Again zamanı dialoq olmadan dərhal rədd edilməyə səbəb olan təkrar sorğudur.
Ən yaxşı təcrübələrə daxildir: Activity-nin bütün həyat dövrü üçün bir Handler nümunəsinin yaradılması, nəticələri ViewModel-ə ötürmək üçün SharedFlow istifadəsi, analitika üçün bütün sorğu və rəddlərin qeydə alınması, həmçinin ilk rəddlə sistem dialoqundan əvvəl xüsusi rationale dialoqunun göstərilməsi. Bu qaydalara riayət etmək Android-in bütün versiyalarında icazələrlə sabit işi təmin edir.
Tez-tez verilən suallar
Permission Handler — checkSelfPermission, requestPermissions və shouldShowRequestPermissionRationale-i inkapsulyasiya edən, runtime icazələrinin mərkəzləşdirilmiş idarə edilməsi üçün komponentdir. Kodun saxlanmasını asanlaşdırır və testləri yaxşılaşdırır.
androidx.activity kitabxanasından ActivityResultContracts.RequestPermission tövsiyə olunur. O, köhnəlmiş onRequestPermissionsResult-u əvəz edir və Boolean nəticəsi ilə təmiz callback API təmin edir.
Bir icazə üçün Handler məcburi deyil — Activity-də birbaşa RequestPermission launcher çağırışından istifadə edə bilərsiniz. Handler 3 və daha çox icazə olduqda kod təkrarlanmasının qarşısını almaq üçün zəruri olur.
PermissionHandler interfeysi və onun vahid testlər üçün fake tətbiqini yaradın. Fake sistem çağırışları olmadan əvvəlcədən müəyyən edilmiş nəticələri qaytarır. Bu, ViewModel və UI məntiqini emulyator olmadan test etməyə imkan verir.
Rədd edildikdən sonra shouldShowRequestPermissionRationale-ı yoxlayın. Metod false qaytarıbsa — Never Ask Again rejimi aktivdir. Handler PermissionResult.DENIED(false) qaytarmalı, UI isə Parametrlərə keçid düyməsini göstərməlidir.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun