Creare app che supportano più utenti

Quando un dispositivo supporta più utenti, le sue app devono essere consapevoli di questi utenti distinti.

Per alcune app è necessario che alcuni componenti vengano eseguiti come oggetti singoli e possano accettare richieste da qualsiasi utente. Al momento, solo le app di sistema possono utilizzare questa funzionalità.

Questa struttura:

  • Risparmia risorse
  • Gestisce una o più risorse condivise tra gli utenti
  • Riduce l'overhead della rete utilizzando una singola connessione al server

Consulta il diagramma seguente per una rappresentazione del flusso di autorizzazioni con più utenti.

Flusso di autorizzazioni per più utenti

Figura 1. Autorizzazioni per più utenti

Attivare un componente singleton

Per identificare un'app come singleton, aggiungi android:singleUser="true" al servizio, al ricevitore o al provider nel file manifest di Android.

Il sistema esegue l'inizializzazione del componente nel processo in esecuzione solo come utente 0. Eventuali richieste di connessione a quel fornitore o servizio o di trasmissione a quel ricevitore da parte di qualsiasi utente vengono inoltrate al processo nell'utente 0. Se questo è l'unico componente dell'app, viene eseguita solo un'istanza dell'app.

Le attività nel pacchetto vengono comunque avviate in un processo separato per ciascun utente, con l'UID che rientra nell'intervallo UID dell'utente (ad esempio 1010034).

Interagire con gli utenti

Imposta autorizzazioni

Sono richieste le seguenti autorizzazioni:

INTERACT_ACROSS_USERS (signature|system)
INTERACT_ACROSS_USERS_FULL (signature)

Utilizzare le API

Utilizza le seguenti API per rendere le app consapevoli della presenza di più utenti.

  1. Estrai l'handle utente dalle chiamate Binder in arrivo:
    • int userHandle = UserHandle.getCallingUserId()
  2. Utilizza nuove API protette per avviare servizi, attività e trasmissioni su un utente specifico:
    • Context.startActivityAsUser(Intent, UserHandle)
    • Context.bindServiceAsUser(Intent, …, UserHandle)
    • Context.sendBroadcastAsUser(Intent, … , UserHandle)
    • Context.startServiceAsUser(Intent, …, UserHandle)
    UserHandle può essere un utente esplicito o uno degli handle speciali: UserHandle.CURRENT o UserHandle.ALL. CURRENT indica l'utente attualmente in primo piano. Utilizza ALL quando vuoi inviare una trasmissione a tutti gli utenti.
  3. Comunica con i componenti della tua app: (INTERACT_ACROSS_USERS) O con i componenti di altre app: (INTERACT_ACROSS_USERS_FULL)
  4. Potresti dover creare componenti proxy che vengono eseguiti nel processo dell'utente e poi accedono al componente singleUser nell'utente 0.
  5. Esegui query sugli utenti e sui relativi handle con il nuovo servizio di sistema UserManager:
    • UserManager.getUsers()
    • UserManager.getUserInfo()
    • UserManager.supportsMultipleUsers()
    • UserManager.getUserSerialNumber(int userHandle): un numero non riciclato che corrisponde a un handle utente.
    • UserManager.getUserHandle(int serialNumber)
    • UserManager.getUserProfiles(): restituisce la raccolta di profili personali e gestiti, se presenti.
  6. Registrati per ascoltare utenti specifici o tutti gli utenti e i rilanci con nuove API su ContentObserver, PackageMonitor, BroadcastReceiver che forniscono informazioni aggiuntive su quale utente ha causato il richiamo.

Servizi in più utenti o profili

Non tutti i servizi devono eseguire un'istanza in un altro utente o profilo di lavoro. Se il servizio di sistema deve essere eseguito solo come utente 0, disattiva i componenti del servizio quando viene eseguito da altri utenti per contribuire a preservare le risorse. L'esempio seguente mostra come eseguire questa operazione nei punti di accesso del servizio:

// 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);
}

L'esempio potrebbe anche utilizzare PackageManager.setApplicationEnabledSetting() per disattivare l'intera app.