כשמכשיר תומך במספר משתמשים, צריך להודיע לאפליקציות במכשיר על המשתמשים הנפרדים האלה.
באפליקציות מסוימות, חלק מהרכיבים צריכים לפעול כרכיבים יחידים (singletons) ולקבל בקשות מכל משתמש. בשלב הזה, רק אפליקציות מערכת יכולות להשתמש בתכונה הזו.
המתקן הזה:
- חיסכון במשאבים
- בוררות בין משתמשים לגבי משאב משותף אחד או יותר
- הפחתת העומס ברשת באמצעות חיבור לשרת יחיד
בתרשים הבא מתואר תהליך העברת ההרשאות עם כמה משתמשים.
איור 1. הרשאות של משתמשים מרובים
הפעלת רכיב יחיד (singleton)
כדי לזהות אפליקציה כ-singleton, מוסיפים את הערך android:singleUser="true"
לשירות, למקלט או לספק במניפסט של Android.
המערכת יוצרת מופע של הרכיב הזה בתהליך שפועל בתור משתמש 0 בלבד. כל בקשה של משתמש כלשהו להתחבר לספק או לשירות הזה, או לשדר למכשיר המקלט הזה, מנותבת לתהליך במשתמש 0. אם זהו הרכיב היחיד באפליקציה, רק מופע אחד של האפליקציה פועל.
הפעילויות בחבילה עדיין מופעלות בתהליך נפרד לכל משתמש, וה-UID נמצא בטווח ה-UID של המשתמש הזה (למשל 1010034).
אינטראקציה עם משתמשים
הגדר הרשאות
נדרשות ההרשאות הבאות:
INTERACT_ACROSS_USERS (signature|system) INTERACT_ACROSS_USERS_FULL (signature)
שימוש בממשקי API
אתם יכולים להשתמש בממשקי ה-API הבאים כדי לאפשר לאפליקציות לזהות כמה משתמשים.
- חילוץ הכינוי של המשתמש מהקריאות הנכנסות של Binder:
int userHandle = UserHandle.getCallingUserId()
- שימוש בממשקי API חדשים ומוגנים כדי להפעיל שירותים, פעילויות ושידור של משתמש ספציפי:
Context.startActivityAsUser(Intent, UserHandle)
Context.bindServiceAsUser(Intent, …, UserHandle)
Context.sendBroadcastAsUser(Intent, … , UserHandle)
Context.startServiceAsUser(Intent, …, UserHandle)
UserHandle
יכול להיות משתמש מפורש או אחד מהכינויים המיוחדים:UserHandle.CURRENT
אוUserHandle.ALL
.CURRENT
מציין את המשתמש שנמצא כרגע בחזית. משתמשים ב-ALL
כשרוצים לשדר לכל המשתמשים. - לתקשר עם רכיבים באפליקציה שלכם:
(INTERACT_ACROSS_USERS)
או עם רכיבים באפליקציות אחרות:(INTERACT_ACROSS_USERS_FULL)
- יכול להיות שתצטרכו ליצור רכיבי proxy שפועלים בתהליך של המשתמש, ואז ניגשים לרכיב
singleUser
במשתמש 0. - שולחים שאילתה על משתמשים ועל הכינויים שלהם באמצעות שירות המערכת החדש
UserManager
:UserManager.getUsers()
UserManager.getUserInfo()
UserManager.supportsMultipleUsers()
UserManager.getUserSerialNumber(int userHandle)
– מספר שלא עובר מיחזור ותואם לכינוי משתמש.UserManager.getUserHandle(int serialNumber)
UserManager.getUserProfiles()
– מחזירה את האוסף של הפרופילים שלכם ושל הפרופילים המנוהלים, אם יש כאלה.
- הרשמה להאזנה למשתמשים ספציפיים או לכל המשתמשים ולקריאות החזרה (callbacks) באמצעות ממשקי API חדשים ב-ContentObserver, PackageMonitor ו-BroadcastReceiver, שמספקים מידע נוסף על המשתמש שגרם לקריאה החוזרת.
שירותים בכמה משתמשים או פרופילים
לא כל השירותים צריכים להריץ מכונה בפרופיל משתמש או בפרופיל עבודה אחר. אם שירות המערכת צריך לפעול רק בתור משתמש 0, כדי לחסוך במשאבים, משביתים את הרכיבים של השירות כשהם פועלים בתור משתמשים אחרים. בדוגמה הבאה אפשר לראות איך לעשות זאת בנקודות הכניסה של השירות:
// Add on all entry points such as boot_completed or other manifest-listed receivers and providers if (!UserManager.isSystemUser()) { // Disable the service ComponentName targetServiceName = new ComponentName(this, TargetService.class); context.getPackageManager().setComponentEnabledSetting( targetServiceName, COMPONENT_ENABLED_STATE_DISABLED, 0); }
אפשר גם להשתמש ב-PackageManager.setApplicationEnabledSetting()
כדי להשבית את האפליקציה כולה.