애플리케이션 역할 기능을 사용하면 IT 관리자가 Android 지원 기기에서 관리형 애플리케이션에 특별 권한을 부여할 수 있습니다. 특정 역할을 할당하면 앱이 전원 및 백그라운드 제한, 정지, 최대 절전 모드 (Android 14 이상)에서 제외되고 사용자 컨트롤 (즉, 앱 데이터 강제 종료 및 삭제와 같은 사용자 작업 포함)이 사용 중지되어 (Android 11 이상) 중단 없이 중요한 기능을 실행할 수 있습니다. 또한 앱은 할당된 역할을 알림으로 받을 수 있으므로 사용자 개입 없이 자체적으로 부트스트랩할 수 있습니다.
사용 가능한 애플리케이션 역할과 각 역할에 부여된 특별 권한 목록은 RoleType을 참조하세요.
기본 요건
기기가 AMAPI 기반 EMM으로 관리됩니다 (커스텀 DPC를 사용하는 EMM은 지원되지 않음).
기능을 사용하도록 앱 준비
AMAPI SDK와의 통합은 앱이 할당된 역할을 알림받아 자체적으로 부트스트랩 (즉, 사용자 상호작용 없이 자동 실행)할 수 있도록 하려는 경우에만 필요합니다.
앱에서 AMAPI SDK와 통합
AMAPI SDK 및 이를 앱에 추가하는 방법에 관한 자세한 내용은 AMAPI SDK 통합 가이드를 참고하세요.
앱의 매니페스트에 필수 메타데이터 추가
Android Device Policy (ADP)는 NotificationReceiverService를 구현하는 클래스의 ComponentName을 알아야 앱에 할당된 역할을 알릴 수 있습니다. ADP에서 자동으로 검색할 수 있도록 AndroidManifest.xml에서 서비스에 적절하게 태그를 지정해야 합니다.
- 앱에는
enabled이고android:name가com.google.android.managementapi.notification.NotificationReceiverService.SERVICE_APP_ROLES와 같은meta-data가 있는 서비스가 정확히 하나 있어야 합니다. - 이 서비스의
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 역할을 테스트하는 경우 Android 기기 정책이 로컬 명령어 상태 업데이트를 앱에 전송할 수 있도록 다음 meta-data를 서비스에 추가해야 합니다.
<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 스토어의 지문과 일치하는지 확인합니다.
지문이 다르면 역할이 앱에 할당되지 않고 NonComplianceReason.APP_SIGNING_CERT_MISMATCH 규정 미준수가 EMM에 보고됩니다.
{
"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