Permission Handler في Android: كيف يعمل، معالجة الطلبات والتنفيذ

المؤلف: IT Sectr نُشر: 2026-05-20 وقت القراءة: 8 دق

Permission Handler هو مكون من مكونات تطبيقات Android مسؤول عن التحقق من أذونات وقت التشغيل وطلبها ومعالجة نتائجها. وفقاً لـ Android Developer Guide, 2024، يقوم معالج الأذونات بمركزة منطق checkSelfPermission وrequestPermissions وshouldShowRequestPermissionRationale في فئة واحدة أو ViewModel. وهذا يبسط صيانة الكود ويحسن الاختبار.

الرئيسية

  • Permission Handler — مكون متخصص للإدارة المركزية لأذونات وقت التشغيل في Android.
  • يغلف منطق checkSelfPermission وrequestPermissions وshouldShowRequestPermissionRationale.
  • التنفيذات الحديثة تستند إلى ActivityResultContracts من androidx.activity.
  • يبسط اختبارات الوحدة بفضل عكس التبعيات وعزل كود المنصة.
  • أفضل الممارسات تتضمن معالجاً واحداً لكل Activity وإعادة الاستخدام عبر حاوية DI.

ما هو Permission Handler في Android

Permission Handler هو نمط معماري للإدارة المركزية لأذونات وقت التشغيل في Android. بدلاً من الاستدعاءات المتناثرة لـ ContextCompat.checkSelfPermission وActivityCompat.requestPermissions في جميع أنحاء كود التطبيق، يتركز منطق الطلبات ومعالجة النتائج بالكامل في فئة واحدة. وهذا يقلل التكرار ويبسط الصيانة ويجعل الكود أكثر قابلية للتنبؤ.

نشأت الحاجة إلى Permission Handler مع إدخال أذونات وقت التشغيل في Android 6.0. قبل ذلك، كانت جميع الأذونات تُطلب عند تثبيت التطبيق، وكان كود التطبيق يستخدم أي واجهات برمجة بدون تحقق. بعد الانتقال إلى نموذج وقت التشغيل، يتطلب كل استخدام لإذن خطير تحققاً من ثلاث خطوات: checkSelfPermission وrequestPermissions وonRequestPermissionsResult. توزيع هذا المنطق عبر Activity وFragment يؤدي إلى تكرار مضمن وأخطاء. وفقاً لـ Google I/O 2019، فإن مركزة معالجة الأذونات تقلل عدد الأخطاء المتعلقة بـ Permission Denial بمتوسط 60 بالمائة.

يوفر Permission Handler الجيد واجهة نظيفة للكود المستدعي. لا ينبغي أن تعرف Activity أو Fragment تفاصيل الطلب — فهي تستدعي طريقة مثل requestCamera(callback)، ويدير المعالج نفسه التحقق من الحالة وعرض المبرر واستدعاء حوار النظام ونقل النتيجة إلى callback. وهذا يحقق مبدأ المسؤولية الواحدة ويفصل منطق الأعمال عن كود أذونات المنصة.

متى تحتاج Permission Handler

يصبح Permission Handler ضرورياً عندما يستخدم التطبيق 3 أذونات خطيرة أو أكثر. للتطبيقات البسيطة بإذن واحد (مثل الكاميرا لماسح QR)، قد يكون الاستدعاء المباشر كافياً. لكن لتطبيق جوال نموذجي بكاميرا وموقع جغرافي وإشعارات وتخزين — فإن معالجاً مركزياً ضروري للصيانة.

بنية Permission Handler

يتكون Permission Handler النموذجي من ثلاث طبقات: عقد واجهة، وتنفيذ مع ActivityResultLauncher، وطبقة ViewModel. تحدد الواجهة طرق الطلب لكل إذن — requestCamera وrequestLocation وrequestStorage. يربط التنفيذ هذه الطرق بعقود ActivityResultContracts.RequestPermission المقابلة.

المكونات الرئيسية للبنية:

  • PermissionHandlerContract — واجهة بطرق لكل إذن
  • PermissionHandlerImpl — تنفيذ يتصل بـ ActivityResultRegistry
  • PermissionResult — فئة مغلقة بحالات GRANTED وDENED وNEVER_ASK_AGAIN
  • RationaleHandler — مكون لعرض الشروحات قبل الطلب

تسمح هذه البنية بتبديل التنفيذات بسهولة في الاختبارات: بدلاً من ActivityResultLauncher حقيقي، يُستخدم mock يعيد نتيجة محددة مسبقاً دون تفاعل مع النظام. هذا أمر بالغ الأهمية لاختبار وحدة منطق واجهة المستخدم، حيث أن تشغيل Activity لحوار إذن أمر مستحيل.

إدارة دورة الحياة

يجب أن يراعي Permission Handler دورة حياة Activity وFragment. تُسجل المشغلات في ActivityResultRegistry، الذي يحفظ ويستعيد الحالة تلقائياً عند تدوير الشاشة وإعادة إنشاء Activity. يجب ألا يخزن المعالج مراجع مباشرة لـ Activity أو Fragment — بدلاً من ذلك، استخدم WeakReference أو مرر registry عبر المنشئ. وهذا يمنع تسرب الذاكرة والتعطل أثناء تغييرات التكوين.

تنفيذ Permission Handler في Kotlin

يُبنى التنفيذ الأساسي لـ Permission Handler على ActivityResultContracts.RequestPermission. يتلقى المعالج ActivityResultRegistry من ComponentActivity أو Fragment ويسجل مشغلات لكل إذن. يقبل كل مشغل دالة callback تُستدعى بعد استجابة المستخدم.

kotlin
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
    }
}

التهيئة في Activity

تتم تهيئة المعالج في onCreate الخاص بـ Activity عبر registerForActivityResult، الذي يوفر الوصول إلى ActivityResultRegistry. بعد التهيئة، يصبح المعالج جاهزاً لمعالجة الطلبات طوال دورة حياة Activity. من المهم استدعاء initialize قبل الطلب الأول، وإلا فلن يتم تسجيل المشغل.

Permission Handler مع ViewModel

دمج Permission Handler مع ViewModel هو النهج الأكثر تقدماً. يدير ViewModel حالة الطلبات، بينما يقوم Handler فقط باستدعاءات المنصة. يحتوي ViewModel على StateFlow<PermissionUiState>، حيث يصف UiState أي إذن يُطلب وأي نتيجة تم استلامها. تشترك Activity في StateFlow هذا وتفوض الطلب إلى Handler.

kotlin
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()
}

في هذا النموذج، تتحقق Activity من isPermissionGranted عبر Handler عند بدء التشغيل، بينما يدير ViewModel الحالة فقط. إذا لم يكن الإذن ممنوحاً — تشترك Activity في uiState، وتستدعي requestCamera من Handler وتمرر النتيجة مرة أخرى إلى ViewModel عبر onPermissionResult. فصل كود المنصة عن منطق الأعمال يسمح باختبار ViewModel دون اعتماديات Android.

اختبار Permission Handler

اختبار الوحدة لـ Permission Handler ممكن بفضل واجهة PermissionHandler. في الاختبارات، يُنشأ FakePermissionHandler يحاكي سيناريوهات مختلفة: الإذن ممنوح، مرفوض، Never Ask Again. يتم اختبار كل سيناريو بشكل مستقل. هذا مهم بشكل خاص لاختبار منطق واجهة المستخدم الذي يجب أن يستجيب بشكل صحيح لجميع النتائج الثلاث.

kotlin
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
    }
}

يتيح التنفيذ الوهمي اختبار ViewModel بدون محاكي. ما عليك سوى تعيين cameraResult إلى القيمة المطلوبة والتحقق من أن ViewModel يحدّث UiState بشكل صحيح. تختبر اختبارات التكامل Permission Handler الحقيقي مع ActivityScenario، لكن عادةً ما يكون هناك 2-3 اختبارات فقط لكل تطبيق — أما السيناريوهات المتبقية فتغطى باختبارات الوحدة باستخدام fakes.

الأنماط الشائعة والأخطاء

تشمل الأخطاء النموذجية عند العمل مع Permission Handler: عدم التحقق من checkSelfPermission قبل كل استدعاء API، وتجاهل shouldShowRequestPermissionRationale، وإعادة استدعاء requestPermissions بعد Never Ask Again، وتخزين المشغلات دون مراعاة دورة حياة Activity. دعنا نفحص كل مشكلة وحلها.

الخطأ الأكثر شيوعاً هو استدعاء API دون التحقق من حالة الإذن. يفترض المطورون أنه إذا مُنح الإذن مرة واحدة، فسيظل إلى الأبد. ومع ذلك، يمكن للمستخدم إلغاؤه عبر الإعدادات في أي وقت. يجب أن يستدعي Permission Handler دائماً isPermissionGranted قبل تنفيذ عملية حساسة. الخطأ الثاني الشائع هو تجاهل shouldShowRequestPermissionRationale وتكرار الطلب، مما يؤدي إلى رفض فوري دون حوار في وضع Never Ask Again.

تشمل أفضل الممارسات: إنشاء نسخة واحدة من Handler لدورة حياة Activity بأكملها، واستخدام SharedFlow لنقل النتائج إلى ViewModel، وتسجيل جميع الطلبات والرفض للتحليلات، وعرض حوار مبرر مخصص قبل حوار النظام عند أول رفض. اتباع هذه القواعد يضمن معالجة مستقرة للأذونات في جميع إصدارات Android.

الأسئلة الشائعة

ما هو Permission Handler في Android؟

Permission Handler هو مكون للإدارة المركزية لأذونات وقت التشغيل، يغلف checkSelfPermission وrequestPermissions وshouldShowRequestPermissionRationale. يبسط صيانة الكود ويحسن الاختبار.

ما API لاستخدامها لـ Handler في 2024؟

يُوصى باستخدام ActivityResultContracts.RequestPermission من مكتبة androidx.activity. يحل محل onRequestPermissionsResult القديم ويوفر واجهة callback نظيفة بنتيجة Boolean.

هل يحتاج Handler لإذن واحد؟

لإذن واحد، Handler غير إلزامي — يمكن استخدام استدعاء مباشر لمشغل RequestPermission في Activity. يصبح Handler ضرورياً مع 3 أذونات أو أكثر لتجنب تكرار الكود.

كيفية اختبار Permission Handler؟

أنشئ واجهة PermissionHandler وتنفيذها الوهمي لاختبارات الوحدة. يعيد الوهمي نتائج محددة مسبقاً بدون استدعاءات نظام. هذا يسمح باختبار ViewModel ومنطق واجهة المستخدم بدون محاكي.

كيفية معالجة Never Ask Again في Handler؟

بعد الرفض، تحقق من shouldShowRequestPermissionRationale. إذا أعادت الطريقة false — وضع Never Ask Again نشط. يجب أن يعيد Handler PermissionResult.DENIED(false)، وتعرض واجهة المستخدم زراً للانتقال إلى الإعدادات.

الملخص

  • Permission Handler — مكون معماري للإدارة المركزية لأذونات وقت التشغيل في Android.
  • يستند إلى ActivityResultContracts.RequestPermission من مكتبة androidx.activity.
  • واجهة بطرق لكل إذن تبسط اختبارات الوحدة عبر التنفيذات الوهمية.
  • التكامل مع ViewModel عبر StateFlow يفصل كود المنصة عن منطق الأعمال.
  • الأخطاء النموذجية: عدم وجود checkSelfPermission، تجاهل المبرر و Never Ask Again.
  • أفضل ممارسة — Handler واحد لكل Activity مسجل في onCreate.
  • المركزة تقلل عدد أخطاء Permission Denial بنسبة 60 بالمائة في المشاريع النموذجية.

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا