בקשת הרשאות בזמן ריצה

כל אפליקציית Android פועלת בארגז חול עם גישה מוגבלת. אם האפליקציה צריכה להשתמש במשאבים או במידע מחוץ לארגז החול שלה, אתם יכולים להצהיר על הרשאה בתחילת ההפעלה ולהגדיר בקשת הרשאה שתספק את הגישה הזו. השלבים האלה הם חלק מתהליך העבודה לשימוש בהרשאות.

אם אתם מצהירים על הרשאות מסוכנות, והאפליקציה שלכם מותקנת במכשיר עם Android 6.0 (רמת API ‏23) ומעלה, אתם צריכים לבקש את ההרשאות המסוכנות בזמן הריצה לפי השלבים במדריך הזה.

אם לא מצהירים על הרשאות מסוכנות, או אם האפליקציה מותקנת במכשיר עם Android 5.1 (רמת API‏ 22) ומטה, ההרשאות ניתנות באופן אוטומטי ואין צורך לבצע את שאר השלבים שבדף הזה.

עקרונות בסיסיים

אלה העקרונות הבסיסיים לבקשת הרשאות בזמן הריצה:

  • בקשו הרשאה בהקשר, כשהמשתמש מתחיל להשתמש בתכונה שדורשת את ההרשאה.
  • אל תחסמו את המשתמש. תמיד צריך לספק אפשרות לבטל תהליך של ממשק משתמש הסברתי, כמו תהליך שמסביר את הנימוק לבקשת הרשאות.
  • אם המשתמש דוחה או מבטל הרשאה שנדרשת לתכונה מסוימת, צריך לבצע הפחתה חיננית (graceful degradation) של האפליקציה כדי שהמשתמש יוכל להמשיך להשתמש בה, למשל על ידי השבתת התכונה שדורשת את ההרשאה.
  • אל תניחו הנחות לגבי התנהגות המערכת. לדוגמה, אל תניחו שההרשאות מופיעות באותה קבוצת הרשאות. קבוצת הרשאות רק עוזרת למערכת לצמצם את מספר תיבות הדו-שיח שמוצגות למשתמש כשאפליקציה מבקשת הרשאות שקשורות זו לזו.

תהליך העבודה לבקשת הרשאות

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

אם הגעתם למסקנה שהאפליקציה שלכם צריכה להצהיר על הרשאות בתחילת ההפעלה ולבקש אותן, בצעו את השלבים הבאים:

  1. מצהירים על ההרשאות שהאפליקציה עשויה לבקש בקובץ המניפסט של האפליקציה.
  2. מעצבים את חוויית המשתמש (UX) באפליקציה כך שפעולות ספציפיות ישויכו להרשאות ספציפיות בתחילת ההפעלה. חשוב להודיע למשתמשים אילו פעולות עשויות לדרוש שהם ייתנו לאפליקציה הרשאת גישה לנתונים פרטיים.
  3. מחכים שהמשתמש יפעיל את המשימה או הפעולה באפליקציה שדורשת גישה לנתונים פרטיים ספציפיים. בשלב הזה, האפליקציה יכולה לבקש את ההרשאה בתחילת ההפעלה שנדרשת כדי לגשת לנתונים האלה.
  4. בודקים אם המשתמש כבר נתן

    הרשאה בתחילת ההפעלה שהאפליקציה דורשת. אם כן, האפליקציה יכולה לגשת לנתונים הפרטיים של המשתמש. אם הבעיה ממשיכה, עוברים לשלב הבא.

    בכל פעם שמבצעים פעולה שנדרשת לה הרשאה, צריך לבדוק אם ההרשאה הזו כבר ניתנה.

  5. בודקים אם האפליקציה צריכה להציג למשתמש הסבר למה היא צריכה שהוא יעניק לה הרשאה מסוימת בתחילת ההפעלה. אם המערכת קובעת שהאפליקציה לא צריכה להציג הסבר, ממשיכים ישירות לשלב הבא בלי להציג רכיב בממשק המשתמש.

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

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

  7. בודקים את התשובה של המשתמש – אם הוא בחר לאשר או לדחות את ההרשאה בתחילת ההפעלה.

  8. אם המשתמש העניק הרשאה לאפליקציה, היא תוכל לגשת לנתונים הפרטיים שלו. אם המשתמש דחה את ההרשאה, צריך לבצע הפחתה חיננית (graceful degradation) של חוויית השימוש באפליקציה ולשמור על הפונקציונליות שלא תלויה בנתונים שאין גישה אליהם.

באיור 1 מוצגים תהליך העבודה וקבוצת ההחלטות שקשורות לתהליך הזה:

תרשים זרימה שממחיש את תהליך קבלת ההחלטות לבקשת הרשאות בתחילת ההפעלה, החל מפעולה באפליקציה, בדיקה אם ניתנה הרשאה, בדיקה אם נדרש הסבר, בקשת הרשאה וטיפול בתגובת המשתמש.
איור 1. דיאגרמה שמציגה את תהליך העבודה להצהרה ובקשה של הרשאות בתחילת ההפעלה ב-Android.

איך בודקים אם האפליקציה כבר קיבלה את ההרשאה

כדי לבדוק אם המשתמש כבר נתן לאפליקציה הרשאה מסוימת, מעבירים את ההרשאה הזו ל-method‏ ContextCompat.checkSelfPermission(). השיטה הזו מחזירה PERMISSION_GRANTED או PERMISSION_DENIED, בהתאם להרשאה של האפליקציה.

צריך להסביר למה האפליקציה צריכה את ההרשאה

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

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

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

אם אתם צריכים לבקש הרשאה כדי שתכונה מסוימת תפעל, אבל הסיבה לא ברורה למשתמש, אתם צריכים למצוא דרך להסביר למה אתם צריכים הרשאות גישה למידע רגיש.

אם השיטה ContextCompat.checkSelfPermission() מחזירה את הערך PERMISSION_DENIED, צריך להפעיל את shouldShowRequestPermissionRationale(). אם השיטה הזו מחזירה true, צריך להציג למשתמש ממשק משתמש עם הסבר. בממשק המשתמש הזה, צריך להסביר למה התכונה שהמשתמש רוצה להפעיל צריכה הרשאה מסוימת.

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

שליחת בקשה להרשאות

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

כדי לעשות את זה, משתמשים בחוזה RequestPermission, שכלול בספריית AndroidX, שבה מאפשרים למערכת לנהל את קוד בקשת ההרשאה בשבילכם. השימוש בחוזה RequestPermission מפשט את הלוגיקה, ולכן זה הפתרון המומלץ כשאפשר להשתמש בו. עם זאת, במקרה הצורך אתם יכולים גם לנהל קוד בקשה בעצמכם כחלק מבקשת ההרשאה, ולכלול את קוד הבקשה הזה בלוגיקה של הקריאה החוזרת (callback) של ההרשאה.

המערכת יכולה לנהל את קוד בקשת ההרשאה

כדי לאפשר למערכת לנהל את קוד הבקשה שמשויך לבקשת הרשאה, מוסיפים יחסי תלות בספריות הבאות בקובץ build.gradle של המודול:

לאחר מכן אפשר להשתמש באחת מהמחלקות הבאות:

כך משתמשים בחוזה RequestPermission: התהליך כמעט זהה לחוזה של RequestMultiplePermissions.

  1. בלוגיקת האתחול של הפעילות או החלק, מעבירים הטמעה של ActivityResultCallback לקריאה ל-registerForActivityResult(). ה-ActivityResultCallback מגדיר איך האפליקציה מטפלת בתגובה של המשתמש לבקשת ההרשאה.

    שומרים הפניה לערך המוחזר של registerForActivityResult(), שהוא מסוג ActivityResultLauncher.

  2. כדי להציג את תיבת הדו-שיח של הרשאות המערכת במקרה הצורך, מפעילים את השיטה launch() במכונה של ActivityResultLauncher ששמרתם בשלב הקודם.

    אחרי הקריאה ל-launch(), מופיעה תיבת הדו-שיח של הרשאות המערכת. כשהמשתמש בוחר, המערכת מפעילה באופן אסינכרוני את ההטמעה של ActivityResultCallback, שהגדרתם בשלב הקודם.

    הערה: אי אפשר להתאים אישית את תיבת הדו-שיח שמופיעה כשמפעילים את launch(). כדי לספק למשתמשים מידע נוסף או הקשר, צריך לשנות את ממשק המשתמש של האפליקציה כך שהמשתמשים יבינו בקלות למה תכונה מסוימת באפליקציה צריכה הרשאה מסוימת. לדוגמה, אתם יכולים לשנות את הטקסט בלחצן שמפעיל את התכונה.

    בנוסף, הטקסט בתיבת הדו-שיח של הרשאות המערכת מפנה לקבוצת ההרשאות שמשויכת להרשאה שביקשתם. קבוצת ההרשאות הזו נועדה להקל על השימוש במערכת, והאפליקציה לא צריכה להסתמך על כך שההרשאות נמצאות בתוך קבוצת הרשאות ספציפית או מחוץ לה.

בקטע הקוד הבא מוצג איך לטפל בתגובה להרשאות:

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

קטע הקוד הבא מדגים את התהליך המומלץ לבדיקת הרשאה ולבקשת הרשאה מהמשתמש במקרה הצורך:

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 (רמת API‏ 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 API. הנה כמה דוגמאות:

  • באפליקציה לשיתוף מיקום עם בני משפחה, יש תכונה שמאפשרת למשתמשים לשתף את המיקום שלהם עם בני המשפחה באופן רציף.
  • באפליקציית IoT, תכונה מאפשרת למשתמשים להגדיר את המכשירים הביתיים שלהם כך שהם יכבו כשהמשתמשים יוצאים מהבית ויופעלו כשהמשתמשים חוזרים הביתה.

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

ב-Android מגרסה 10 (רמת API‏ 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>

טיפול בדחיית הרשאה

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

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

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

  • אל תחסמו את ממשק המשתמש. במילים אחרות, אל תציגו הודעת אזהרה במסך מלא שמונעת מהמשתמשים להמשיך להשתמש באפליקציה.

  • קבלו את ההעדפה של המשתמש: מותר להסביר למשתמשים איך הפונקציונליות של האפליקציה מושפעת מהיעדר גישה להרשאות המבוקשות, אבל אסור להפעיל עליהם לחץ לשנות את דעתם. חשוב ליידע את המשתמשים שהם לא מקבלים גישה מלאה לתכונות כשהדבר רלוונטי (למשל, כשמנסים להשתמש בחלק מהאפליקציה שנחסם ללא ההרשאה), אבל הצקה מתמשכת כדי שישקלו מחדש את הבחירה שלהם לא מכבדת את הבחירה הזו.

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

בנוסף, אם המשתמש לוחץ על "דחייה" של הרשאה מסוימת יותר מפעם אחת במהלך תקופת ההתקנה של האפליקציה במכשיר, תיבת הדו-שיח של הרשאות המערכת לא תופיע יותר אם האפליקציה תבקש את ההרשאה הזו שוב. הפעולה של המשתמש מרמזת על "אל תשאל שוב", ונחשבת לדחייה קבועה. חשוב מאוד לבקש מהמשתמשים הרשאות רק כשהם צריכים גישה לתכונה ספציפית. אחרת, יכול להיות שתאבדו בטעות את היכולת לבקש שוב הרשאות. במצבים מסוימים, יכול להיות שההרשאה תידחה באופן אוטומטי, בלי שהמשתמש יבצע פעולה כלשהי. (יכול להיות שההרשאה תוענק גם באופן אוטומטי). חשוב לא להניח הנחות לגבי התנהגות אוטומטית. בכל פעם שהאפליקציה צריכה לגשת לפונקציונליות שדורשת הרשאה, צריך לבדוק אם ההרשאה הזו עדיין ניתנת לאפליקציה. כדי לספק את חוויית המשתמש הטובה ביותר כשמבקשים הרשאות שניתנות לאפליקציה, כדאי לעיין גם בשיטות מומלצות להרשאות שניתנות לאפליקציה.

בדיקת סטטוס הדחייה במהלך בדיקה וניפוי באגים

כדי לזהות אם לאפליקציה נדחו הרשאות באופן סופי (למטרות ניפוי באגים ובדיקה), משתמשים בפקודה הבאה:

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 הוא שם ההרשאה שרוצים לאפס.

‫PERMISSION_NAME הוא שם ההרשאה שרוצים לאפס.

כדי לראות רשימה מלאה של ההרשאות שניתנות לאפליקציות ל-Android, אפשר להיכנס לדף העזרה של ה-API בנושא הרשאות.

הרשאות חד-פעמיות

האפשרות &quot;רק הפעם&quot; היא הכפתור השני מבין שלושת הכפתורים בתיבת הדו-שיח.
איור 2. תיבת דו-שיח של המערכת שמופיעה כשאפליקציה מבקשת הרשאה חד-פעמית.

החל מ-Android 11 (רמת API‏ 30), בכל פעם שהאפליקציה מבקשת הרשאה שקשורה למיקום, למיקרופון או למצלמה, תיבת הדו-שיח של ההרשאות שגלויה למשתמשים מכילה אפשרות שנקראת רק הפעם, כמו שמוצג באיור 2. אם המשתמש בוחר באפשרות הזו בתיבת הדו-שיח, האפליקציה מקבלת הרשאה חד-פעמית זמנית.

לאחר מכן, האפליקציה יכולה לגשת לנתונים הקשורים למשך פרק זמן שתלוי בהתנהגות של האפליקציה ובפעולות של המשתמש:

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

תהליך האפליקציה מסתיים כשההרשאה מבוטלת

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

בפעם הבאה שהמשתמש יפתח את האפליקציה ותכונה באפליקציה תבקש גישה למיקום, למיקרופון או למצלמה, המשתמש יתבקש לתת את ההרשאה שוב.

איפוס הרשאות שלא בשימוש

ב-Android יש כמה דרכים לאפס הרשאות בתחילת ההפעלה שלא נמצאות בשימוש למצב ברירת המחדל שלהן, שבו הן נדחות:

הסרת הגישה לאפליקציות

ב-Android 13 (רמת API‏ 33) ומעלה, אתם יכולים להסיר את הגישה של האפליקציה להרשאות בתחילת ההפעלה שהאפליקציה כבר לא צריכה. כשמעדכנים את האפליקציה, צריך לבצע את השלב הזה כדי שהמשתמשים יבינו למה האפליקציה ממשיכה לבקש הרשאות ספציפיות. הידע הזה עוזר לבנות אמון של המשתמשים באפליקציה.

כדי להסיר את הגישה להרשאה בתחילת ההפעלה, צריך להעביר את שם ההרשאה אל revokeSelfPermissionOnKill(). כדי להסיר את הגישה לקבוצה של הרשאות בתחילת ההפעלה בבת אחת, מעבירים אוסף של שמות הרשאות אל revokeSelfPermissionsOnKill(). תהליך הסרת ההרשאות מתבצע באופן אסינכרוני ומפסיק את כל התהליכים שמשויכים למזהה המשתמש של האפליקציה.

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

כדי להודיע למשתמש שהאפליקציה כבר לא צריכה גישה להרשאות ספציפיות בתחילת ההפעלה, צריך להציג תיבת דו-שיח בפעם הבאה שהמשתמש מפעיל את האפליקציה. תיבת הדו-שיח הזו יכולה לכלול את רשימת ההרשאות.

איפוס אוטומטי של הרשאות לאפליקציות שלא בשימוש

אם האפליקציה שלכם מטרגטת את Android 11 (רמת API‏ 30) ומעלה, ולא משתמשים בה במשך כמה חודשים, המערכת מגינה על נתוני המשתמשים על ידי איפוס אוטומטי של ההרשאות הרגישות בתחילת ההפעלה שהמשתמשים העניקו לאפליקציה. מידע נוסף זמין במדריך בנושא מצב תנומה של אפליקציה.

בקשה להפוך ל-handler שמוגדר כברירת מחדל, אם צריך

יש אפליקציות שצריכות גישה למידע רגיש של משתמשים שקשור ליומני שיחות ולהודעות SMS. אם אתם רוצים לבקש את ההרשאות הספציפיות ליומני שיחות ולהודעות SMS ולפרסם את האפליקציה בחנות Play, אתם צריכים לבקש מהמשתמש להגדיר את האפליקציה כhandler שמוגדר כברירת מחדל לפונקציית מערכת עיקרית לפני שאתם מבקשים את ההרשאות האלה בתחילת ההפעלה.

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

מתן כל ההרשאות בתחילת ההפעלה למטרות בדיקה

כדי להעניק את כל ההרשאות בתחילת ההפעלה באופן אוטומטי כשמתקינים אפליקציה באמולטור או במכשיר בדיקה, משתמשים באפשרות -g של הפקודה adb shell install, כמו שמוצג בקטע הקוד הבא:

adb shell install -g PATH_TO_APK_FILE

מקורות מידע נוספים

למידע נוסף על הרשאות, כדאי לקרוא את המאמרים הבאים:

כדי לקבל מידע נוסף על בקשת הרשאות, אפשר לעיין בדוגמאות להרשאות.

אתם יכולים גם להשלים את שיעור ה-Codelab הזה שמדגים שיטות מומלצות לשמירה על הפרטיות.