Рабочие профили

Платформа Android позволяет устройствам иметь рабочие профили (иногда называемые управляемыми профилями). Рабочий профиль контролируется ИТ-администратором, а доступные ему функции задаются отдельно от функций основного профиля пользователя. Такой подход позволяет организациям контролировать среду, в которой на устройстве пользователя работают специфичные для компании приложения и данные, при этом позволяя пользователям использовать свои личные приложения и профили.

В этом уроке показано, как изменить приложение, чтобы оно надежно работало на устройстве с рабочим профилем. Вам не нужно делать ничего, кроме обычных рекомендаций по разработке приложений. Однако некоторые из этих рекомендаций становятся особенно важными на устройствах с рабочими профилями. В этом документе освещаются вопросы, о которых вам необходимо знать.

Обзор

Пользователи часто хотят использовать свои личные устройства в корпоративных условиях. Эта ситуация может поставить организации перед дилеммой. Если пользователь может использовать свое собственное устройство, организации следует беспокоиться о том, что конфиденциальная информация (например, электронные письма и контакты сотрудников) находится на устройстве, которое организация не контролирует.

Чтобы решить эту ситуацию, Android 5.0 (уровень API 21) позволяет организациям настраивать рабочие профили . Если на устройстве есть рабочий профиль, настройки профиля находятся под контролем ИТ-администратора. ИТ-администратор может выбирать, какие приложения разрешены для этого профиля, и контролировать, какие функции устройства доступны для этого профиля.

Если на устройстве есть рабочий профиль, это повлечет за собой последствия для приложений, работающих на устройстве, независимо от того, под каким профилем оно работает:

  • По умолчанию большинство намерений не переходят из одного профиля в другой. Если приложение, работающее в профиле, активирует намерение, в этом профиле нет обработчика намерения, и намерению не разрешено переходить в другой профиль из-за ограничений профиля, запрос завершается неудачно, и приложение может неожиданно завершить работу.
  • ИТ-администратор профиля может ограничить доступность системных приложений в рабочем профиле. Это ограничение также может привести к отсутствию обработчика некоторых общих целей в рабочем профиле.
  • Поскольку личный и рабочий профили имеют отдельные области хранения, URI файла, действительный для одного профиля, недействителен для другого. Любое намерение, запущенное в одном профиле, может быть обработано в другом (в зависимости от настроек профиля), поэтому прикреплять URI файлов к намерениям небезопасно.

Предотвращение неудачных намерений

На устройстве с рабочим профилем существуют ограничения на возможность пересечения намерений из одного профиля в другой. В большинстве случаев, когда намерение срабатывает, оно обрабатывается в том же профиле, где оно было сгенерировано. Если в этом профиле нет обработчика намерения, намерение не обрабатывается, и приложение, которое его инициировало, может неожиданно завершить работу, даже если в другом профиле есть обработчик намерения.

Администратор профиля может выбрать, каким намерениям разрешено переходить из одного профиля в другой. Поскольку это решение принимает ИТ-администратор, вы не можете заранее узнать , каким намерениям разрешено пересекать эту границу. ИТ-администратор устанавливает эту политику и может изменить ее в любое время.

Прежде чем ваше приложение начнет действовать, вы должны убедиться, что существует подходящее решение. Вы можете проверить наличие приемлемого разрешения, вызвав Intent.resolveActivity() . Если нет способа разрешить намерение, метод возвращает null . Если метод возвращает ненулевое значение, существует по крайней мере один способ разрешить намерение, и его можно безопасно отключить. В этом случае намерение может быть разрешимым либо потому, что в текущем профиле есть обработчик, либо потому, что намерению разрешено переходить к обработчику в другом профиле. (Дополнительную информацию о разрешении намерений см. в разделе Общие намерения .)

Например, если вашему приложению необходимо установить таймеры, ему необходимо будет проверить наличие допустимого обработчика для намерения ACTION_SET_TIMER . Если приложение не может разрешить намерение, оно должно предпринять соответствующее действие (например, отобразить сообщение об ошибке).

Котлин

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)

    }
}

Ява

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

    }
}

Делитесь файлами между профилями

Иногда приложению необходимо предоставить другим приложениям доступ к своим файлам. Например, приложение галереи изображений может захотеть поделиться своими изображениями с редакторами изображений. Обычно вы можете поделиться файлом двумя способами: с помощью URI файла или URI контента .

URI файла начинается с префикса file: за которым следует абсолютный путь к файлу в хранилище устройства. Однако поскольку рабочий профиль и личный профиль используют отдельные области хранения, URI файла, действительный для одного профиля, недействителен для другого. Эта ситуация означает, что если вы прикрепляете URI файла к намерению, а намерение обрабатывается в другом профиле, обработчик не сможет получить доступ к файлу.

Вместо этого вам следует делиться файлами с URI контента . URI контента идентифицируют файл более безопасным и общедоступным способом. URI содержимого содержит путь к файлу, а также центр, предоставляющий файл, и идентификационный номер, идентифицирующий файл. Вы можете создать идентификатор контента для любого файла с помощью FileProvider . Затем вы можете поделиться этим идентификатором контента с другими приложениями (даже в другом профиле). Получатель может использовать идентификатор контента, чтобы получить доступ к реальному файлу.

Например, вот как можно получить URI контента для URI конкретного файла:

Котлин

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

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

Ява

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

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

Когда вы вызываете метод getUriForFile() , вы должны указать полномочия поставщика файлов (в этом примере "com.example.myapp.fileprovider" ), которые указаны в элементе <provider> манифеста вашего приложения. Дополнительные сведения о совместном использовании файлов с помощью URI контента см. в разделе Общий доступ к файлам .

Слушайте уведомления

Приложение обычно предоставляет подкласс NotificationListenerService для получения обратных вызовов от системы об изменениях в уведомлениях. Устройства с рабочими профилями могут повлиять на работу NotificationListenerService с вашим приложением.

В рабочем профиле

Вы не можете использовать NotificationListenerService из приложения, работающего в рабочем профиле. Когда ваше приложение работает в рабочем профиле, система игнорирует NotificationListenerService вашего приложения. Однако приложения, работающие в личном профиле, могут прослушивать уведомления.

В личном профиле

Когда ваше приложение работает в личном профиле, вы можете не получать уведомления о приложениях, работающих в рабочем профиле. По умолчанию все приложения личного профиля получают обратные вызовы, но ИТ-администратор может внести в белый список одно или несколько приложений личного профиля, которым он разрешит прослушивать изменения уведомлений. Затем система блокирует приложения, не внесенные в белый список. В Android 8.0 (уровень API 26) или более поздней версии контроллер политики устройства (DPC), который управляет рабочим профилем, может заблокировать вашему приложению прослушивание уведомлений рабочего профиля с помощью метода DevicePolicyManager setPermittedCrossProfileNotificationListeners() . Ваше приложение по-прежнему получает обратные вызовы об уведомлениях, размещенных в личном профиле.

Проверьте свое приложение на совместимость с рабочими профилями

Вам следует протестировать свое приложение в среде рабочего профиля, чтобы выявить проблемы, которые могут привести к сбою вашего приложения на устройстве с рабочими профилями. В частности, тестирование на устройстве с рабочим профилем — это хороший способ убедиться, что ваше приложение правильно обрабатывает намерения: не активирует намерения, которые невозможно обработать, не прикрепляет URI, которые не работают в нескольких профилях, и т. д.

Мы предоставили образец приложения TestDPC , которое вы можете использовать для настройки рабочего профиля на устройстве Android под управлением Android 5.0 (уровень API 21) и выше. Это приложение предлагает вам простой способ протестировать ваше приложение в среде рабочего профиля. Вы также можете использовать это приложение для настройки рабочего профиля следующим образом:

  • Укажите, какие приложения по умолчанию доступны в управляемом профиле.
  • Настройте, каким намерениям разрешено переходить из одного профиля в другой.

Если вы вручную устанавливаете приложение через USB-кабель на устройство, имеющее рабочий профиль, приложение устанавливается как в личном, так и в рабочем профиле. После установки приложения вы можете протестировать его при следующих условиях:

  • Если намерение обычно обрабатывается приложением по умолчанию (например, приложением камеры), попробуйте отключить это приложение по умолчанию в рабочем профиле и убедитесь, что приложение обрабатывает это соответствующим образом.
  • Если вы запускаете намерение, ожидая, что оно будет обработано каким-либо другим приложением, попробуйте включить и отключить разрешение этого намерения на переход из одного профиля в другой. Убедитесь, что приложение работает правильно в обоих случаях. Если намерению не разрешено пересекать профили, проверьте поведение приложения, когда в профиле приложения есть подходящий обработчик, и когда его нет. Например, если ваше приложение запускает намерение, связанное с картой, попробуйте каждый из следующих сценариев:
    • Устройство позволяет переносить намерения карты из одного профиля в другой, а в другом профиле (профиле, в котором приложение не работает) имеется подходящий обработчик.
    • Устройство не позволяет намерениям карты пересекаться между профилями, но в профиле приложения есть подходящий обработчик.
    • Устройство не позволяет намерениям карты пересекаться между профилями, и в профиле устройства нет подходящего обработчика для намерений карты.
  • Если вы прикрепляете контент к намерению, убедитесь, что намерение работает правильно как при обработке в профиле приложения, так и при пересечении между профилями.

Тест по рабочим профилям: советы и рекомендации

Есть несколько приемов, которые могут оказаться полезными при тестировании на устройстве рабочего профиля.

  • Как уже отмечалось, когда вы загружаете приложение на устройство с рабочим профилем, оно устанавливается в оба профиля. При желании вы можете удалить приложение из одного профиля и оставить его в другом.
  • Большинство команд диспетчера активности, доступных в оболочке Android Debug Bridge (adb), поддерживают флаг --user , который позволяет указать, от имени какого пользователя запускать. Указав пользователя, вы можете выбрать, будет ли он работать в качестве неуправляемого основного пользователя или рабочего профиля. Для получения дополнительной информации см. Команды оболочки ADB .
  • Чтобы найти активных пользователей на устройстве, используйте команду list users менеджера пакетов adb. Первое число в выходной строке — это идентификатор пользователя, который можно использовать с флагом --user . Для получения дополнительной информации см. Команды оболочки ADB .

Например, чтобы найти пользователей на устройстве, вы должны выполнить следующую команду:

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

В этом случае основной пользователь («Дрю») имеет идентификатор пользователя 0, а рабочий профиль имеет идентификатор пользователя 10. Чтобы запустить приложение в рабочем профиле, вы должны использовать следующую команду:

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