Profili di lavoro

La piattaforma Android consente ai dispositivi di avere profili di lavoro (talvolta chiamati profili gestiti). Un profilo di lavoro è controllato da un amministratore IT e la funzionalità disponibile è impostata separatamente da quelle del profilo principale dell'utente. Questo approccio consente alle organizzazioni di controllare l'ambiente in cui le app e i dati specifici dell'azienda vengono eseguiti sul dispositivo di un utente, permettendo comunque agli utenti di utilizzare i propri profili e app personali.

Questa lezione spiega come modificare l'applicazione in modo che funzioni in modo affidabile su un dispositivo con un profilo di lavoro. Non devi fare altro oltre alle normali best practice per lo sviluppo di app. Tuttavia, alcune di queste best practice diventano particolarmente importanti sui dispositivi con profili di lavoro. Questo documento evidenzia i problemi di cui devi essere a conoscenza.

Panoramica

Gli utenti spesso preferiscono utilizzare i propri dispositivi personali in un ambiente aziendale. Questa situazione può porre un dilemma alle organizzazioni. Se l'utente può utilizzare il proprio dispositivo, l'organizzazione deve preoccuparsi che le informazioni riservate (come email e contatti dei dipendenti) siano su un dispositivo che non è sotto il controllo dell'organizzazione.

Per far fronte a questa situazione, Android 5.0 (livello API 21) consente alle organizzazioni di configurare i profili di lavoro. Se su un dispositivo è presente un profilo di lavoro, le impostazioni del profilo sono sotto il controllo dell'amministratore IT. L'amministratore IT può scegliere quali app consentire per il profilo e controllare solo quali funzionalità del dispositivo sono disponibili per il profilo.

Se un dispositivo ha un profilo di lavoro, ci sono implicazioni per le app in esecuzione sul dispositivo, indipendentemente dal profilo con cui viene eseguita l'app:

  • Per impostazione predefinita, la maggior parte degli intent non si incrocia da un profilo all'altro. Se un'app in esecuzione sul profilo attiva un intent, non esiste un gestore per l'intent in quel profilo e quest'ultimo non può passare all'altro profilo a causa delle limitazioni del profilo, la richiesta non va a buon fine e l'app potrebbe arrestarsi inaspettatamente.
  • L'amministratore IT del profilo può limitare le app di sistema disponibili nel profilo di lavoro. Questa limitazione può anche comportare l'assenza di gestori per alcuni intent comuni nel profilo di lavoro.
  • Poiché i profili personale e di lavoro hanno aree di archiviazione separate, l'URI del file valido in un profilo non lo è nell'altro. Qualsiasi intent attivato su un profilo potrebbe essere gestito nell'altro (a seconda delle impostazioni del profilo), pertanto non è sicuro allegare gli URI dei file agli intent.

Prevenzione degli intent non riusciti

Su un dispositivo con un profilo di lavoro sono previste limitazioni relative alla possibilità di trasferire gli intent da un profilo all'altro. Nella maggior parte dei casi, quando un intent viene attivato, viene gestito nello stesso profilo in cui viene attivato. Se non esiste un gestore per l'intent in quel profilo, l'intent non viene gestito e l'app che lo ha attivato potrebbe arrestarsi in modo imprevisto, anche se esiste un gestore per l'intent sull'altro profilo.

L'amministratore del profilo può scegliere quali intent consentire di passare da un profilo all'altro. Poiché questa decisione viene presa dall'amministratore IT, non c'è modo di sapere in anticipo quali intent sono consentiti per superare questo confine. L'amministratore IT imposta questo criterio e può modificarlo in qualsiasi momento.

Prima di avviare un'attività con l'app, devi verificare che esista una risoluzione adatta. Puoi verificare che esista una risoluzione accettabile chiamando il numero Intent.resolveActivity(). Se non è possibile risolvere l'intent, il metodo restituisce null. Se il metodo restituisce un valore non null, esiste almeno un modo per risolvere l'intent ed è sicuro attivarlo. In questo caso, l'intent potrebbe essere risolvibile perché nel profilo corrente è presente un gestore o perché l'intent può passare a un gestore sull'altro profilo. Per ulteriori informazioni sulla risoluzione degli intent, consulta Intent comuni.

Ad esempio, se l'app deve impostare timer, deve verificare che esista un gestore valido per l'intent ACTION_SET_TIMER. Se l'app non è in grado di risolvere l'intent, dovrebbe adottare un'azione appropriata (ad esempio, mostrare un messaggio di errore).

Kotlin

fun startTimer(message: String, seconds: Int) {

    // Build the "set timer" intent
    val timerIntent = Intent(AlarmClock.ACTION_SET_TIMER).apply {
        putExtra(AlarmClock.EXTRA_MESSAGE, message)
        putExtra(AlarmClock.EXTRA_LENGTH, seconds)
        putExtra(AlarmClock.EXTRA_SKIP_UI, true)
    }

    // Check if there's a handler for the intent
    if (timerIntent.resolveActivity(packageManager) == null) {

        // Can't resolve the intent! Fail this operation cleanly
        // (perhaps by showing an error message)

    } else {
        // Intent resolves, it's safe to fire it off
        startActivity(timerIntent)

    }
}

Java

public void startTimer(String message, int seconds) {

    // Build the "set timer" intent
    Intent timerIntent = new Intent(AlarmClock.ACTION_SET_TIMER)
            .putExtra(AlarmClock.EXTRA_MESSAGE, message)
            .putExtra(AlarmClock.EXTRA_LENGTH, seconds)
            .putExtra(AlarmClock.EXTRA_SKIP_UI, true);

    // Check if there's a handler for the intent
    if (timerIntent.resolveActivity(getPackageManager()) == null) {

        // Can't resolve the intent! Fail this operation cleanly
        // (perhaps by showing an error message)

    } else {
        // Intent resolves, it's safe to fire it off
        startActivity(timerIntent);

    }
}

Condividere file tra profili

A volte un'app deve fornire ad altre app l'accesso ai propri file. Ad esempio, un'app Galleria immagini potrebbe voler condividere le immagini con gli editor di immagini. In genere, esistono due modi per condividere un file: con un URI del file o con un URI di contenuto.

L'URI del file inizia con il prefisso file:, seguito dal percorso assoluto del file nello spazio di archiviazione del dispositivo. Tuttavia, poiché il profilo di lavoro e il profilo personale utilizzano aree di archiviazione separate, l'URI di un file valido in un profilo non è valido nell'altro. Questa situazione significa che se alleghi l'URI di un file a un intent, che viene gestito nell'altro profilo, il gestore non sarà in grado di accedere al file.

Invece, devi condividere i file con URI di contenuti. Gli URI di contenuto identificano il file in un modo più sicuro e condivisibile. L'URI dei contenuti contiene il percorso del file, ma anche l'autorità che fornisce il file e un numero ID che identifica il file. Puoi generare un ID contenuti per qualsiasi file utilizzando un FileProvider. Puoi quindi condividere questo ID con altre app (anche sull'altro profilo). Il destinatario può utilizzare Content ID per accedere al file effettivo.

Ad esempio, ecco come ottenere l'URI dei contenuti per un URI di file specifico:

Kotlin

// Open File object from its file URI
val fileToShare = File(fileUriToShare)

val contentUriToShare: Uri = FileProvider.getUriForFile(
        context,
        "com.example.myapp.fileprovider",
        fileToShare
)

Java

// Open File object from its file URI
File fileToShare = new File(fileUriToShare);

Uri contentUriToShare = FileProvider.getUriForFile(getContext(),
        "com.example.myapp.fileprovider", fileToShare);

Quando chiami il metodo getUriForFile(), devi includere l'autorità del provider del file (in questo esempio, "com.example.myapp.fileprovider"), che è specificata nell'elemento <provider> del file manifest dell'app. Per ulteriori informazioni sulla condivisione di file con URI di contenuti, consulta Condivisione di file.

Ascoltare le notifiche

In genere, un'app fornisce una sottoclasse NotificationListenerService per ricevere i callback dal sistema relativi alle modifiche alle notifiche. I dispositivi con profili di lavoro potrebbero influire sul funzionamento di NotificationListenerService con la tua app.

In un profilo di lavoro

Non puoi utilizzare un NotificationListenerService da un'app in esecuzione nel profilo di lavoro. Quando l'app è in esecuzione in un profilo di lavoro, il sistema ignora NotificationListenerService dell'app. Tuttavia, le app in esecuzione nel profilo personale possono ascoltare le notifiche.

In un profilo personale

Quando la tua app viene eseguita nel profilo personale, potresti non ricevere notifiche per le app in esecuzione nel profilo di lavoro. Per impostazione predefinita, tutte le app del profilo personale ricevono callback, ma un amministratore IT può inserire nella lista consentita una o più app del profilo personale a cui consente di ascoltare le modifiche alle notifiche. Il sistema poi blocca le app non incluse nella lista consentita. In Android 8.0 (livello API 26) o versioni successive, un controller dei criteri dei dispositivi (DPC) che gestisce un profilo di lavoro potrebbe impedire alla tua app di ascoltare le notifiche del profilo di lavoro utilizzando il DevicePolicyManagermetodo setPermittedCrossProfileNotificationListeners(). L'app continua a ricevere callback per le notifiche pubblicate nel profilo personale.

Testa la compatibilità dell'app con i profili di lavoro

Dovresti testare la tua app in un ambiente con profilo di lavoro per individuare problemi che potrebbero comprometterne l'esecuzione su un dispositivo con profili di lavoro. In particolare, eseguire test su un dispositivo del profilo di lavoro è un buon modo per assicurarsi che l'app gestisca correttamente gli intent: non attivare intent che non possono essere gestiti, non collegare URI che non funzionano in più profili e così via.

Abbiamo fornito un'app di esempio, TestDPC, che puoi utilizzare per configurare un profilo di lavoro su un dispositivo Android con Android 5.0 (livello API 21) e versioni successive. Questa app offre un modo semplice per testarla in un ambiente con profilo di lavoro. Puoi anche utilizzare questa app per configurare il profilo di lavoro nel seguente modo:

  • Specifica quali app predefinite sono disponibili nel profilo gestito
  • Configura quali intent sono consentiti passando da un profilo all'altro

Se installi manualmente un'app tramite cavo USB su un dispositivo con un profilo di lavoro, l'app viene installata sia sul profilo personale che su quello di lavoro. Dopo aver installato l'app, puoi testarla alle seguenti condizioni:

  • Se un intent in genere viene gestito da un'app predefinita (ad esempio, l'app Fotocamera), prova a disattivare l'app predefinita sul profilo di lavoro e verifica che l'app gestisca questa operazione in modo appropriato.
  • Se attivi un intent pensando che venga gestito da un'altra app, prova ad attivare e disattivare l'autorizzazione dell'intent a passare da un profilo all'altro. Verifica che l'app funzioni correttamente in entrambe le circostanze. Se l'intent non è autorizzato a passare da un profilo all'altro, verifica il comportamento dell'app sia quando esiste un gestore adatto nel profilo dell'app, sia quando non c'è. Ad esempio, se la tua app attiva un intent relativo alla mappa, prova ognuno dei seguenti scenari:
    • Il dispositivo consente il passaggio degli intent della mappa da un profilo all'altro ed è presente un gestore adatto sull'altro profilo (il profilo su cui non è in esecuzione l'app)
    • Il dispositivo non consente che gli intent della mappa passino da un profilo all'altro, ma esiste un gestore adatto nel profilo dell'app
    • Il dispositivo non consente l'attraversamento di intent della mappa da un profilo all'altro e non esiste un gestore adatto per intent della mappa nel profilo del dispositivo
  • Se alleghi contenuti a un intent, verifica che quest'ultimo funzioni correttamente sia quando viene gestito nel profilo dell'app sia quando passa da un profilo all'altro.

Testare i profili di lavoro: suggerimenti utili

Esistono alcuni trucchi che potresti trovare utili per eseguire test su un dispositivo con profilo di lavoro.

  • Come indicato, quando esegui il sideload di un'app su un dispositivo del profilo di lavoro, l'app viene installata su entrambi i profili. Se vuoi, puoi eliminare l'app da un profilo e lasciarla nell'altro.
  • La maggior parte dei comandi di Activity Manager disponibili nella shell di Android Debug Bridge (adb) supporta il flag --user, che consente di specificare l'utente da eseguire. Specificando un utente, puoi scegliere se eseguirlo come utente principale non gestito o profilo di lavoro. Per ulteriori informazioni, vedi Comandi shell ADB.
  • Per trovare gli utenti attivi su un dispositivo, utilizza il comando list users del gestore di pacchetti adb. Il primo numero nella stringa di output è l'ID utente, che puoi utilizzare con il flag --user. Per ulteriori informazioni, consulta Comandi di Shell ADB.

Ad esempio, per trovare gli utenti su un dispositivo, devi eseguire questo comando:

$ adb shell pm list users
UserInfo{0:Drew:13} running
UserInfo{10:Work profile:30} running

In questo caso, l'utente principale("Drew") ha l'ID utente 0 e l'ID utente del profilo di lavoro è 10. Per eseguire un'app nel profilo di lavoro, utilizza un comando come questo:

$ adb shell am start --user 10 \
-n "com.example.myapp/com.example.myapp.testactivity" \
-a android.intent.action.MAIN -c android.intent.category.LAUNCHER