관리 구성 설정

엔터프라이즈 시장용 앱을 개발하는 경우 조직의 정책에 따라 설정된 특정 요구사항을 충족해야 할 수 있습니다. 이전에는 애플리케이션 제한사항이라고 했던 관리 구성을 통해 조직의 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 참조에 설명되어 있습니다. 이 파일에는 앱의 모든 구성 옵션에 관한 <restriction> 하위 요소가 하나씩 포함된 단일 최상위 <restrictions> 요소가 있습니다.

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

엔터프라이즈 환경에서 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

자바

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

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

Kotlin

var appRestrictions: Bundle = myRestrictionsMgr.applicationRestrictions

자바

Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();

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

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

관리 구성 읽기 및 적용

getApplicationRestrictions() 메서드는 설정된 각 구성의 키-값 쌍이 포함된 Bundle을 반환합니다. 값은 모두 Boolean, int, String, String[] 유형입니다. 관리 구성 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
}

자바

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
}

자바

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

자바

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의 사용을 더 자세히 보여줍니다.

개인 프로필에서 앱 허용 목록/차단 목록

서드 파티 앱 스토어는 관리 구성을 사용하여 개인 프로필과 사용자가 민감한 앱을 보관할 수 있는 추가 개인 공간인 비공개 스페이스 소비자 기능에 모두 앱 차단 목록 또는 허용 목록을 적용할 수 있는 안정적인 방법을 갖고자 할 수 있습니다. 기업용 앱 스토어를 개발하고 이 기능을 사용하려면 이 양식을 제출하여 관심을 표현하고 양식에서 답변 사유서드 파티 앱 스토어 허용 목록 추가에 관심이 있음을 선택하세요.