Настройка управляемых конфигураций

Если вы разрабатываете приложения для корпоративного рынка, вам может потребоваться удовлетворить определенные требования, установленные политикой организации. Управляемые конфигурации, ранее известные как ограничения приложений , позволяют ИТ-администратору организации удаленно задавать настройки для приложений. Эта возможность особенно полезна для приложений, одобренных организацией, развернутых в рабочем профиле.

Например, организация может потребовать, чтобы одобренные приложения позволяли ИТ-администратору:

  • Разрешить или заблокировать URL-адреса для веб-браузера
  • Настройте, разрешено ли приложению синхронизировать контент через сотовую сеть или только по Wi-Fi.
  • Настройте параметры электронной почты приложения

В этом руководстве показано, как реализовать параметры управляемой конфигурации в вашем приложении. Чтобы просмотреть примеры приложений с управляемой конфигурацией, см. ManagedConfigurations . Если вы разработчик системы управления корпоративной мобильностью (EMM), обратитесь к руководству по Android Management API .

Примечание. По историческим причинам эти параметры конфигурации известны как ограничения и реализуются с помощью файлов и классов, которые используют этот термин (например, RestrictionsManager ). Однако эти ограничения на самом деле могут реализовывать широкий спектр параметров конфигурации, а не только ограничения на функциональность приложения.

Обзор удаленной конфигурации

Приложения определяют параметры управляемой конфигурации, которые ИТ-администратор может настроить удаленно. Это произвольные параметры, которые может изменить поставщик управляемой конфигурации. Если ваше приложение работает в рабочем профиле, ИТ-администратор может изменить управляемую конфигурацию вашего приложения.

Поставщик управляемых конфигураций — это другое приложение, работающее на том же устройстве. Обычно это приложение контролируется ИТ-администратором. ИТ-администратор передает изменения конфигурации приложению поставщика управляемой конфигурации. Это приложение, в свою очередь, меняет конфигурации вашего приложения.

Чтобы предоставить конфигурации, управляемые извне:

  • Объявите управляемые конфигурации в манифесте вашего приложения. Это позволит ИТ-администратору читать конфигурации приложения через API Google Play.
  • При каждом возобновлении работы приложения используйте объект RestrictionsManager , чтобы проверить текущие управляемые конфигурации и изменить пользовательский интерфейс и поведение приложения в соответствии с этими конфигурациями.
  • Прослушайте намерение ACTION_APPLICATION_RESTRICTIONS_CHANGED . Когда вы получите это сообщение, проверьте RestrictionsManager чтобы узнать, каковы текущие управляемые конфигурации, и внесите все необходимые изменения в поведение вашего приложения.

Определение управляемых конфигураций

Ваше приложение может поддерживать любую управляемую конфигурацию, которую вы хотите определить. Вы объявляете управляемые конфигурации приложения в файле управляемых конфигураций и объявляете файл конфигурации в манифесте. Создание файла конфигурации позволяет другим приложениям проверять управляемые конфигурации, предоставляемые вашим приложением. Партнеры EMM могут читать конфигурации вашего приложения с помощью API Google Play.

Чтобы определить параметры удаленной конфигурации вашего приложения, поместите следующий элемент в элемент <application> вашего манифеста:

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

Создайте файл с именем app_restrictions.xml в каталоге res/xml вашего приложения. Структура этого файла описана в справочнике по RestrictionsManager . В файле есть один элемент <restrictions> верхнего уровня, который содержит один дочерний элемент <restriction> для каждого параметра конфигурации, имеющегося в приложении.

Примечание. Не создавайте локализованные версии файла управляемой конфигурации. Вашему приложению разрешено иметь только один файл управляемых конфигураций, поэтому конфигурации вашего приложения будут одинаковыми во всех языковых стандартах.

В корпоративной среде EMM обычно использует схему управляемой конфигурации для создания удаленной консоли для ИТ-администраторов, чтобы администраторы могли удаленно настраивать ваше приложение.

Поставщик управляемой конфигурации может запросить приложение, чтобы найти подробную информацию о доступных конфигурациях приложения, включая текст их описания. Поставщик конфигураций и ИТ-администратор могут изменить управляемые конфигурации вашего приложения в любое время, даже если приложение не запущено.

Например, предположим, что ваше приложение можно удаленно настроить, чтобы разрешить или запретить загрузку данных через сотовое соединение. Ваше приложение может иметь такой элемент <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:title и android:description должны быть взяты из локализованного файла ресурсов, как описано в разделе Локализация с помощью ресурсов .

Приложение определяет ограничения, используя пакеты в bundle_array . Например, приложение с несколькими вариантами VPN-подключения может определить каждую конфигурацию VPN-сервера в bundle , при этом несколько пакетов будут сгруппированы в массив пакетов:

<?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 и описаны в справочниках по RestrictionsManager и RestrictionEntry .

Таблица 1. Типы и использование записей ограничений.

Тип Android: тип ограничения Типичное использование
TYPE_BOOLEAN "bool" Логическое значение, истинное или ложное.
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" Скрытый тип ограничения. Используйте этот тип для информации, которую необходимо передать, но не следует представлять пользователю в пользовательском интерфейсе. Хранит одно строковое значение.
TYPE_BUNDLE_ARRAY "bundle_array" Используйте это для хранения массивов bundles ограничений. Доступно в Android 6.0 (уровень API 23).

Примечание. android:entryValues ​​являются машиночитаемыми и не могут быть локализованы. Используйте android:entries для представления удобочитаемых значений, которые можно локализовать. Каждая запись должна иметь соответствующий индекс в android:entryValues .

Проверьте управляемые конфигурации

Ваше приложение не уведомляется автоматически, когда другие приложения меняют настройки конфигурации. Вместо этого вам необходимо проверить, каковы управляемые конфигурации при запуске или возобновлении работы вашего приложения, и прислушаться к намерению системы, чтобы выяснить, изменяются ли конфигурации во время работы вашего приложения.

Чтобы узнать текущие параметры конфигурации, ваше приложение использует объект RestrictionsManager . Ваше приложение должно проверять текущие управляемые конфигурации в следующие моменты:

Чтобы получить объект RestrictionsManager , получите текущую активность с помощью getActivity() , затем вызовите метод Activity.getSystemService() этой активности:

Котлин

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

Ява

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

Если у вас есть RestrictionsManager , вы можете получить текущие настройки конфигурации, вызвав его метод getApplicationRestrictions() :

Котлин

var appRestrictions: Bundle = myRestrictionsMgr.applicationRestrictions

Ява

Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();

Примечание. Для удобства вы также можете получить текущие конфигурации с помощью UserManager , вызвав UserManager.getApplicationRestrictions() . Этот метод ведет себя точно так же, как RestrictionsManager.getApplicationRestrictions() .

Метод getApplicationRestrictions() требует чтения из хранилища данных, поэтому его следует делать с осторожностью. Не вызывайте этот метод каждый раз, когда вам нужно узнать текущую конфигурацию. Вместо этого вам следует вызывать его один раз при запуске или возобновлении работы приложения и кэшировать полученный пакет управляемых конфигураций. Затем прослушайте намерение ACTION_APPLICATION_RESTRICTIONS_CHANGED , чтобы узнать, изменилась ли конфигурация, пока ваше приложение активно, как описано в разделе «Прослушивание изменений управляемой конфигурации» .

Чтение и применение управляемых конфигураций

Метод getApplicationRestrictions() возвращает Bundle , содержащий пару ключ-значение для каждой установленной конфигурации. Все значения имеют тип Boolean , int , String и String[] . Получив управляемые конфигурации Bundle , вы можете проверить текущие параметры конфигурации с помощью стандартных методов Bundle для этих типов данных, таких как getBoolean() или getString() .

Примечание. Bundle управляемых конфигураций содержит один элемент для каждой конфигурации, явно заданной поставщиком управляемых конфигураций. Однако нельзя предполагать, что конфигурация будет присутствовать в пакете только потому, что вы определили значение по умолчанию в XML-файле управляемых конфигураций.

Ваше приложение должно предпринять соответствующие действия в зависимости от текущих параметров управляемой конфигурации. Например, если в вашем приложении есть конфигурация, определяющая, может ли оно загружать данные через сотовое соединение, и вы обнаружите, что для конфигурации установлено значение false , вам придется отключить загрузку данных, за исключением случаев, когда устройство имеет соединение Wi-Fi, как показано в следующем примере кода:

Котлин

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 анализируются и используются для создания списка вариантов подключения к серверу:

Котлин

// 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 отправляется только прослушивателям, которые зарегистрированы динамически, а не прослушивателям, объявленным в манифесте приложения.

Следующий код показывает, как динамически зарегистрировать широковещательный приемник для этой цели:

Котлин

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

Примечание. Обычно вашему приложению не требуется получать уведомления об изменениях конфигурации, когда оно приостановлено. Вместо этого вам следует отменить регистрацию приемника вещания, когда приложение приостановлено. Когда работа приложения возобновляется, вы сначала проверяете текущие управляемые конфигурации (как описано в разделе «Проверка управляемых конфигураций »), а затем регистрируете приемник широковещательной передачи, чтобы получать уведомления об изменениях конфигурации, которые происходят, пока приложение активно.

Отправьте отзыв об управляемой конфигурации специалистам EMM.

После применения изменений управляемой конфигурации к вашему приложению рекомендуется уведомить EMM о статусе изменения. Android поддерживает функцию, называемую состояниями приложения с ключами , которую вы можете использовать для отправки отзыва каждый раз, когда ваше приложение пытается применить изменения управляемой конфигурации. Этот отзыв может служить подтверждением того, что ваше приложение успешно установило управляемые конфигурации, или может включать сообщение об ошибке, если вашему приложению не удалось применить указанные изменения.

Поставщики EMM могут получать эти отзывы и отображать их на своих консолях для просмотра ИТ-администраторами. Дополнительную информацию по этой теме, включая подробное руководство о том, как добавить поддержку отзывов в ваше приложение, см. в разделе «Отправка отзывов о приложении в EMM».

Дополнительные примеры кода

Образец ManagedConfigurations дополнительно демонстрирует использование API, описанных на этой странице.