관리 구성 설정

엔터프라이즈 시장을 위한 앱을 개발하는 경우 조직의 정책에서 설정한 특정 요구사항을 충족해야 할 수 있습니다. 이전에 애플리케이션 제한사항이라고 하던 관리 구성을 사용하면 조직의 IT 관리자가 원격으로 앱 설정을 지정할 수 있습니다. 이 기능은 직장 프로필에 배포된 조직 승인 앱에 특히 유용합니다.

예를 들어 조직에서는 승인된 앱에서 IT 관리자가 다음을 수행하도록 요구할 수 있습니다.

  • 웹브라우저에서 URL 허용 또는 차단하기
  • 앱이 모바일 데이터를 통해 콘텐츠를 동기화하도록 허용할지 아니면 Wi-Fi를 통해서만 콘텐츠를 동기화할 수 있는지 구성
  • 앱의 이메일 설정 구성

이 가이드에서는 앱에서 관리 구성 설정을 구현하는 방법을 설명합니다. 관리 구성이 포함된 샘플 앱을 보려면 ManagedConfigurations를 참조하세요. 엔터프라이즈 모바일 관리 (EMM) 개발자인 경우 Android Management API 가이드를 참고하세요.

참고: 기록상의 이유로 이러한 구성 설정은 제한사항이라고 하며 이 용어를 사용하는 파일 및 클래스 (예: RestrictionsManager)로 구현됩니다. 그러나 이러한 제한사항은 앱 기능 제한사항뿐만 아니라 다양한 구성 옵션을 실제로 구현할 수 있습니다.

원격 구성 개요

앱은 IT 관리자가 원격으로 설정할 수 있는 관리 구성 옵션을 정의합니다. 이는 관리형 구성 제공자가 변경할 수 있는 임의의 설정입니다. 앱이 직장 프로필에서 실행 중이면 IT 관리자가 앱의 관리 구성을 변경할 수 있습니다.

관리 구성 제공자는 동일한 기기에서 실행되는 다른 앱입니다. 이 앱은 일반적으로 IT 관리자가 제어합니다. IT 관리자가 관리 구성 제공자 앱에 구성 변경사항을 전달하면 이 앱이 내 앱의 구성을 변경합니다.

외부에서 관리하는 구성을 제공하려면 다음 안내를 따르세요.

  • 앱 매니페스트에서 관리 구성을 선언합니다. 이렇게 하면 IT 관리자가 Google Play API를 통해 앱 구성을 읽을 수 있습니다.
  • 앱이 다시 시작될 때마다 RestrictionsManager 객체를 사용하여 현재 관리 구성을 확인하고 이러한 구성에 맞게 앱의 UI 및 동작을 변경합니다.
  • ACTION_APPLICATION_RESTRICTIONS_CHANGED 인텐트를 수신 대기합니다. 이 브로드캐스트를 수신하면 RestrictionsManager를 확인하여 현재 관리 구성을 확인하고 앱 동작에 필요한 변경사항을 적용합니다.

관리 구성 정의

앱은 개발자가 정의하려는 모든 관리 구성을 지원할 수 있습니다. 관리 구성 파일에서 앱의 관리 구성을 선언하고 매니페스트에서 구성 파일을 선언합니다. 구성 파일을 만들면 다른 앱이 내 앱이 제공하는 관리 구성을 검사할 수 있습니다. EMM 파트너는 Google Play API를 사용하여 앱 구성을 읽을 수 있습니다.

앱의 원격 구성 옵션을 정의하려면 매니페스트의 <application> 요소에 다음 요소를 삽입합니다.

<meta-data android:name="android.content.APP_RESTRICTIONS"
    android:resource="@xml/app_restrictions" />

앱의 res/xml 디렉터리에 app_restrictions.xml라는 파일을 만듭니다. 이 파일의 구조는 RestrictionsManager 참조에 설명되어 있습니다. 파일에는 단일 최상위 수준 <restrictions> 요소가 있으며 여기에는 앱의 구성 옵션마다 <restriction> 하위 요소가 하나씩 포함되어 있습니다.

참고: 관리 구성 파일의 현지화된 버전은 만들지 마세요. 앱에는 관리되는 구성 파일이 하나만 허용되므로 모든 언어에서 앱의 구성이 일관됩니다.

엔터프라이즈 환경에서 EMM은 일반적으로 관리 구성 스키마를 사용하여 IT 관리자를 위한 원격 콘솔을 생성하므로 관리자가 애플리케이션을 원격으로 구성할 수 있습니다.

관리 구성 제공자는 앱을 쿼리하여 설명 텍스트를 포함하여 앱의 사용 가능한 구성에 관한 세부정보를 찾을 수 있습니다. 구성 제공자와 IT 관리자는 앱이 실행되고 있지 않을 때도 앱의 관리 구성을 언제든지 변경할 수 있습니다.

예를 들어 모바일 데이터 연결을 통한 데이터 다운로드를 허용하거나 금지하도록 앱을 원격으로 구성할 수 있다고 가정해 보겠습니다. 앱에 다음과 같은 <restriction> 요소가 있을 수 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<restrictions xmlns:android="http://schemas.android.com/apk/res/android">

  <restriction
    android:key="downloadOnCellular"
    android:title="@string/download_on_cell_title"
    android:restrictionType="bool"
    android:description="@string/download_on_cell_description"
    android:defaultValue="true" />

</restrictions>

각 구성의 android:key 속성을 사용하여 관리 구성 번들에서 값을 읽습니다. 따라서 각 구성에는 고유한 키 문자열이 있어야 하며 이 문자열은 현지화할 수 없습니다. 문자열 리터럴로 지정해야 합니다.

참고: 프로덕션 앱에서는 리소스로 현지화에 설명된 대로 현지화된 리소스 파일에서 android:titleandroid:description를 가져와야 합니다.

앱이 bundle_array 내의 번들을 사용하여 제한을 정의합니다. 예를 들어 여러 VPN 연결 옵션이 있는 앱은 여러 번들이 번들 배열로 그룹화된 상태로 bundle에 각 VPN 서버 구성을 정의할 수 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<restrictions xmlns:android="http://schemas.android.com/apk/res/android" >

  <restriction
    android:key="vpn_configuration_list"
    android:restrictionType="bundle_array">
    <restriction
      android:key="vpn_configuration"
      android:restrictionType="bundle">
      <restriction
        android:key="vpn_server"
        android:restrictionType="string"/>
      <restriction
        android:key="vpn_username"
        android:restrictionType="string"/>
      <restriction
        android:key="vpn_password"
        android:restrictionType="string"/>
    </restriction>
  </restriction>

</restrictions>

android:restrictionType 요소에 지원되는 유형은 표 1에 나열되어 있으며 RestrictionsManagerRestrictionEntry 참조에 설명되어 있습니다.

표 1. 제한 항목 유형 및 사용

유형 android:restrictionType 유형 일반적인 용도
TYPE_BOOLEAN "bool" 불리언 값(true 또는 false)
TYPE_STRING "string" 문자열 값(예: 이름)
TYPE_INTEGER "integer" MIN_VALUE에서 MAX_VALUE 사이의 값을 가진 정수입니다.
TYPE_CHOICE "choice" android:entryValues에서 선택된 문자열 값이며, 일반적으로 단일 선택 목록으로 표시됩니다.
TYPE_MULTI_SELECT "multi-select" android:entryValues에서 선택한 값이 있는 문자열 배열. 허용 목록에 특정 제목을 선택하는 경우와 같이 둘 이상의 항목을 선택할 수 있는 다중 선택 목록을 표시하는 데 사용합니다.
TYPE_NULL "hidden" 숨겨진 제한사항 유형 전송되어야 하지만 UI에서 사용자에게 표시되어서는 안 되는 정보에 이 유형을 사용합니다. 단일 문자열 값을 저장합니다.
TYPE_BUNDLE_ARRAY "bundle_array" 제한 bundles의 배열을 저장하는 데 사용합니다. Android 6.0 (API 수준 23)에서 사용할 수 있습니다.

참고: android:entryValues는 머신에서 읽을 수 있으며 현지화할 수 없습니다. android:entries를 사용하여 사람이 읽을 수 있는 현지화 가능한 값을 표시합니다. 각 항목에는 android:entryValues에 상응하는 색인이 있어야 합니다.

관리 구성 확인

다른 앱이 구성 설정을 변경해도 앱에 자동으로 알림이 전송되지는 않습니다. 대신 앱이 시작되거나 재개될 때 관리 구성을 확인하고 시스템 인텐트를 수신 대기하여 앱 실행 중에 구성이 변경되는지 확인해야 합니다.

현재 구성 설정을 확인하기 위해 앱에서 RestrictionsManager 객체를 사용합니다. 앱은 다음과 같은 시간에 현재 관리 구성을 확인해야 합니다.

RestrictionsManager 객체를 가져오려면 getActivity()로 현재 활동을 가져온 다음 활동의 Activity.getSystemService() 메서드를 호출합니다.

Kotlin

var myRestrictionsMgr =
        activity?.getSystemService(Context.RESTRICTIONS_SERVICE) as RestrictionsManager

Java

RestrictionsManager myRestrictionsMgr =
    (RestrictionsManager) getActivity()
        .getSystemService(Context.RESTRICTIONS_SERVICE);

RestrictionsManager가 있으면 getApplicationRestrictions() 메서드를 호출하여 현재 구성 설정을 가져올 수 있습니다.

Kotlin

var appRestrictions: Bundle = myRestrictionsMgr.applicationRestrictions

Java

Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();

참고: 편의를 위해 UserManager.getApplicationRestrictions()를 호출하여 UserManager로 현재 구성을 가져올 수도 있습니다. 이 메서드는 RestrictionsManager.getApplicationRestrictions()와 정확히 동일하게 작동합니다.

getApplicationRestrictions() 메서드는 데이터 저장소에서 읽어야 하므로 최소한으로 실행해야 합니다. 현재 구성을 알아야 할 때마다 이 메서드를 호출하지 마세요. 대신 앱이 시작되거나 재개될 때 한 번 호출하고 가져온 관리 구성 번들을 캐시해야 합니다. 그런 다음 관리 구성 변경 수신 대기에 설명된 대로 ACTION_APPLICATION_RESTRICTIONS_CHANGED 인텐트를 수신 대기하여 앱이 활성 상태일 때 구성 변경이 있는지 확인합니다.

관리 구성 읽기 및 적용

getApplicationRestrictions() 메서드는 설정된 각 구성의 키-값 쌍을 포함하는 Bundle를 반환합니다. 값은 모두 Boolean, int, StringString[] 유형입니다. 관리 구성 Bundle이 있으면 해당 데이터 유형(예: getBoolean() 또는 getString())에 대한 표준 Bundle 메서드로 현재 구성 설정을 확인할 수 있습니다.

참고: 관리 구성 Bundle에는 관리 구성 제공자에 의해 명시적으로 설정된 모든 구성 항목이 하나씩 포함됩니다. 그러나 관리 구성 XML 파일에 기본값을 정의했다고 해서 구성이 번들에 있다고 가정할 수는 없습니다.

현재 관리되는 구성 설정에 따라 적절한 조치는 앱에 달려 있습니다. 예를 들어 앱에 모바일 데이터 연결을 통해 데이터를 다운로드할 수 있는지 지정하는 구성이 있고 구성이 false로 설정되어 있다면 다음 코드 예와 같이 기기가 Wi-Fi에 연결된 경우를 제외하고 데이터 다운로드를 중지해야 합니다.

Kotlin

val appCanUseCellular: Boolean =
        if (appRestrictions.containsKey("downloadOnCellular")) {
            appRestrictions.getBoolean("downloadOnCellular")
        } else {
            // cellularDefault is a boolean using the restriction's default value
            cellularDefault
        }

if (!appCanUseCellular) {
    // ...turn off app's cellular-download functionality
    // ...show appropriate notices to user
}

Java

boolean appCanUseCellular;

if (appRestrictions.containsKey("downloadOnCellular")) {
    appCanUseCellular = appRestrictions.getBoolean("downloadOnCellular");
} else {
    // cellularDefault is a boolean using the restriction's default value
    appCanUseCellular = cellularDefault;
}

if (!appCanUseCellular) {
    // ...turn off app's cellular-download functionality
    // ...show appropriate notices to user
}

여러 개의 중첩된 제한을 적용하려면 bundle_array 제한 항목을 Parcelable 객체의 컬렉션으로 읽고 Bundle로 변환합니다. 이 예에서는 각 VPN의 구성 데이터가 파싱되어 서버 연결 선택 목록을 빌드하는 데 사용됩니다.

Kotlin

// VpnConfig is a sample class used store config data, not defined
val vpnConfigs = mutableListOf<VpnConfig>()

val parcelables: Array<out Parcelable>? =
        appRestrictions.getParcelableArray("vpn_configuration_list")

if (parcelables?.isNotEmpty() == true) {
    // iterate parcelables and cast as bundle
    parcelables.map { it as Bundle }.forEach { vpnConfigBundle ->
        // parse bundle data and store in VpnConfig array
        vpnConfigs.add(VpnConfig()
                .setServer(vpnConfigBundle.getString("vpn_server"))
                .setUsername(vpnConfigBundle.getString("vpn_username"))
                .setPassword(vpnConfigBundle.getString("vpn_password")))
    }
}

if (vpnConfigs.isNotEmpty()) {
    // ...choose a VPN configuration or prompt user to select from list
}

Java

// VpnConfig is a sample class used store config data, not defined
List<VpnConfig> vpnConfigs = new ArrayList<>();

Parcelable[] parcelables =
    appRestrictions.getParcelableArray("vpn_configuration_list");

if (parcelables != null && parcelables.length > 0) {
    // iterate parcelables and cast as bundle
    for (int i = 0; i < parcelables.length; i++) {
        Bundle vpnConfigBundle = (Bundle) parcelables[i];
        // parse bundle data and store in VpnConfig array
        vpnConfigs.add(new VpnConfig()
            .setServer(vpnConfigBundle.getString("vpn_server"))
            .setUsername(vpnConfigBundle.getString("vpn_username"))
            .setPassword(vpnConfigBundle.getString("vpn_password")));
    }
}

if (!vpnConfigs.isEmpty()) {
    // ...choose a VPN configuration or prompt user to select from list
}

관리 구성 변경 리슨

앱의 관리 구성이 변경될 때마다 시스템은 ACTION_APPLICATION_RESTRICTIONS_CHANGED 인텐트를 실행합니다. 구성 설정이 변경될 때 앱의 동작을 변경할 수 있도록 앱이 이 인텐트를 수신 대기해야 합니다.

참고: ACTION_APPLICATION_RESTRICTIONS_CHANGED 인텐트는 앱 매니페스트에 선언된 리스너가 아닌 동적으로 등록된 리스너로만 전송됩니다.

다음 코드는 이 인텐트의 broadcast receiver를 동적으로 등록하는 방법을 보여줍니다.

Kotlin

val restrictionsFilter = IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED)

val restrictionsReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {

        // Get the current configuration bundle
        val appRestrictions = myRestrictionsMgr.applicationRestrictions

        // Check current configuration settings, change your app's UI and
        // functionality as necessary.
    }
}

registerReceiver(restrictionsReceiver, restrictionsFilter)

Java

IntentFilter restrictionsFilter =
    new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);

BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
  @Override public void onReceive(Context context, Intent intent) {

    // Get the current configuration bundle
    Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();

    // Check current configuration settings, change your app's UI and
    // functionality as necessary.
  }
};

registerReceiver(restrictionsReceiver, restrictionsFilter);

참고: 일반적으로 앱이 일시중지되었을 때 구성 변경에 관한 알림을 받을 필요는 없습니다. 대신 앱이 일시중지될 때 broadcast receiver를 등록 취소해야 합니다. 앱이 다시 시작되면 먼저 관리 구성 확인에 설명된 대로 현재 관리 구성을 확인한 다음 broadcast receiver를 등록하여 앱이 활성 상태인 동안 발생하는 구성 변경에 관한 알림을 받도록 합니다.

EMM에 관리 구성 의견 보내기

관리 구성 변경사항을 앱에 적용한 후에는 EMM에 변경사항 상태를 알리는 것이 좋습니다. Android는 키가 지정된 앱 상태라는 기능을 지원합니다. 이 기능을 사용하면 앱이 관리된 구성 변경사항을 적용하려고 할 때마다 의견을 보낼 수 있습니다. 이 피드백은 앱이 관리 구성을 성공적으로 설정했음을 확인하는 역할을 하거나 앱이 지정된 변경사항을 적용하지 못한 경우 오류 메시지를 포함할 수 있습니다.

EMM 제공업체는 이러한 의견을 가져와서 IT 관리자가 볼 수 있도록 콘솔에 표시할 수 있습니다. 앱에 의견 지원을 추가하는 방법에 관한 자세한 가이드를 비롯하여 이 주제에 관한 자세한 내용은 EMM에 앱에 관한 의견 보내기를 참고하세요.

추가 코드 샘플

ManagedConfigurations 샘플은 이 페이지에서 다룬 API 사용을 자세히 보여줍니다.