建立多用戶感知的應用程式

當設備支援多個用戶時,其應用程式必須了解這些不同的用戶。

某些應用程式需要某些元件作為單例運行,並且可以接受來自任何使用者的請求。目前只有系統應用程式可以使用此功能。

該設施:

  • 節約資源
  • 仲裁用戶之間的一個或多個共享資源
  • 透過使用單一伺服器連線減少網路開銷

請參閱下圖,以了解多個使用者的權限流的描述。

多用戶權限流程

圖 1.多用戶權限

啟用單例元件

若要將應用程式標識為單例,請將android:singleUser="true"新增至 Android 清單中的服務、接收器或提供者。

系統將在僅以使用者 0 身分運行的進程中實例化該元件。來自任何使用者的任何連接到該提供者或服務或廣播到該接收器的請求都會被路由到使用者0 中的進程。如果這是您的應用程式中的唯一元件,則只會執行您的應用程式程式的一個實例。

套件中的活動仍將在每個使用者的單獨進程中啟動,且 UID 位於該使用者的 UID 範圍內(例如 1010034)。

與用戶互動

設定權限

需要這些權限

INTERACT_ACROSS_USERS (signature|system)
INTERACT_ACROSS_USERS_FULL (signature)

使用API

使用以下 API 使應用程式能夠識別多個使用者。

  1. 從傳入的 Binder 呼叫中提取使用者句柄:
    • int userHandle = UserHandle.getCallingUserId()
  2. 使用新的、受保護的 API 來啟動特定使用者的服務、活動和廣播:
    • Context.startActivityAsUser(Intent, UserHandle)
    • Context.bindServiceAsUser(Intent, …, UserHandle)
    • Context.sendBroadcastAsUser(Intent, … , UserHandle)
    • Context.startServiceAsUser(Intent, …, UserHandle)
    UserHandle可以是明確使用者或特殊句柄之一: UserHandle.CURRENTUserHandle.ALLCURRENT表示目前位於前台的使用者。當您想要向所有使用者發送廣播時,請使用ALL
  3. 與您自己的應用程式中的元件通訊: (INTERACT_ACROSS_USERS)或與其他應用程式中的元件通訊: (INTERACT_ACROSS_USERS_FULL)
  4. 您可能需要建立在使用者程序中執行的代理元件,然後存取使用者 0 中的singleUser元件。
  5. 使用新的UserManager系統服務查詢使用者及其句柄:
    • UserManager.getUsers()
    • UserManager.getUserInfo()
    • UserManager.supportsMultipleUsers()
    • UserManager.getUserSerialNumber(int userHandle) - 與使用者句柄對應的非回收編號。
    • UserManager.getUserHandle(int serialNumber)
    • UserManager.getUserProfiles() - 傳回自身和託管設定檔的集合(如果有)。
  6. 註冊以監聽特定或所有使用者以及 ContentObserver、PackageMonitor、BroadcastReceiver 上新 API 的回調,這些 API 提供有關哪個使用者引起回呼的附加資訊。

多個使用者或設定檔中的服務

並非所有服務都需要在另一個使用者或工作設定檔中執行實例。如果您的系統服務只需以使用者 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()來停用整個應用程式。