建構可辨識多用戶的應用程式

如果裝置支援多位使用者,則其應用程式必須瞭解這些不同的使用者。

某些應用程式需要讓部分元件以單例模式執行,並可接受來自任何使用者的請求。目前只有系統應用程式可以使用這項功能。

這項設施:

  • 節省資源
  • 為多位使用者仲裁一或多個共用資源
  • 使用單一伺服器連線可減少網路支出

請參閱下方圖表,瞭解多位使用者的權限流程。

多位使用者權限流程

圖 1. 多位使用者權限

啟用單例元件

如要將應用程式視為單例,請在 Android 資訊清單中將 android:singleUser="true" 新增至服務、接收器或提供者。

系統只會在以使用者 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() 停用整個應用程式。