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

يتم تشغيل كل تطبيق من تطبيقات 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>

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

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

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

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

في نظام التشغيل 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. إذا أردت طلب الأذونات الخاصة بسجلات المكالمات والرسائل القصيرة ونشر تطبيقك على "متجر Play"، يجب أن تطلب من المستخدم ضبط تطبيقك كمعالج تلقائي لوظيفة نظام أساسية، وذلك قبل طلب أذونات التشغيل هذه.

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

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

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

adb shell install -g PATH_TO_APK_FILE

مراجع إضافية

لمزيد من المعلومات حول الأذونات، يُرجى قراءة المقالات التالية:

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

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