החל מ-27 במרץ 2025, מומלץ להשתמש ב-android-latest-release
במקום ב-aosp-main
כדי ליצור תרומות ל-AOSP. מידע נוסף זמין במאמר שינויים ב-AOSP.
פיתוח אפליקציות שמותאמות למספר משתמשים
קל לארגן דפים בעזרת אוספים
אפשר לשמור ולסווג תוכן על סמך ההעדפות שלך.
כשמכשיר תומך במספר משתמשים, צריך להודיע לאפליקציות במכשיר על המשתמשים הנפרדים האלה.
באפליקציות מסוימות, חלק מהרכיבים צריכים לפעול כרכיבים יחידים (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()
כדי להשבית את האפליקציה כולה.
דוגמאות התוכן והקוד שבדף הזה כפופות לרישיונות המפורטים בקטע רישיון לתוכן. Java ו-OpenJDK הם סימנים מסחריים או סימנים מסחריים רשומים של חברת Oracle ו/או של השותפים העצמאיים שלה.
עדכון אחרון: 2025-07-27 (שעון UTC).
[[["התוכן קל להבנה","easyToUnderstand","thumb-up"],["התוכן עזר לי לפתור בעיה","solvedMyProblem","thumb-up"],["סיבה אחרת","otherUp","thumb-up"]],[["חסרים לי מידע או פרטים","missingTheInformationINeed","thumb-down"],["התוכן מורכב מדי או עם יותר מדי שלבים","tooComplicatedTooManySteps","thumb-down"],["התוכן לא עדכני","outOfDate","thumb-down"],["בעיה בתרגום","translationIssue","thumb-down"],["בעיה בדוגמאות/בקוד","samplesCodeIssue","thumb-down"],["סיבה אחרת","otherDown","thumb-down"]],["עדכון אחרון: 2025-07-27 (שעון UTC)."],[],[],null,["# Build multiuser-aware apps\n\nWhen a device supports [multiple users](/docs/devices/admin/multi-user), its apps must be\nmade aware of these distinct users.\n\nCertain apps need to have some components run as singletons and can accept\nrequests from any user. Only system apps can currently use this feature.\n\nThis facility:\n\n- Conserves resources\n- Arbitrates one or more shared resources across users\n- Reduces network overhead by using a single server connection\n\nSee the diagram below for a depiction of permissions flow with multiple users.\n\n\n**Figure 1.** Multiple users permissions\n\nEnable a singleton component\n----------------------------\n\nTo identify an app as a singleton, add `android:singleUser=\"true\"` to your service,\nreceiver, or provider in the Android manifest.\n\nThe system instantiates that component in the process running as user 0\nonly. Any requests to connect to that provider or service, or to broadcast to that receiver, from\nany user is routed to the process in user 0. If this is the only component in your app,\nonly one instance of your app runs.\n\nActivities in your package are still launched in a separate process for\neach user, with the UID being in the UID range for that user (such as 1010034).\n\nInteract with users\n-------------------\n\n### Set permissions\n\nThese permissions are required: \n\n```\nINTERACT_ACROSS_USERS (signature|system)\nINTERACT_ACROSS_USERS_FULL (signature)\n```\n\n### Employ APIs\n\nUse the following APIs to make apps aware of multiple users.\n\n1. Extract the user handle from incoming Binder calls:\n - `int userHandle = UserHandle.getCallingUserId()`\n2. Use new, protected APIs to start services, activities, broadcasts on a specific user:\n - `Context.startActivityAsUser(Intent, UserHandle)`\n - `Context.bindServiceAsUser(Intent, ..., UserHandle)`\n - `Context.sendBroadcastAsUser(Intent, ... , UserHandle)`\n - `Context.startServiceAsUser(Intent, ..., UserHandle)`\n\n `UserHandle` can be an explicit user or one of the special handles: `UserHandle.CURRENT` or `UserHandle.ALL`. `CURRENT` indicates the user that is currently in the foreground. Use `ALL` when you want to send a broadcast to all users.\n3. Communicate with components in your own app: `(INTERACT_ACROSS_USERS)` Or with components in other apps: `(INTERACT_ACROSS_USERS_FULL)`\n4. You might need to create proxy components that run in the user's process that then access the `singleUser` component in user 0.\n5. Query users and their handles with the new `UserManager` system service:\n - `UserManager.getUsers()`\n - `UserManager.getUserInfo()`\n - `UserManager.supportsMultipleUsers()`\n - `UserManager.getUserSerialNumber(int userHandle)` - a nonrecycled number that corresponds to a user handle.\n - `UserManager.getUserHandle(int serialNumber)`\n - `UserManager.getUserProfiles()` - returns the collection of self and managed profiles, if any.\n6. Register to listen to specific or all users and the callbacks with new APIs on ContentObserver, PackageMonitor, BroadcastReceiver that provide additional information about which user has caused the callback.\n\n### Services in multiple users or profiles\n\nNot all services need to run an instance in another user or work profile. If your system service\nonly needs to run as user 0, disable the service's components when running under other users to\nhelp preserve resources. The following example shows how you might do this at your service's entry\npoints: \n\n```\n// Add on all entry points such as boot_completed or other manifest-listed receivers and providers\nif (!UserManager.isSystemUser()) {\n // Disable the service\n ComponentName targetServiceName = new ComponentName(this, TargetService.class);\n context.getPackageManager().setComponentEnabledSetting(\n targetServiceName, COMPONENT_ENABLED_STATE_DISABLED, 0);\n}\n```\n\nThe example could also use `PackageManager.setApplicationEnabledSetting()` to disable\nthe entire app."]]