שירותי Google Play והרשאות בסביבת זמן הריצה

מאז Android 6.0 Marshmallow, מערכת Android משתמשת במודל הרשאות שמייעל את תהליך ההתקנה והעדכון האוטומטי של האפליקציות. הבקשה להרשאות מוצגת בזמן ההפעלה ולא לפני התקנת האפליקציה. בנוסף, המשתמשים יכולים לבחור שלא לאשר הרשאות ספציפיות. כדי לאפשר למשתמשים את הגמישות הזו, צריך לוודא שהאפליקציה מתנהגת כמו שצריך כשמשתמש מפעיל או משבית הרשאה ספציפית.

ל-Google Play Services עצמו יש הרשאות זמן ריצה שהמשתמשים יכולים לבחור לדחות בנפרד מההרשאות שהאפליקציה שלכם מבקשת באופן ספציפי. ‏Google Play Services מקבל באופן אוטומטי את כל ההרשאות שהוא צריך כדי לתמוך בממשקי ה-API שלו. עם זאת, האפליקציה עדיין צריכה לבדוק ולבקש הרשאות בזמן הריצה לפי הצורך, ולטפל בשגיאות בצורה מתאימה במקרים שבהם משתמש דחה את ההרשאה של שירותי Google Play שנדרשת ל-API שהאפליקציה משתמשת בו.

מומלץ לנהל את ציפיות המשתמשים בהגדרת הרשאות שהסביבה עשויה לדרוש. השיטות המומלצות הבאות יעזרו לכם להימנע מבעיות פוטנציאליות.

דרישות מוקדמות

צריך להצהיר על הרשאות בקובץ AndroidManifest.xml. לדוגמה:

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

הנחיות

אימות הרשאות לפני הפעלת ממשקי API

אחרי שמצהירים על ממשקי ה-API שרוצים להשתמש בהם בקובץ AndroidManifest.xml, צריך לוודא שיש את ההרשאה הנדרשת לפני שמבצעים קריאה ל-API. אפשר לעשות את זה באמצעות השיטה checkSelfPermission של ActivityCompat או ContextCompat.

אם הקריאה מחזירה את הערך false, המשמעות היא שההרשאות לא ניתנו וצריך להשתמש ב-requestPermissions כדי לבקש אותן. התשובה לכך מוחזרת בקריאה חוזרת (callback) שתוצג בשלב הבא.

לדוגמה:

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

הטמעה של הקריאה החוזרת (callback) לבקשת הרשאה

אם המשתמש לא העניק את ההרשאה שהאפליקציה צריכה, צריך לקרוא לשיטה requestPermissions כדי לבקש מהמשתמש להעניק אותה. התגובה של המשתמש מתועדת בקריאה החוזרת (callback) של 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 Services API יציגו אוטומטית תיבת דו-שיח (אם הלקוח הוא מופע של Activity) או התראה במגש המערכת (אם הלקוח הוא מופע של Context). המשתמש יכול להקיש על ההתראה כדי להתחיל את כוונת ההרשאה. השיחות יתווספו לתור ויבוצע ניסיון חוזר ברגע שההרשאה תינתן.