管理应用角色

借助应用角色功能,IT 管理员可以向 Android 设备上的受管理应用授予特殊权限。通过分配特定角色,应用可以免受电源和后台限制、暂停、休眠(在 Android 14 及更高版本中)的影响,并停用用户控制(即包括强制停止和清除应用数据等用户操作)(在 Android 11 及更高版本中),从而使其能够不间断地执行其关键功能。此外,应用可以收到其分配角色的通知,从而无需用户干预即可自行引导。

如需查看可用应用角色以及授予每个角色的特殊权限的列表,请参阅 RoleType。

前提条件

设备由基于 AMAPI 的 EMM 管理(不支持使用自定义 DPC 的 EMM)。

为应用做好使用该功能的准备

只有当应用希望收到其分配角色的通知,以便自行引导(即在没有用户互动的情况下自动启动)时,才需要与 AMAPI SDK 集成。

在应用中集成 AMAPI SDK

如需详细了解 AMAPI SDK 以及如何将其添加到应用中,请参阅 AMAPI SDK 集成指南。

将所需元数据添加到应用的清单中

Android 设备政策 (ADP) 需要知道实现 NotificationReceiverService 的类的 ComponentName,以便向您的应用通知其分配的角色。您必须在 AndroidManifest.xml 中为服务添加适当的标记,以便 ADP 能够自动发现该服务。

  • 您的应用必须只有一个服务,该服务为 enabled,并且具有 meta-data,其 android:name 等于 com.google.android.managementapi.notification.NotificationReceiverService.SERVICE_APP_ROLES
  • 此服务必须将 android:exported 设置为 true
  • meta-data 的 android:value 必须设置为空字符串
<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 设备政策可以向您的应用发送本地命令状态更新:

<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 中的每个角色还包含 IT 管理员在政策中授予的 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()
  }

只有 IT 管理员才能授予额外功能。如果您在传递给 EnvironmentClient 的角色上设置 extraCapabilities,则调用会失败,并显示 InvalidArgumentException。

使用应用角色政策配置设备

应用开发者可以使用 EMM 或按照 Android Management API 快速入门中的说明,测试如何为应用分配应用角色。借助 AMAPI Colab 笔记本,您可以注册企业、创建政策和配置设备。

使用应用角色为应用设置政策

使用 ApplicationPolicy.roles 设置一个 policy,其中包含您的应用应具有的应用角色。

以下示例展示了如何为 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。

在按照政策指定分配角色之前,系统会检查设备上的应用签名密钥证书指纹是否与 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" }
      ]
    }
  ]
}

如果您的应用具有受管理配置,IT 管理员可以在应用政策中为相关 restriction 设置初始配置:

{
  "applications": [

    {
      "packageName": "com.example.mtd",
      "installType": "FORCE_INSTALLED",
      "roles": [
        { "roleType": "MOBILE_THREAT_DEFENSE_ENDPOINT_DETECTION_RESPONSE" }
      ],
      "managedConfiguration": {
        "<key>": "<value>"
      }
    }
  ]
}

验证电池豁免状态

具有移动威胁防御 (MTD) 角色的应用会自动免受标准后台电源限制。不过,此豁免由应用待机存储分区实现,而不是由系统的电源许可清单实现。

如需验证应用免检是否有效,请执行以下操作:

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