"خدمات Google Play" وأذونات وقت التشغيل

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

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

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

المتطلبات الأساسية

عليك الإفصاح عن الأذونات في ملف AndroidManifest.xml. على سبيل المثال:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

الإرشادات

التحقّق من الأذونات قبل استدعاء واجهات برمجة التطبيقات

بعد الإفصاح عن واجهات برمجة التطبيقات التي تريد استخدامها في ملف AndroidManifest.xml، تأكَّد من حصولك على الإذن المطلوب قبل طلب واجهة برمجة تطبيقات. يمكن إجراء ذلك باستخدام طريقة checkSelfPermission في ActivityCompat أو ContextCompat.

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

على سبيل المثال:

Kotlin

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED) {
            // Request Permissions Now
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                REQUEST_LOCATION_PERMISSION_CODE)
    } else {
        // permission has been granted, continue as usual
        val locationResult = LocationServices
            .getFusedLocationProviderClient(this /* Context */)
            .lastLocation
    }

Java

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED) {
        // Request Permissions Now
        ActivityCompat.requestPermissions(
            this,
            new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
            REQUEST_LOCATION_PERMISSION_CODE);
    } else {
        // permission has been granted, continue as usual
        Task locationResult = LocationServices
            .getFusedLocationProviderClient(this /** Context */)
            .getLastLocation();
    }

تنفيذ دالة معاودة الاتصال لطلب الإذن

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

Kotlin

    fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array,
        grantResults: IntArray
    ) {
        if (requestCode == REQUEST_LOCATION_PERMISSION_CODE) {
            if (grantResults.singleOrNull() == PackageManager.PERMISSION_GRANTED) {
               // We can now safely use the API we requested access to
               val locationResult: Task = LocationServices
                    .getFusedLocationProviderClient(this /* Context */)
                    .lastLocation // Request the last known location.
            } else {
                // Permission was denied or request was cancelled
            }
        }
    }

Java

    public void onRequestPermissionsResult(int requestCode,
                                            String[] permissions,
                                            int[] grantResults) {
        if (requestCode == REQUEST_LOCATION_PERMISSION_CODE) {
            if(grantResults.length == 1
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // We can now safely use the API we requested access to
                Task locationResult = LocationServices
                    .getFusedLocationProviderClient(this /** Context */)
                    .getLastLocation(); // Request the last known location.
            } else {
                // Permission was denied or request was cancelled
            }
        }
    }

عرض سبب طلب الإذن

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

في هذه الحالة، قبل الاتصال بـ "requestPermissions"، عليك الاتصال بالرقم shouldShowRequestPermissionRationale. إذا عرضت القيمة true، عليك إنشاء بعض عناصر واجهة المستخدم لعرض سياق إضافي للإذن.

على سبيل المثال، قد يبدو الرمز البرمجي على النحو التالي:

Kotlin

    private const val REQUEST_LOCATION_PERMISSION_CODE = 2
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED) {
        // Check Permissions Now
        if ActivityCompat.shouldShowRequestPermissionRationale(
            this,
            Manifest.permission.ACCESS_FINE_LOCATION
        ) {
            // Display UI and wait for user interaction
        } else {
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                REQUEST_LOCATION_PERMISSION_CODE)
        }
    } else {
        // Permission has already been granted, continue as usual
        val locationResult: Task = LocationServices
            .getFusedLocationProviderClient(this /* Context */)
            .lastLocation
    }

Java

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED) {
        // Check Permissions Now
        private static final int REQUEST_LOCATION_PERMISSION_CODE = 2;
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.ACCESS_FINE_LOCATION)) {
            // Display UI and wait for user interaction
        } else {
            ActivityCompat.requestPermissions(
                this, new String[]{Manifest.permission.LOCATION_FINE},
                REQUEST_LOCATION_PERMISSION_CODE);
        }
    } else {
        // permission has been granted, continue as usual
        Task locationResult = LocationServices
            .getFusedLocationProviderClient(this /** Context */)
            .getLastLocation();
    }

ستعرض طلبات البيانات من واجهة برمجة التطبيقات لخدمات Google Play تلقائيًا إما مربّع حوار (إذا تم إنشاء مثيل للعميل باستخدام Activity) أو إشعارًا في شريط النظام (إذا تم إنشاء مثيل للعميل باستخدام Context) يمكن للمستخدم النقر عليه لبدء الغرض من حلّ الأذونات. سيتم وضع المكالمات في قائمة الانتظار وإعادة المحاولة بعد منح الإذن.