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

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

إذا أبلغت عن أي أذونات خطرة وإذا كان تطبيقك مثبَّتًا على جهاز يعمل بالإصدار Android 6.0 (المستوى 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. وفي ما يلي أمثلة عديدة على ذلك:

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

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

في نظام التشغيل Android 10 (مستوى واجهة برمجة التطبيقات 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 عدة طرق لإعادة ضبط أذونات وقت التشغيل غير المستخدَمة على حالة الرفض التلقائية:

إزالة إمكانية وصول التطبيقات إلى حسابك

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

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

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

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

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

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

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

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

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

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

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

adb shell install -g PATH_TO_APK_FILE

مصادر إضافية

للحصول على معلومات إضافية حول الأذونات، اطّلِع على المقالات التالية:

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

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