כל אפליקציית Android פועלת בארגז חול עם גישה מוגבלת. אם האפליקציה שלכם צריכה להשתמש במשאבים או במידע מחוץ לארגז החול שלה, אתם יכולים להצהיר על הרשאת זמן ריצה ולהגדיר בקשת הרשאה שתספק את הגישה הזו. השלבים האלה הם חלק מתהליך העבודה לשימוש בהרשאות.
אם מצהירים על הרשאות מסוכנות, ואם האפליקציה מותקנת במכשיר עם Android בגרסה 6.0 (רמת API 23) ומעלה, צריך לבקש את ההרשאות המסוכנות בזמן הריצה. לשם כך, צריך לפעול לפי השלבים במדריך הזה.
אם לא הצהרתם על הרשאות מסוכנות, או אם האפליקציה שלכם מותקנת במכשיר עם Android 5.1 (רמת API 22) או גרסה מוקדמת יותר, ההרשאות ניתנות באופן אוטומטי, ולא צריך לבצע את השלבים שנותרו בדף הזה.
עקרונות בסיסיים
העקרונות הבסיסיים לבקשת הרשאות בזמן ריצה הם:
- לבקש הרשאה בהקשר, כשהמשתמש מתחיל לקיים אינטראקציה עם התכונה שדורשת אותה.
- לא לחסום את המשתמש. תמיד צריך לספק אפשרות לבטל תהליך של ממשק משתמש חינוכי, כמו תהליך שמסביר את הנימוק לבקשת הרשאות.
- אם המשתמש דוחה או מבטל הרשאה שנדרשת לתכונה מסוימת, צריך לבצע הפחתה חיננית (graceful degradation) של האפליקציה כדי שהמשתמש יוכל להמשיך להשתמש בה. אפשר לעשות זאת על ידי השבתת התכונה שדורשת את ההרשאה.
- אל תניחו הנחות לגבי התנהגות המערכת. לדוגמה, אל תניחו שההרשאות מופיעות באותה קבוצת הרשאות. קבוצת הרשאות רק עוזרת למערכת לצמצם את מספר תיבות הדו-שיח של המערכת שמוצגות למשתמש כשבאפליקציה מתבקשות הרשאות שקשורות זו לזו.
תהליך העבודה לבקשת הרשאות
לפני שמצהירים על הרשאות בזמן ריצה ומבקשים אותן באפליקציה, צריך להעריך אם האפליקציה צריכה לעשות זאת. אפשר להשתמש באפליקציה במקרים רבים, כמו צילום תמונות, השהיית הפעלת מדיה והצגת מודעות רלוונטיות, בלי להצהיר על הרשאות כלשהן.
אם הגעת למסקנה שהאפליקציה שלך צריכה להצהיר על הרשאות ולבקש אותן בזמן הריצה, צריך לבצע את השלבים הבאים:
- בקובץ המניפסט של האפליקציה, מצהירים על ההרשאות שהאפליקציה עשויה לבקש.
- מעצבים את חוויית השימוש באפליקציה כך שפעולות ספציפיות ישויכו להרשאות ספציפיות בזמן ריצה. חשוב להודיע למשתמשים אילו פעולות עשויות לדרוש שהם ייתנו לאפליקציה הרשאת גישה לנתונים פרטיים.
- מחכים שהמשתמש יפעיל את המשימה או הפעולה באפליקציה שדורשת גישה לנתונים פרטיים ספציפיים. בשלב הזה, האפליקציה יכולה לבקש הרשאת זמן ריצה שנדרשת כדי לגשת לנתונים האלה.
בודקים אם המשתמש כבר נתן לאפליקציה את הרשאת זמן הריצה שהיא דורשת. אם כן, האפליקציה יכולה לגשת לנתונים הפרטיים של המשתמש. אם הבעיה ממשיכה, עוברים לשלב הבא.
בכל פעם שמבצעים פעולה שנדרשת לה הרשאה, צריך לבדוק אם ההרשאה הזו כבר ניתנה.
בודקים אם האפליקציה צריכה להציג למשתמש נימוק שמסביר למה האפליקציה צריכה שהמשתמש יעניק לה הרשאה מסוימת בתחילת ההפעלה. אם המערכת קובעת שלא צריך להציג הסבר לגבי האפליקציה, ממשיכים ישירות לשלב הבא בלי להציג רכיב ממשק משתמש.
אם המערכת קובעת שהאפליקציה צריכה להציג נימוק, צריך להציג אותו למשתמש ברכיב של ממשק המשתמש. בנימוק הזה, צריך להסביר בצורה ברורה לאילו נתונים האפליקציה מנסה לגשת, ואילו יתרונות היא יכולה לתת למשתמש אם הוא יעניק לה את ההרשאה בתחילת ההפעלה. אחרי שהמשתמש מאשר שהוא הבין את הנימוק, ממשיכים לשלב הבא.
מבקשים את ההרשאה בזמן הריצה שהאפליקציה צריכה כדי לגשת לנתונים הפרטיים של המשתמש. המערכת מציגה בקשה להרשאה בזמן ריצה, כמו זו שמוצגת בדף סקירה כללית על הרשאות.
בודקים את התשובה של המשתמש – אם הוא בחר להעניק או לדחות את הרשאת זמן הריצה.
אם המשתמש העניק הרשאה לאפליקציה, היא תוכל לגשת לנתונים הפרטיים שלו. אם המשתמש דחה את ההרשאה, צריך לבצע הפחתה חיננית (graceful degradation) של חוויית השימוש באפליקציה ולשמור על הפונקציונליות שלא תלויה בנתונים שאין גישה אליהם.
איור 1 מציג את תהליך העבודה ואת קבוצת ההחלטות שקשורות לתהליך הזה:
בודקים אם האפליקציה כבר קיבלה את ההרשאה
כדי לבדוק אם המשתמש כבר נתן לאפליקציה הרשאה מסוימת, מעבירים את ההרשאה הזו לשיטה ContextCompat.checkSelfPermission(). השיטה הזו מחזירה את הערך PERMISSION_GRANTED או את הערך PERMISSION_DENIED, בהתאם להרשאה שיש לאפליקציה.
הסבר למה האפליקציה צריכה את ההרשאה
בתיבת הדו-שיח של ההרשאות שמוצגת על ידי המערכת כשמתקשרים
requestPermissions() מצוין איזו הרשאה האפליקציה רוצה, אבל לא מצוין למה. במקרים מסוימים, המשתמשים עשויים להתבלבל. מומלץ להסביר למשתמש למה האפליקציה מבקשת את ההרשאות לפני שמפעילים את requestPermissions().
מחקרים מראים שמשתמשים מרגישים הרבה יותר בנוח עם בקשות להרשאות אם הם יודעים למה האפליקציה צריכה אותן, למשל אם ההרשאה נדרשת לתמיכה בתכונת ליבה של האפליקציה או לפרסום. לכן, אם אתם משתמשים רק בחלק מקריאות ה-API שכלולות בקבוצת הרשאות, כדאי לציין במפורש באילו הרשאות אתם משתמשים ולמה. לדוגמה, אם אתם משתמשים רק במיקום משוער, עליכם לציין זאת בתיאור האפליקציה או במאמרי העזרה בנושא האפליקציה.
במקרים מסוימים, כדאי גם להודיע למשתמשים בזמן אמת על גישה לנתונים רגישים. לדוגמה, אם אתם ניגשים למצלמה או למיקרופון, כדאי להודיע על כך למשתמש באמצעות סמל התראה איפשהו באפליקציה או במגש ההתראות (אם האפליקציה פועלת ברקע), כדי שלא ייראה כאילו אתם אוספים נתונים בהיחבא.
בסופו של דבר, אם אתם צריכים לבקש הרשאה כדי שמשהו באפליקציה שלכם יפעל, אבל הסיבה לא ברורה למשתמש, אתם צריכים למצוא דרך להסביר למשתמש למה אתם צריכים את ההרשאות הרגישות ביותר.
אם השיטה ContextCompat.checkSelfPermission() מחזירה PERMISSION_DENIED, צריך להפעיל את shouldShowRequestPermissionRationale().
אם השיטה הזו מחזירה true, צריך להציג למשתמש ממשק משתמש עם הסבר. בממשק המשתמש הזה, צריך לתאר למה התכונה שהמשתמש רוצה להפעיל צריכה הרשאה מסוימת.
בנוסף, אם האפליקציה מבקשת הרשאה שקשורה למיקום, למיקרופון או למצלמה, כדאי להסביר למה האפליקציה צריכה גישה למידע הזה.
שליחת בקשה להרשאות
אחרי שהמשתמש צפה בממשק משתמש עם הסבר, או אם ערך ההחזרה של shouldShowRequestPermissionRationale() מציין שלא צריך להציג ממשק משתמש עם הסבר, מבקשים את ההרשאה. המשתמשים רואים תיבת דו-שיח של הרשאת מערכת, שבה הם יכולים לבחור אם להעניק לאפליקציה הרשאה מסוימת.
כדי לעשות זאת, משתמשים בחוזה RequestPermission, שכלול בספריית AndroidX, שבו מאפשרים למערכת לנהל את קוד בקשת ההרשאה בשבילכם. מומלץ להשתמש בחוזה RequestPermission כשאפשר, כי הוא מפשט את הלוגיקה. עם זאת, אם צריך, אפשר גם לנהל קוד בקשה בעצמכם כחלק מבקשת ההרשאה, ולכלול את קוד הבקשה הזה בלוגיקה של הקריאה החוזרת (callback) של ההרשאה.
ההגדרה הזו מאפשרת למערכת לנהל את קוד בקשת ההרשאה
כדי לאפשר למערכת לנהל את קוד הבקשה שמשויך לבקשת הרשאות, מוסיפים תלויות בספריות הבאות בקובץ build.gradle של המודול:
-
androidx.activity, גרסה 1.2.0 ואילך -
androidx.fragment, מגרסה 1.3.0 ואילך
אחר כך תוכלו להשתמש באחת מהמחלקות הבאות:
- כדי לבקש הרשאה אחת, משתמשים ב-
RequestPermission. - כדי לבקש כמה הרשאות בו-זמנית, משתמשים ב-
RequestMultiplePermissions.
בשלבים הבאים מוסבר איך להשתמש בחוזה RequestPermission. התהליך כמעט זהה לחוזה RequestMultiplePermissions.
בלוגיקה של הפעילות או של קטע הקוד, מעבירים הטמעה של
ActivityResultCallbackלקריאה אלregisterForActivityResult(). התגActivityResultCallbackמגדיר איך האפליקציה מטפלת בתשובת המשתמש לבקשת ההרשאה.שומרים הפניה לערך המוחזר של
registerForActivityResult(), שהוא מסוגActivityResultLauncher.כדי להציג את תיבת הדו-שיח של הרשאות המערכת כשצריך, מפעילים את השיטה
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 (רמת 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>
טיפול בדחיית הרשאה
אם המשתמש דוחה בקשת הרשאה, האפליקציה צריכה לעזור לו להבין את ההשלכות של דחיית ההרשאה. באופן ספציפי, האפליקציה צריכה להציג למשתמשים את התכונות שלא פועלות בגלל ההרשאה החסרה. כשעושים את זה, כדאי לזכור את השיטות המומלצות הבאות:
להפנות את תשומת הלב של המשתמש. צריך להדגיש חלק ספציפי בממשק המשתמש של האפליקציה שבו הפונקציונליות מוגבלת כי לאפליקציה אין את ההרשאה הנדרשת. דוגמאות לפעולות שאפשר לבצע:
- הצגת הודעה במקום שבו היו אמורים להופיע התוצאות או הנתונים של התכונה.
- הצגת לחצן אחר שמכיל סמל שגיאה וצבע.
חשוב להיות ספציפיים. לא להציג הודעה גנרית. במקום זאת, צריך להבהיר אילו תכונות לא זמינות כי לאפליקציה אין את ההרשאה הנדרשת.
אל תחסמו את ממשק המשתמש. במילים אחרות, אל תציגו הודעת אזהרה במסך מלא שמונעת מהמשתמשים להמשיך להשתמש באפליקציה שלכם בכלל.
במקביל, האפליקציה צריכה לכבד את ההחלטה של המשתמש לדחות בקשת הרשאה. החל מ-Android 11 (רמת API 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, אפשר לעבור אל דף ההפניה של ה-API להרשאות.
הרשאות חד-פעמיות
החל מ-Android 11 (רמת API 30), בכל פעם שהאפליקציה מבקשת הרשאה שקשורה למיקום, למיקרופון או למצלמה, תיבת הדו-שיח של ההרשאות שמוצגת למשתמש מכילה אפשרות שנקראת רק הפעם, כמו שמוצג באיור 2. אם המשתמש בוחר באפשרות הזו בתיבת הדו-שיח, האפליקציה מקבלת הרשאה זמנית חד-פעמית.
לאחר מכן, האפליקציה יכולה לגשת לנתונים הרלוונטיים למשך תקופה שתלויה בהתנהגות האפליקציה ובפעולות של המשתמש:
- בזמן שהפעילות באפליקציה גלויה, האפליקציה יכולה לגשת לנתונים.
- אם המשתמש מעביר את האפליקציה לרקע, היא יכולה להמשיך לגשת לנתונים למשך פרק זמן קצר.
- אם מפעילים שירות שפועל בחזית בזמן שהפעילות גלויה, ואז המשתמש מעביר את האפליקציה לרקע, האפליקציה יכולה להמשיך לגשת לנתונים עד שהשירות שפועל בחזית מפסיק.
תהליך האפליקציה מסתיים כשמבטלים את ההרשאה
אם המשתמש מבטל את ההרשאה החד-פעמית, למשל בהגדרות המערכת, האפליקציה לא יכולה לגשת לנתונים, גם אם הפעלתם שירות בחזית. כמו בכל הרשאה, אם המשתמש מבטל את ההרשאה החד-פעמית של האפליקציה, התהליך של האפליקציה מסתיים.
בפעם הבאה שהמשתמש יפתח את האפליקציה שלכם, ותכונה באפליקציה תבקש גישה למיקום, למיקרופון או למצלמה, תוצג למשתמש שוב בקשה להרשאה.
איפוס הרשאות שלא נעשה בהן שימוש
ב-Android יש כמה דרכים לאפס הרשאות זמן ריצה שלא נעשה בהן שימוש למצב ברירת המחדל שלהן, כלומר למצב 'נדחתה':
- API שבו אפשר להסיר באופן יזום את הגישה של האפליקציה להרשאת זמן ריצה שלא נעשה בה שימוש.
- מנגנון מערכת שמאפס אוטומטית את ההרשאות של אפליקציות שלא בשימוש.
הסרת הגישה לאפליקציה
ב-Android 13 (רמת API 33) ומעלה, אפשר להסיר את הגישה של האפליקציה להרשאות זמן ריצה שהאפליקציה כבר לא צריכה. כשמעדכנים את האפליקציה, חשוב לבצע את השלב הזה כדי שהמשתמשים יבינו למה האפליקציה ממשיכה לבקש הרשאות ספציפיות. הידע הזה עוזר לבנות אמון של המשתמשים באפליקציה שלכם.
כדי להסיר גישה להרשאת זמן ריצה, מעבירים את שם ההרשאה אל revokeSelfPermissionOnKill().
כדי להסיר גישה לקבוצת הרשאות בזמן ריצה בבת אחת, מעבירים אוסף של שמות הרשאות אל revokeSelfPermissionsOnKill().
תהליך הסרת ההרשאה מתבצע באופן אסינכרוני ומפסיק את כל התהליכים שמשויכים ל-UID של האפליקציה.
כדי שהמערכת תסיר את הגישה של האפליקציה להרשאות, צריך להפסיק את כל התהליכים שקשורים לאפליקציה. כשמבצעים קריאה ל-API, המערכת קובעת מתי בטוח להפסיק את התהליכים האלה. בדרך כלל, המערכת מחכה עד שהאפליקציה פועלת במשך תקופה ארוכה ברקע במקום בחזית.
כדי ליידע את המשתמש שהאפליקציה שלך כבר לא צריכה גישה להרשאות ספציפיות בתחילת ההפעלה, צריך להציג תיבת דו-שיח בפעם הבאה שהמשתמש מפעיל את האפליקציה. תיבת הדו-שיח יכולה לכלול את רשימת ההרשאות.
איפוס אוטומטי של הרשאות שניתנו לאפליקציות שלא היו בשימוש כבר הרבה זמן
אם האפליקציה שלכם מיועדת ל-Android 11 (רמת API 30) ומעלה, ולא נעשה בה שימוש במשך כמה חודשים, המערכת מגנה על נתוני המשתמשים על ידי איפוס אוטומטי של הרשאות זמן הריצה הרגישות שהמשתמש העניק לאפליקציה. מידע נוסף זמין במדריך בנושא העברה של אפליקציות למצב שינה.
אם צריך, שולחים בקשה להפוך ל-handler שמוגדר כברירת מחדל
יש אפליקציות שזקוקות לגישה למידע רגיש של משתמשים שקשור ליומני שיחות ולהודעות SMS. אם רוצים לבקש את ההרשאות שספציפיות ליומני שיחות ולהודעות SMS ולפרסם את האפליקציה בחנות Play, צריך להציג למשתמש בקשה להגדיר את האפליקציה כhandler שמוגדר כברירת מחדל לפונקציית מערכת מרכזית לפני שמבקשים את ההרשאות האלה בזמן הריצה.
למידע נוסף על גורמים מטפלים שמוגדרים כברירת מחדל, כולל הנחיות להצגת הנחיה למשתמשים לבחירת גורם מטפל שמוגדר כברירת מחדל, אפשר לעיין במדריך בנושא הרשאות שמשמשות רק בגורמים מטפלים שמוגדרים כברירת מחדל.
מתן כל ההרשאות בזמן הריצה למטרות בדיקה
כדי להעניק באופן אוטומטי את כל ההרשאות בזמן הריצה כשמתקינים אפליקציה באמולטור או במכשיר בדיקה, משתמשים באפשרות -g של הפקודה adb shell install, כמו שמוצג בקטע הקוד הבא:
adb shell install -g PATH_TO_APK_FILE
מקורות מידע נוספים
מידע נוסף על הרשאות זמין במאמרים הבאים:
אפשר גם להשלים את ה-codelab הזה שמציג שיטות מומלצות לשמירה על פרטיות.