Функция ролей приложений позволяет системному администратору предоставлять особые права управляемому приложению на устройстве Android. Приложение с определенной ролью может быть освобождено от ограничений на энергопотребление и фоновую активность, приостановки и перевода в спящий режим (в Android 14 и более поздних версиях). Кроме того, для него могут быть отключены элементы управления пользователя, например принудительная остановка и очистка данных приложения (в Android 11 и более поздних версиях). Это позволяет приложению выполнять свои основные функции без перебоев. Кроме того, приложение может получать уведомления о назначенных ему ролях, что позволяет ему выполнять самонастройку без вмешательства пользователя.
Список доступных ролей приложения и особых прав, предоставляемых каждой роли, приведен в статье RoleType.
Требования
Устройство управляется EMM-решением на основе AMAPI (EMM-решения, использующие собственный контроллер политики устройств, не поддерживаются).
Подготовьте приложение к использованию функции
Интеграция с AMAPI SDK требуется, только если приложение должно получать уведомления о назначенных ему ролях, чтобы запускаться автоматически без участия пользователя.
Интегрируйте AMAPI SDK в свое приложение
Подробную информацию об AMAPI SDK и о том, как добавить его в приложение, можно найти в руководстве по интеграции AMAPI SDK.
Добавьте необходимые метаданные в манифест приложения
Приложению Android Device Policy (ADP) необходимо знать ComponentName вашего класса, который реализует NotificationReceiverService, чтобы уведомлять ваше приложение о назначенных ему ролях. Вам необходимо добавить в AndroidManifest.xml тег, чтобы ADP мог автоматически обнаружить ваш сервис.
- В приложении должен быть только один сервис
enabled, у которого естьmeta-dataсandroid:name, равнымcom.google.android.managementapi.notification.NotificationReceiverService.SERVICE_APP_ROLES. - Для этого сервиса необходимо задать значение
trueдля параметраandroid:exported. - Для свойства
android:valueобъектаmeta-dataдолжна быть задана пустая строка.
<service
android:name=".MyNotificationReceiverService"
android:exported="true">
<meta-data android:name="com.google.android.managementapi.notification.NotificationReceiverService.SERVICE_APP_ROLES" android:value="" />
</service>
Если вы тестируете роль COMPANION_APP, добавьте в сервис следующий элемент meta-data, чтобы приложение Android Device Policy могло отправлять в ваше приложение обновления статуса локальных команд:
<meta-data android:name="com.google.android.managementapi.notification.NotificationReceiverService.SERVICE_COMMAND_STATUS" android:value="" />
Создайте сервис, расширяющий NotificationReceiverService (или обновите существующий).
Создайте или обновите существующий класс NotificationReceiverService и реализуйте AppRolesListener, чтобы отслеживать роли, назначенные вашему приложению. Для этого требуется только getAppRolesListener(). Если вашему приложению назначена роль COMPANION_APP, вам также следует реализовать getCommandListener():
import android.util.Log
import com.google.android.managementapi.approles.AppRolesListener
import com.google.android.managementapi.approles.model.AppRolesSetRequest
import com.google.android.managementapi.approles.model.AppRolesSetResponse
import com.google.android.managementapi.commands.CommandListener
import com.google.android.managementapi.commands.model.Command
import com.google.android.managementapi.notification.NotificationReceiverService
class MyNotificationReceiverService : NotificationReceiverService() {
// If your app wants to listen for roles assigned
override fun getAppRolesListener(): AppRolesListener =
object : AppRolesListener {
override fun onAppRolesSet(request: AppRolesSetRequest): AppRolesSetResponse {
val roleTypes = request.roles.map { role -> role.roleType }
Log.i(TAG, "onAppRolesSet: $roleTypes")
return AppRolesSetResponse.getDefaultInstance()
}
}
// If your app wants to listen for local command status updates
// Only relevant for COMPANION_APP role
override fun getCommandListener(): CommandListener {
return object : CommandListener {
override fun onCommandStatusChanged(command: Command) {
Log.i(TAG, "onCommandStatusChanged")
}
}
}
private companion object {
const val TAG = "MyNotificationReceiverService"
}
}
Если роли приложения меняются несколько раз, оно может получить несколько уведомлений. Если все роли удалены, приложение все равно получит уведомление с пустым списком ролей. Это уведомление выведет приложение из остановленного состояния, и оно сможет запуститься без участия пользователя. Благодаря уведомлениям и исключениям для ролей приложения ваш продукт может прослушивать трансляции ACTION_BOOT_COMPLETED. Если ваше приложение зависит от управляемых конфигураций, ознакомьтесь с разделом Настройка управляемых конфигураций, чтобы узнать, как считывать и отслеживать изменения.
Начиная с AMAPI SDK 1.9.0, каждая роль в AppRolesSetRequest также включает Role.ExtraCapabilities, предоставленные системным администратором в правилах. Например, сопутствующее приложение может проверить, разрешено ли ему выполнять команду локального удаления данных:
import com.google.android.managementapi.approles.model.AppRolesSetRequest
import com.google.android.managementapi.approles.model.AppRolesSetResponse
import com.google.android.managementapi.common.model.Role
...
override fun onAppRolesSet(request: AppRolesSetRequest): AppRolesSetResponse {
val canWipeLocally =
request.roles.any { role ->
role.roleType == Role.RoleType.COMPANION_APP &&
role.extraCapabilities.localDeviceWipeCommand ==
Role.ExtraCapabilities.LocalDeviceWipeCommand.LOCAL_DEVICE_WIPE_COMMAND_ALLOWED
}
Log.i(TAG, "onAppRolesSet: canWipeLocally=$canWipeLocally")
return AppRolesSetResponse.getDefaultInstance()
}
Дополнительные возможности может предоставить только системный администратор. Если вы зададите extraCapabilities для роли, которую передаете в EnvironmentClient, вызов завершится ошибкой InvalidArgumentException.
Настройте устройство с помощью правил ролей приложений
Разработчики приложений могут протестировать назначение ролей своему приложению с помощью EMM или следуя краткому руководству по Android Management API. Блокнот Colab для AMAPI позволяет зарегистрировать предприятие, создать правило и настроить устройство.
Как настроить правила для приложения с помощью ролей
Настройте policy с ролями, которые должно иметь ваше приложение, используя ApplicationPolicy.roles.
В примере ниже показано, как настроить роль для приложений MTD.
{
"applications": [
{
"packageName": "com.example.mtd",
"installType": "FORCE_INSTALLED",
"roles": [
{ "roleType": "MOBILE_THREAT_DEFENSE_ENDPOINT_DETECTION_RESPONSE" }
]
}
]
}
Только роль COMPANION_APP поддерживает extraCapabilities. Чтобы разрешить сопутствующему приложению удалять данные с устройства или из рабочего профиля, задайте для параметра extraCapabilities.localDeviceWipeCommand значение LOCAL_DEVICE_WIPE_COMMAND_ALLOWED.
Прежде чем назначить роли, указанные в правилах, система проверит, совпадает ли цифровой отпечаток сертификата ключа подписи приложения на устройстве с отпечатком из Google Play.
Если цифровой отпечаток не совпадает, роли не будут назначены приложению, а в EMM будет отправлено сообщение о несоответствии NonComplianceReason.APP_SIGNING_CERT_MISMATCH.
{
"applications": [
{
"packageName": "com.example.mtd",
"installType": "FORCE_INSTALLED",
"signingKeyCerts": [
{ "signingKeyCertFingerprintSha256": "base64-encoded-sha256" }
],
"roles": [
{ "roleType": "MOBILE_THREAT_DEFENSE_ENDPOINT_DETECTION_RESPONSE" }
]
}
]
}
Если в вашем приложении есть управляемая конфигурация, [системный] администратор может задать начальную конфигурацию для соответствующих restriction в правилах для приложений:
{
"applications": [
{
"packageName": "com.example.mtd",
"installType": "FORCE_INSTALLED",
"roles": [
{ "roleType": "MOBILE_THREAT_DEFENSE_ENDPOINT_DETECTION_RESPONSE" }
],
"managedConfiguration": {
"<key>": "<value>"
}
}
]
}
Проверьте статус исключения для батареи
Приложения с ролью Mobile Threat Defense (MTD) автоматически освобождаются от стандартных ограничений на энергопотребление в фоновом режиме. Однако это исключение реализуется группой App Standby, а не белым списком энергопотребления системы.
Чтобы проверить, активно ли исключение для приложения:
import android.app.usage.UsageStatsManager
import android.content.Context
// UsageStatsManager.STANDBY_BUCKET_EXEMPTED is annotated as a @SystemApi. We can redefine it for clarity.
// Define this at the top level of your file, or inside a companion object
private const val STANDBY_BUCKET_EXEMPTED = 5
private fun isAppExemptedFromAppStandbyBucket(): Boolean =
(getSystemService(Context.USAGE_STATS_SERVICE) as? UsageStatsManager)
?.appStandbyBucket == STANDBY_BUCKET_EXEMPTED