طلب أذونات التشغيل

يتم تشغيل كل تطبيق Android في بيئة حماية ذات إذن وصول محدود. إذا كان تطبيقك بحاجة إلى استخدام موارد أو معلومات خارج مساحة المحاكاة الخاصة به، يمكنك تضمين إذن أثناء التشغيل وإعداد طلب إذن يمنح هذا الوصول. تشكّل هذه الخطوات جزءًا من سير العمل لاستخدام الأذونات.

إذا أدرجت أي أذونات خطيرة، وإذا تم تثبيت تطبيقك على جهاز يعمل بالإصدار 6.0 من نظام التشغيل Android (المستوى 23 من واجهة برمجة التطبيقات) أو إصدار أحدث، عليك طلب الأذونات الخطيرة أثناء التشغيل باتّباع الخطوات الواردة في هذا الدليل.

إذا لم تذكر أي أذونات خطيرة أو إذا كان تطبيقك مثبَّتًا على جهاز يعمل بنظام التشغيل Android 5.1 (المستوى 22 من واجهة برمجة التطبيقات) أو إصدار أقدم، يتم منح الأذونات تلقائيًا، ولن تحتاج إلى إكمال أي من الخطوات المتبقية في هذه الصفحة.

المبادئ الأساسية

في ما يلي المبادئ الأساسية لطلب الأذونات أثناء التشغيل:

  • اطلب الإذن في السياق، عندما يبدأ المستخدم التفاعل مع الميزة التي تتطلّب ذلك.
  • لا تحظر المستخدم. يجب دائمًا توفير خيار لإلغاء مسار واجهة مستخدم تتعلّق بالتعليم، مثل مسار يوضّح السبب المنطقي لطلب الأذونات.
  • إذا رفض المستخدم الإذن الذي تطلبه إحدى الميزات أو أبطله، يمكنك خفض إصدار تطبيقك على نحو ملائم مع السماح للمستخدم بمواصلة استخدام التطبيق، وذلك من خلال إيقاف الميزة التي تتطلّب الإذن.
  • لا تفترض أي سلوك للنظام. على سبيل المثال، لا تفترض أنّ الأذونات تظهر في مجموعة الأذونات نفسها. تساعد مجموعة الأذونات النظام في تقليل عدد مربّعات حوار النظام التي يتم عرضها للمستخدم عندما يطلب تطبيق أذونات ذات صلة وثيقة.

سير العمل لطلب الأذونات

قبل الإفصاح عن أذونات التشغيل وطلبها في تطبيقك، عليك تقييم ما إذا كان تطبيقك بحاجة إلى ذلك. يمكنك تلبية العديد من حالات الاستخدام في تطبيقك، مثل التقاط الصور وإيقاف تشغيل الوسائط مؤقتًا وعرض الإعلانات ذات الصلة، بدون الحاجة إلى الإفصاح عن أي أذونات.

إذا تبيّن لك أنّ تطبيقك يحتاج إلى تقديم بيان عن أذونات التشغيل وطلبها، عليك إكمال الخطوات التالية:

  1. في ملف البيان الخاص بتطبيقك، أفصح عن الأذونات التي قد يحتاج تطبيقك إلى طلبها.
  2. يجب تصميم تجربة المستخدم في تطبيقك بحيث تكون الإجراءات المحدّدة في تطبيقك مرتبطة بأذونات وقت التشغيل المحدّدة. أطلِع المستخدمين على الإجراءات التي قد تتطلّب منهم منح إذن لتطبيقك بالوصول إلى بيانات المستخدمين الخاصة.
  3. انتظر إلى أن يطلب المستخدم تنفيذ المهمة أو الإجراء في تطبيقك الذي يتطلّب الوصول إلى بيانات خاصة معيّنة للمستخدم. وفي هذه الحالة، يمكن لتطبيقك طلب إذن التشغيل المطلوب للوصول إلى هذه البيانات.
  4. تحقَّق مما إذا كان المستخدم قد منح الإذن الذي يتطلبه تطبيقك في وقت التشغيل. في هذه الحالة، يمكن لتطبيقك الوصول إلى بيانات المستخدم الخاصة. إذا لم يكن الأمر كذلك، انتقِل إلى الخطوة التالية.

    عليك التحقّق مما إذا كان لديك إذن في كل مرة تُجري فيها عملية تتطلّب هذا الإذن.

  5. تحقّق مما إذا كان يجب أن يعرض تطبيقك سببًا منطقيًا للمستخدم، ويشرح سبب احتياج تطبيقك إلى أن يمنح المستخدم إذن تشغيل معيّنًا. إذا قرّر النظام أنّ تطبيقك لا يجب أن يقدّم مبررًا منطقيًا، يمكنك المتابعة إلى الخطوة التالية مباشرةً بدون عرض أي عنصر في واجهة المستخدم.

    إذا قرّر النظام أنّ تطبيقك يجب أن يُظهر مبررًا منطقيًا، يمكنك تقديم الأساس المنطقي للمستخدم في عنصر في واجهة المستخدم. في هذه المبررات، وضِّح بوضوح البيانات التي يحاول تطبيقك الوصول إليها والمزايا التي يمكن أن يوفّرها للمستخدم في حال منحه إذن التشغيل. بعد أن يقر المستخدم بالأسباب، تابع إلى الخطوة التالية.

  6. اطلب إذن وقت التشغيل الذي يحتاجه تطبيقك للوصول إلى بيانات المستخدم الخاصة. يعرض النظام طلبًا للحصول على إذن وقت التشغيل، مثل الطلب الذي يظهر في صفحة النظرة العامة على الأذونات.

  7. تحقّق من ردّ المستخدم لمعرفة ما إذا كان قد اختار منح إذن التشغيل أو رفضه.

  8. إذا منح المستخدم الإذن لتطبيقك، يمكنك الوصول إلى بيانات المستخدم الخاصة. إذا رفض المستخدم الإذن، يمكنك خفض إصدار تجربته في تطبيقك بشكل ملائم كي يقدّم للمستخدم وظائف بدون المعلومات المحمية بهذا الإذن.

يوضّح الشكل 1 سير العمل ومجموعة القرارات المرتبطة بهذه العملية:

الشكل 1. مخطّط بياني يعرض سير العمل المتعلّق بتعريف أذونات وقت التشغيل و طلبها على Android

تحديد ما إذا كان قد سبق أن تم منح تطبيقك الإذن

للتحقّق مما إذا سبق للمستخدم منح تطبيقك إذنًا معيّنًا، نقْل هذا الإذن إلى الأسلوب ContextCompat.checkSelfPermission(). تعرض هذه الطريقة إما PERMISSION_GRANTED أو PERMISSION_DENIED، بناءً على ما إذا كان تطبيقك قد حصل على الإذن أم لا.

توضيح سبب احتياج تطبيقك إلى الإذن

يعرض مربّع حوار الأذونات الذي يعرضه النظام عند الاتصال requestPermissions() الإذن الذي يريده تطبيقك، ولكن لا يوضّح السبب. في بعض الحالات، قد يجد المستخدم هذا اللغز. ننصحك بأن تشرح للمستخدم سبب طلب تطبيقك للأذونات قبل استدعاء requestPermissions().

تُظهر الأبحاث أنّ المستخدمين يشعرون براحة أكبر مع طلبات الأذونات إذا كانوا يعرفون سبب احتياج التطبيق إليها، مثل ما إذا كان الإذن مطلوبًا لدعم ميزة أساسية في التطبيق أو لعرض الإعلانات. نتيجةً لذلك، إذا كنت تستخدم جزءًا فقط من طلبات بيانات واجهة برمجة التطبيقات التي تندرج ضمن مجموعة أذونات، فإنه يساعد في إدراج الأذونات التي تستخدمها وسبب استخدامها بشكل صريح. على سبيل المثال، إذا كنت تستخدم الموقع الجغرافي التقريبي فقط، يُرجى إبلاغ المستخدم بذلك في وصف التطبيق أو في مقالات المساعدة حول التطبيق.

في ظروف معيّنة، من المفيد أيضًا إبلاغ المستخدمين بشأن الوصول إلى البيانات الحسّاسة في الوقت الفعلي. على سبيل المثال، إذا كنت تريد الوصول إلى الكاميرا أو الميكروفون، من الأفضل إبلاغ المستخدم من خلال استخدام رمز إشعار في مكان ما في تطبيقك أو في علبة الإشعارات (إذا كان التطبيق قيد التشغيل في الخلفية)، حتى لا يبدو أنّك تجمع البيانات بشكل خفي.

في النهاية، إذا كنت بحاجة إلى طلب إذن لجعل عملية معيّنة تعمل في تطبيقك، ولكن لم يكن السبب واضحًا للمستخدم، ابحث عن طريقة لإعلام المستخدم بسبب حاجتك إلى الأذونات الأكثر حساسية.

إذا كانت الطريقة ContextCompat.checkSelfPermission() تُرجع PERMISSION_DENIED، اتصل shouldShowRequestPermissionRationale(). إذا كانت هذه الطريقة تعرض القيمة true، عليك عرض واجهة مستخدم تعليمية للمستخدم. في واجهة المستخدم هذه، اشرح سبب احتياج الميزة التي يريد المستخدم تفعيلها إلى إذن معيّن.

بالإضافة إلى ذلك، إذا كان تطبيقك يطلب إذنًا مرتبطًا بالموقع الجغرافي أو الميكروفون أو الكاميرا، ننصحك بشرح سبب حاجة تطبيقك إلى الوصول إلى هذه المعلومات.

طلب الأذونات

بعد أن يطّلع المستخدم على واجهة مستخدم تعليمية، أو تشير القيمة المعروضة shouldShowRequestPermissionRationale() إلى أنّك لست بحاجة إلى عرض واجهة مستخدم تعليمية، اطلب الإذن. يظهر للمستخدمين مربّع حوار بشأن أحد أذونات النظام، حيث يمكنهم اختيار ما إذا كانوا يريدون منح إذنًا معيّنًا لتطبيقك.

لإجراء ذلك، استخدِم عقد RequestPermission المضمَّن في مكتبة AndroidX حيث تسمح للنظام بإدارة رمز طلب الإذن نيابةً عنك. وبما أنّ استخدام عقد RequestPermission يبسّط منطقك، ننصحك باستخدام الحل الموصى به إن أمكن. ومع ذلك، يمكنك أيضًا إدارة رمز طلب بنفسك إذا لزم الأمر كجزء من طلب الإذن و تضمين رمز الطلب هذا في منطق الاستدعاء الخاص بالإذن.

السماح للنظام بإدارة رمز طلب الإذن

للسماح للنظام بإدارة رمز الطلب المرتبط بطلب الأذونات، أضِف الاعتماديات إلى المكتبات التالية في ملف build.gradle الخاص بالوحدة:

يمكنك بعد ذلك استخدام إحدى الفئات التالية:

توضّح الخطوات التالية كيفية استخدام عقد RequestPermission. تتمثّل العملية نفسها تقريبًا في عقد RequestMultiplePermissions.

  1. في منطق إعداد النشاط أو الجزء، أدخِل تنفيذ ActivityResultCallback في استدعاء registerForActivityResult(). تحدِّد ActivityResultCallback كيفية تعامل تطبيقك مع استجابة المستخدم لطلب الإذن.

    احتفظ بمرجع إلى القيمة المعروضة من registerForActivityResult()، والتي تكون من النوع ActivityResultLauncher.

  2. لعرض مربّع حوار أذونات النظام عند الضرورة، يمكنك استدعاء الطريقة launch() على مثيل ActivityResultLauncher الذي حفظته في الخطوة السابقة.

    بعد استدعاء launch()، يظهر مربّع حوار أذونات النظام. عندما يحدّد المستخدم خيارًا، يستدعي النظام بشكل غير متزامن عملية تنفيذ ActivityResultCallback، التي حدّدتها في الخطوة السابقة.

    ملاحظة: لا يمكن لتطبيقك تخصيص مربّع الحوار الذي يظهر عند الاتصال برقم launch(). لتوفير مزيد من المعلومات أو السياق للمستخدم، عليك تغيير واجهة المستخدم في تطبيقك لكي يسهل على المستخدمين فهم سبب احتياج ميزة ما في تطبيقك إلى إذن معيّن. على سبيل المثال، يمكنك تغيير النص في الزر الذي يفعّل الميزة.

    يشير النص في مربّع الحوار الخاص بأذونات النظام أيضًا إلى مجموعة الأذونات المرتبطة بالإذن الذي طلبته. تم تصميم هذه المجموعة من الأذونات لتسهيل استخدام النظام، ويجب ألا يعتمد تطبيقك على الأذونات التي تكون ضمن مجموعة معيّنة من الأذونات أو خارجها.

يعرض مقتطف الرمز التالي طريقة التعامل مع استجابة الأذونات:

Kotlin

// Register the permissions callback, which handles the user's response to the
// system permissions dialog. Save the return value, an instance of
// ActivityResultLauncher. You can use either a val, as shown in this snippet,
// or a lateinit var in your onAttach() or onCreate() method.
val requestPermissionLauncher =
    registerForActivityResult(RequestPermission()
    ) { isGranted: Boolean ->
        if (isGranted) {
            // Permission is granted. Continue the action or workflow in your
            // app.
        } else {
            // Explain to the user that the feature is unavailable because the
            // feature requires a permission that the user has denied. At the
            // same time, respect the user's decision. Don't link to system
            // settings in an effort to convince the user to change their
            // decision.
        }
    }

Java

// Register the permissions callback, which handles the user's response to the
// system permissions dialog. Save the return value, an instance of
// ActivityResultLauncher, as an instance variable.
private ActivityResultLauncher<String> requestPermissionLauncher =
    registerForActivityResult(new RequestPermission(), isGranted -> {
        if (isGranted) {
            // Permission is granted. Continue the action or workflow in your
            // app.
        } else {
            // Explain to the user that the feature is unavailable because the
            // feature requires a permission that the user has denied. At the
            // same time, respect the user's decision. Don't link to system
            // settings in an effort to convince the user to change their
            // decision.
        }
    });

يوضح مقتطف الرمز هذا العملية المقترَحة للتحقّق من الحصول على إذن وطلب إذن من المستخدم عند الضرورة:

Kotlin

when {
    ContextCompat.checkSelfPermission(
            CONTEXT,
            Manifest.permission.REQUESTED_PERMISSION
            ) == PackageManager.PERMISSION_GRANTED -> {
        // You can use the API that requires the permission.
    }
    ActivityCompat.shouldShowRequestPermissionRationale(
            this, Manifest.permission.REQUESTED_PERMISSION) -> {
        // In an educational UI, explain to the user why your app requires this
        // permission for a specific feature to behave as expected, and what
        // features are disabled if it's declined. In this UI, include a
        // "cancel" or "no thanks" button that lets the user continue
        // using your app without granting the permission.
        showInContextUI(...)
    }
    else -> {
        // You can directly ask for the permission.
        // The registered ActivityResultCallback gets the result of this request.
        requestPermissionLauncher.launch(
                Manifest.permission.REQUESTED_PERMISSION)
    }
}

Java

if (ContextCompat.checkSelfPermission(
        CONTEXT, Manifest.permission.REQUESTED_PERMISSION) ==
        PackageManager.PERMISSION_GRANTED) {
    // You can use the API that requires the permission.
    performAction(...);
} else if (ActivityCompat.shouldShowRequestPermissionRationale(
        this, Manifest.permission.REQUESTED_PERMISSION)) {
    // In an educational UI, explain to the user why your app requires this
    // permission for a specific feature to behave as expected, and what
    // features are disabled if it's declined. In this UI, include a
    // "cancel" or "no thanks" button that lets the user continue
    // using your app without granting the permission.
    showInContextUI(...);
} else {
    // You can directly ask for the permission.
    // The registered ActivityResultCallback gets the result of this request.
    requestPermissionLauncher.launch(
            Manifest.permission.REQUESTED_PERMISSION);
}

إدارة رمز طلب الأذونات بنفسك

يمكنك إدارة رمز طلب الإذن بنفسك بدلاً من السماح للنظام بإدارة رمز طلب الإذن. لإجراء ذلك، عليك تضمين رمز الطلب في مكالمة requestPermissions().

يوضّح المقتطف البرمجي التالي كيفية طلب إذن باستخدام رمز طلب:

Kotlin

when {
    ContextCompat.checkSelfPermission(
            CONTEXT,
            Manifest.permission.REQUESTED_PERMISSION
            ) == PackageManager.PERMISSION_GRANTED -> {
        // You can use the API that requires the permission.
        performAction(...)
    }
    ActivityCompat.shouldShowRequestPermissionRationale(
            this, Manifest.permission.REQUESTED_PERMISSION) -> {
        // In an educational UI, explain to the user why your app requires this
        // permission for a specific feature to behave as expected, and what
        // features are disabled if it's declined. In this UI, include a
        // "cancel" or "no thanks" button that lets the user continue
        // using your app without granting the permission.
        showInContextUI(...)
    }
    else -> {
        // You can directly ask for the permission.
        requestPermissions(CONTEXT,
                arrayOf(Manifest.permission.REQUESTED_PERMISSION),
                REQUEST_CODE)
    }
}

Java

if (ContextCompat.checkSelfPermission(
        CONTEXT, Manifest.permission.REQUESTED_PERMISSION) ==
        PackageManager.PERMISSION_GRANTED) {
    // You can use the API that requires the permission.
    performAction(...);
} else if (ActivityCompat.shouldShowRequestPermissionRationale(
        this, Manifest.permission.REQUESTED_PERMISSION)) {
    // In an educational UI, explain to the user why your app requires this
    // permission for a specific feature to behave as expected, and what
    // features are disabled if it's declined. In this UI, include a
    // "cancel" or "no thanks" button that lets the user continue
    // using your app without granting the permission.
    showInContextUI(...);
} else {
    // You can directly ask for the permission.
    requestPermissions(CONTEXT,
            new String[] { Manifest.permission.REQUESTED_PERMISSION },
            REQUEST_CODE);
}

بعد استجابة المستخدم لمربّع حوار أذونات النظام، يستدعي النظام بعد ذلك تنفيذ onRequestPermissionsResult() في تطبيقك. يُرسِل النظام ردّ العميل إلى مربّع حوار الإذن، بالإضافة إلى رمز الطلب الذي حدّدته، كما هو موضّح في مقتطف الرمز البرمجي التالي:

Kotlin

override fun onRequestPermissionsResult(requestCode: Int,
        permissions: Array<String>, grantResults: IntArray) {
    when (requestCode) {
        PERMISSION_REQUEST_CODE -> {
            // If request is cancelled, the result arrays are empty.
            if ((grantResults.isNotEmpty() &&
                    grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                // Permission is granted. Continue the action or workflow
                // in your app.
            } else {
                // Explain to the user that the feature is unavailable because
                // the feature requires a permission that the user has denied.
                // At the same time, respect the user's decision. Don't link to
                // system settings in an effort to convince the user to change
                // their decision.
            }
            return
        }

        // Add other 'when' lines to check for other
        // permissions this app might request.
        else -> {
            // Ignore all other requests.
        }
    }
}

Java

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
        int[] grantResults) {
    switch (requestCode) {
        case PERMISSION_REQUEST_CODE:
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0 &&
                    grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission is granted. Continue the action or workflow
                // in your app.
            }  else {
                // Explain to the user that the feature is unavailable because
                // the feature requires a permission that the user has denied.
                // At the same time, respect the user's decision. Don't link to
                // system settings in an effort to convince the user to change
                // their decision.
            }
            return;
        }
        // Other 'case' lines to check for other
        // permissions this app might request.
    }
}

طلب أذونات تحديد الموقع الجغرافي

عند طلب أذونات تحديد الموقع الجغرافي، اتّبِع أفضل الممارسات نفسها التي تنطبق على أي إذن وقت تشغيل آخر. يتمثل أحد الاختلافات المهمة في ما يتعلق بأذونات الموقع الجغرافي في أنّه يتضمّن النظام أذونات متعددة ذات صلة بالموقع الجغرافي. تعتمد الأذونات التي تطلبها وطريقة طلبها على متطلبات الموقع الجغرافي لحالة استخدام تطبيقك.

الموقع الجغرافي في المقدّمة

إذا كان تطبيقك يحتوي على ميزة تشارك معلومات الموقع الجغرافي أو تتلقّاها مرة واحدة فقط أو لفترة زمنية محدَّدة، ستتطلّب هذه الميزة الوصول إلى الموقع الجغرافي في المقدّمة. في ما يلي بعض الأمثلة:

  • تتيح ميزة في تطبيق التنقّل للمستخدمين الحصول على اتّجاهات مفصّلة.
  • تتيح ميزة في تطبيق مراسلة للمستخدمين مشاركة موقعهم الجغرافي الحالي مع مستخدم آخر.

يعتبر النظام أنّ تطبيقك يستخدم الموقع الجغرافي في المقدّمة إذا كانت إحدى ميزات تطبيقك تحصل على الموقع الجغرافي الحالي للجهاز في أحد المواقف التالية:

  • النشاط الخاص بتطبيقك مرئي.
  • يشغّل تطبيقك خدمة تعمل في المقدّمة. عند تشغيل خدمة تعمل في المقدّمة، يُعلِم النظام المستخدم من خلال عرض إشعار دائم. يحتفظ تطبيقك بالوصول إلى البيانات عندما يكون في الخلفية، مثلاً عندما يضغط العميل على زر الشاشة الرئيسية على جهازه أو يطفئ شاشة جهازه.

    في نظام التشغيل Android 10 (مستوى واجهة برمجة التطبيقات 29) والإصدارات الأحدث، يجب تحديد نوع الخدمة التي تعمل في المقدّمة من location، كما هو موضّح في مقتطف الرمز التالي. في الإصدارات الأقدم من Android، ننصحك بتقديم بيان عن نوع الخدمة هذا الذي يعمل في المقدّمة.

    <!-- Recommended for Android 9 (API level 28) and lower. -->
    <!-- Required for Android 10 (API level 29) and higher. -->
    <service
        android:name="MyNavigationService"
        android:foregroundServiceType="location" ... >
        <!-- Any inner elements go here. -->
    </service>

أنت تقرّ بالحاجة إلى الموقع الجغرافي في المقدّمة عندما يطلب تطبيقك إذن ACCESS_COARSE_LOCATION أو إذن ACCESS_FINE_LOCATION على النحو الموضّح في المقتطف التالي:

<manifest ... >
  <!-- Include this permission any time your app needs location information. -->
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

  <!-- Include only if your app benefits from precise location access. -->
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>

رصد الموقع الجغرافي في الخلفية

يتطلب التطبيق الوصول إلى الموقع الجغرافي في الخلفية إذا كانت إحدى الميزات في التطبيق تشارك الموقع الجغرافي باستمرار مع مستخدمين آخرين أو تستخدم واجهة برمجة التطبيقات Geofencing. وفي ما يلي أمثلة عديدة على ذلك:

  • تتيح إحدى الميزات في تطبيق مشاركة الموقع الجغرافي مع العائلة للمستخدمين باستمرار مشاركة الموقع الجغرافي مع أفراد العائلة.
  • في أحد تطبيقات إنترنت الأشياء، تتيح ميزة للمستخدمين ضبط أجهزتهم المنزلية بحيث يتم إيقافها عندما يغادر المستخدم منزله وإعادة تشغيلها عندما يعود إليه.

يعتبر النظام أنّ تطبيقك يستخدم الموقع الجغرافي في الخلفية إذا كان يحصل على الموقع الجغرافي الحالي للجهاز في أيّ حالة غير تلك الموضّحة في القسم الموقع الجغرافي في المقدّمة. تكون دقة الموقع الجغرافي في الخلفية مماثلةلدقة الموقع الجغرافي في المقدّمة، والتي تعتمد بدورها علىأذونات الموقع الجغرافي التي يعلن عنها تطبيقك.

في الإصدار 10 من نظام التشغيل Android (المستوى 29 لواجهة برمجة التطبيقات) والإصدارات الأحدث، يجب تقديم بيان عن إذن ACCESS_BACKGROUND_LOCATION في ملف بيان تطبيقك لطلب إذن الوصول إلى الموقع الجغرافي في الخلفية أثناء وقت التشغيل. في الإصدارات السابقة من Android، عندما يحصل تطبيقك على إذن الوصول إلى الموقع الجغرافي في المقدّمة، يحصل تلقائيًا على إذن الوصول إلى الموقع الجغرافي في الخلفية أيضًا.

<manifest ... >
  <!-- Required only when requesting background location access on
       Android 10 (API level 29) and higher. -->
  <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
</manifest>

التعامل مع رفض الإذن

إذا رفض المستخدم طلب إذن، يجب أن يساعد تطبيقك المستخدمين في فهم النتائج المترتبة على رفض الإذن. وعلى وجه الخصوص، يجب أن يُعلم تطبيقك المستخدمين بالميزات التي لا تعمل بسبب عدم توفّر الإذن. عند إجراء ذلك، يُرجى مراعاة أفضل الممارسات التالية:

  • توجيه انتباه المستخدم: ميِّز جزءًا معيّنًا من واجهة مستخدم تطبيقك حيث تكون الوظيفة محدودة لأنّ تطبيقك لا يملك الإذن اللازم. وفي ما يلي أمثلة على الإجراءات التي يمكنك اتخاذها:

    • عرض رسالة في المكان الذي كان من المفترض أن تظهر فيه نتائج الميزة أو بياناتها
    • عرض زر مختلف يحتوي على رمز خطأ ولون
  • أدخِل وصفًا دقيقًا. لا تعرض رسالة عامة. بدلاً من ذلك، وضح الميزات غير المتوفرة لأن تطبيقك لا يحصل على الإذن اللازم.

  • لا تحظر واجهة المستخدم. بعبارة أخرى، لا تعرض رسالة تحذير بملء الشاشة تمنع المستخدمين من مواصلة استخدام تطبيقك إطلاقًا.

وفي الوقت نفسه، يجب أن يحترم تطبيقك قرار المستخدم برفض أحد الأذونات. بدءًا من Android 11 (المستوى 30 من واجهة برمجة التطبيقات)، إذا نقر المستخدم على رفض لإذن معيّن أكثر من مرّة خلال فترة تثبيت تطبيقك على جهاز، لن يظهر للمستخدم مربّع حوار أذونات النظام إذا طلب تطبيقك هذا الإذن مرة أخرى. يشير إجراء المستخدم إلى "عدم السؤال مرة أخرى". وفي الإصدارات السابقة، كان يظهر للمستخدمين مربع حوار أذونات النظام في كل مرة يطلب فيها تطبيقك إذنًا، ما لم يسبق لهم وضع علامة في مربّع الاختيار أو مربّع الاختيار "عدم السؤال مرة أخرى".

إذا رفض المستخدم طلب إذن أكثر من مرة، يُعدّ ذلك علامة على أنّه قد تمّ الرفض بشكل دائم. من المهم جدًا عدم طلب الأذونات من المستخدمين إلا عندما يحتاجون إلى الوصول إلى ميزة معيّنة، وإلا قد تفقد بدون قصد إمكانية إعادة طلب الأذونات.

في بعض الحالات، قد يتم رفض الإذن تلقائيًا بدون أن يتخذ المستخدم أي إجراء. (قد يتم أيضًا منح الإذن تلقائيًا). من المهم ألا تفترض أي شيء عن السلوك التلقائي. في كل مرة يحتاج فيها تطبيقك إلى الوصول إلى وظيفة تتطلّب إذنًا، تحقّق من أنّه لا يزال مُمنوحًا هذا الإذن.

لتقديم أفضل تجربة للمستخدم عند طلب أذونات التطبيق، يمكنك أيضًا الاطّلاع على أفضل الممارسات المتعلّقة بأذونات التطبيق.

فحص حالة الرفض عند الاختبار وتصحيح الأخطاء

لتحديد ما إذا تم رفض أذونات التطبيق نهائيًا (لأغراض تصحيح الأخطاء والاختبار)، استخدِم الأمر التالي:

adb shell dumpsys package PACKAGE_NAME

حيث يكون PACKAGE_NAME هو اسم الحزمة المطلوب فحصها.

ويحتوي مخرج الأمر على أقسام تبدو كما يلي:

...
runtime permissions:
  android.permission.POST_NOTIFICATIONS: granted=false, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]
  android.permission.ACCESS_FINE_LOCATION: granted=false, flags=[ USER_SET|USER_FIXED|USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]
  android.permission.BLUETOOTH_CONNECT: granted=false, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]
...

يتم وضع علامة على الأذونات التي رفضها المستخدم مرة واحدة من خلال USER_SET. يتم وضع علامة على الأذونات التي تم رفضها نهائيًا من خلال النقر على رفض مرتين من قِبل USER_FIXED.

لضمان ظهور مربّع حوار الطلب للمختبِرين أثناء الاختبار، عليك إعادة ضبط هذه العلامات عند الانتهاء من تصحيح أخطاء تطبيقك. لإجراء ذلك، استخدِم الأمر التالي:

adb shell pm clear-permission-flags PACKAGE_NAME PERMISSION_NAME user-set user-fixed

PERMISSION_NAME هو اسم الإذن الذي تريد إعادة ضبطه.

للاطّلاع على قائمة كاملة بأذونات تطبيقات Android، يُرجى الانتقال إلى صفحة مرجع واجهة برمجة التطبيقات للأذونات.

الأذونات لمرة واحدة

الخيار &quot;هذه المرة فقط&quot; هو الزر الثاني من بين ثلاثة أزرار في
    مربّع الحوار.
الشكل 2. مربّع حوار النظام الذي يظهر عندما يطلب أحد التطبيقات إذنًا لمرة واحدة

بدءًا من Android 11 (المستوى 30 من واجهة برمجة التطبيقات)، عندما يطلب تطبيقك إذنًا مرتبطًا بتحديد الموقع الجغرافي أو الميكروفون أو الكاميرا، يحتوي مربّع حوار الأذونات الموجَّه للمستخدمين على خيار هذه المرة فقط، كما هو موضّح في الشكل 2. إذا اختار المستخدم هذا الخيار في المربّع الحواري، يحصل تطبيقك على إذن مؤقت لمرة واحدة.

يمكن لتطبيقك بعد ذلك الوصول إلى البيانات ذات الصلة لفترة زمنية تعتمد على سلوك تطبيقك وإجراءاته:

  • عندما يكون نشاط تطبيقك مرئيًا، يمكن لتطبيقك الوصول إلى البيانات.
  • إذا أرسل المستخدم تطبيقك إلى الخلفية، سيظل بإمكانه الوصول إلى البيانات لفترة قصيرة من الوقت.
  • إذا شغّلت خدمة تعمل في المقدّمة عندما يكون النشاط مرئيًا، ثم نقل المستخدم تطبيقك إلى الخلفية، يمكن لتطبيقك مواصلة الوصول إلى البيانات إلى أن تتوقف الخدمة التي تعمل في المقدّمة.

تنتهي عملية التطبيق عند إبطال الإذن.

إذا ألغى المستخدم الإذن لمرة واحدة، مثل في إعدادات النظام، لن يتمكّن تطبيقك من الوصول إلى البيانات، بغض النظر عمّا إذا كنت قد أطلقت خدمة في المقدّمة. وكما هو الحال مع أي إذن، إذا أبطل المستخدم إذن الوصول إلى تطبيقك لمرة واحدة، سيتم إنهاء المعالجة الخاصة بالتطبيق.

عندما يفتح المستخدم تطبيقك في المرة التالية وتطلب إحدى الميزات في تطبيقك الوصول إلى الموقع الجغرافي أو الميكروفون أو الكاميرا، سيُطلب من المستخدم منح الإذن مرة أخرى.

إعادة ضبط الأذونات غير المستخدمة

يقدّم Android عدة طرق لإعادة ضبط أذونات وقت التشغيل غير المستخدَمة إلى حالتها التلقائية، وهي "محظور":

إزالة إذن وصول التطبيق

في الإصدار 13 من نظام التشغيل Android (المستوى 33 لواجهة برمجة التطبيقات) والإصدارات الأحدث، يمكنك إزالة إذن وصول تطبيقك إلى أذونات التشغيل التي لم يعُد تطبيقك بحاجة إليها. عند تحديث تطبيقك، نفِّذ هذه الخطوة لكي يفهم المستخدمون على الأرجح سبب استمرار تطبيقك في طلب أذونات معيّنة. وتساعد هذه المعرفة في بناء ثقة المستخدمين في تطبيقك.

لإزالة إذن التشغيل، نقْل اسم هذا الإذن إلى revokeSelfPermissionOnKill(). لإزالة إذن الوصول إلى مجموعة من أذونات وقت التشغيل في الوقت نفسه، نقْل مجموعة من أسماء الأذونات إلى revokeSelfPermissionsOnKill(). تتم عملية إزالة الأذونات بشكل غير متزامن وتؤدي إلى إنهاء جميع العمليات المرتبطة بـ UID لتطبيقك.

لكي يزيل النظام إذن وصول تطبيقك إلى الأذونات، يجب إنهاء جميع العمليات المرتبطة بتطبيقك. عند طلب البيانات من واجهة برمجة التطبيقات، يحدد النظام الوقت المناسب لإيقاف هذه العمليات. وعادةً ما ينتظر النظام إلى أن يقضي تطبيقك فترة طويلة من الوقت قيد التشغيل في الخلفية بدلاً من المقدّمة.

لإعلام المستخدم بأنّ تطبيقك لم يعُد يتطلّب الوصول إلى أذونات تشغيل معيّنة، يمكنك عرض مربّع حوار في المرة التالية التي يشغّل فيها المستخدم تطبيقك. ويمكن أن يتضمّن مربّع الحوار هذا قائمة الأذونات.

إعادة ضبط أذونات التطبيقات غير المستخدَمة تلقائيًا

إذا كان تطبيقك يستهدف الإصدار 11 من نظام Android (المستوى 30 لواجهة برمجة التطبيقات) أو إصدارًا أحدث ولم يتم استخدامه لعدة أشهر، يحمي النظام بيانات المستخدم من خلال إعادة ضبط أذونات التشغيل الحسّاسة التي منحها المستخدم لتطبيقك تلقائيًا. يمكنك الاطّلاع على مزيد من المعلومات في الدليل المتعلق بميزة الوضع المنخفض للطاقة في التطبيقات.

طلب أن تصبح المعالِج التلقائي إذا لزم الأمر

تعتمد بعض التطبيقات على الوصول إلى معلومات المستخدمين الحسّاسة المرتبطة بسجلّات المكالمات والرسائل القصيرة. إذا كنت تريد طلب الأذونات الخاصة بسجلّات المكالمات والرسائل القصيرة SMS ونشر تطبيقك على "متجر Play"، عليك أن تطلب من المستخدم ضبط تطبيقك على أنّه المعالِج التلقائي لوظيفة أساسية في النظام قبل طلب أذونات التشغيل هذه.

للحصول على مزيد من المعلومات حول المعالِجات التلقائية، بما في ذلك إرشادات حول عرض طلب المعالِج التلقائي للمستخدمين، يمكنك الاطّلاع على الدليل حول الأذونات المستخدمة في المعالِجات التلقائية فقط.

منح جميع أذونات التشغيل لأغراض الاختبار

لمنح جميع أذونات وقت التشغيل تلقائيًا عند تثبيت تطبيق على جهاز اختبار أو جهاز محاكاة، استخدِم الخيار -g للأمر adb shell install ، كما هو موضّح في مقتطف التعليمات البرمجية التالي:

adb shell install -g PATH_TO_APK_FILE

مصادر إضافية

للحصول على معلومات إضافية حول الأذونات، يُرجى قراءة المقالات التالية:

لمزيد من المعلومات حول طلب الأذونات، يمكنك مراجعة نماذج الأذونات

يمكنك أيضًا إكمال هذا الدرس التطبيقي حول الترميز الذي يوضّح أفضل ممارسات الخصوصية.