设置受管理的配置

如果您要开发面向企业市场的应用,则可能需要 以满足组织政策规定的特定要求。 受管配置,以前称为“应用限制”, 允许单位的 IT 管理员远程指定 。此功能对于由组织批准的 部署到工作资料的应用

例如,组织可能会要求获得批准的应用 IT 管理员执行以下操作:

  • 在网络浏览器中允许或屏蔽网址
  • 配置是允许应用通过移动网络同步内容,还是仅允许 通过 Wi-Fi
  • 配置应用的电子邮件设置

本指南介绍如何在 Google Cloud 控制台中实现受管配置设置。 。如需查看采用托管配置的示例应用,请参阅 ManagedConfigurations。 如果您是企业移动管理 (EMM) 开发者,请参阅 Android Management API 指南

注意:由于历史原因,这些配置设置都称为 限制,通过使用此 字词(例如 RestrictionsManager)。不过,这些 实际上可以实现各种配置选项 不仅仅是限制应用功能

远程配置概览

应用定义了可以远程访问的受管配置选项 由 IT 管理员设置这些设置是任意设置 由受管配置提供商更改。如果您的应用在工作资料中运行, IT 管理员可以更改应用的受管配置。

受管配置提供程序是在同一设备上运行的另一个应用。 此应用通常由 IT 管理员控制。通过 IT 管理员将配置更改传达给受管 配置提供程序应用。该应用进而更改应用的配置。

如需提供由外部管理的配置,请执行以下操作:

  • 在应用清单中声明托管配置。操作 因此 IT 管理员可以读取应用的 配置。
  • 每当应用恢复时,都使用 RestrictionsManager 对象检查当前的 托管配置,并将应用的界面和行为更改为 都符合这些配置
  • 监听 ACTION_APPLICATION_RESTRICTIONS_CHANGED intent。收到此信息后 请查看 RestrictionsManager 了解 当前的托管配置是怎样的, 应用的行为。

定义托管配置

您的应用可以支持您要定义的任何托管配置。您将声明 托管配置文件中存放应用的托管配置,并声明 配置配置文件通过创建配置文件 检查您的应用提供的托管配置。EMM 合作伙伴 可以使用 Google Play API 读取应用的配置。

如需定义应用的远程配置选项,请将以下元素 (位于清单的 <ph type="x-smartling-placeholder"></ph> <application> 元素:

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

在应用的app_restrictions.xml res/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 中使用 bundle 来定义限制。 例如,具有多个 VPN 连接选项的应用可以定义每台 VPN 服务器 bundle 中的配置,其中包含多个 在 bundle 数组中归为一组的 app 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 中列出了这些列, RestrictionsManagerRestrictionEntry

表 1. 限制条目类型和用法。

类型 android:restrictionType 典型用法
TYPE_BOOLEAN "bool" 布尔值(true 或 false)。
TYPE_STRING "string" 字符串值,例如名称。
TYPE_INTEGER "integer" 一个整数,其值来自于 MIN_VALUEMAX_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 的 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();

注意:为方便起见,您还可以提取当前的 具有 UserManagerUserManager.getApplicationRestrictions()。此方法与 与 RestrictionsManager.getApplicationRestrictions() 相同。

getApplicationRestrictions() 方法需要从数据存储中读取数据,因此 请务必谨慎操作。不要在每次需要调用时都调用此方法, 以了解当前配置。而是应该在您的应用 启动或恢复,并缓存提取的受管配置包。然后收听 ACTION_APPLICATION_RESTRICTIONS_CHANGED intent 以了解 在应用处于活动状态时进行更改,如 监听受管配置更改

读取和应用托管配置

getApplicationRestrictions() 方法会返回 Bundle 包含已设置的每个配置的键值对。通过 值均为 BooleanintStringString[]。安装 受管配置Bundle,您可以查看当前的 使用标准 Bundle 方法对配置设置进行 这些数据类型,例如 getBoolean()getString()

注意:受管配置 Bundle 对于由管理员明确设置的每项配置, 受管配置提供程序。不过,您不能假定 仅因为您定义了一个默认值,所以捆绑包中 的值。

您的应用应根据当前 受管配置设置。例如,如果您的应用有一个 指定是否允许通过 并且你发现该配置已设为 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 intent。您的应用必须监听 以便您可以在配置设置时更改应用的行为 更改。

注意ACTION_APPLICATION_RESTRICTIONS_CHANGED intent 只会发送给监听器 是动态注册的监听器,而非声明的监听器

以下代码展示了如何为 此 intent:

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

注意:通常情况下,您的应用不需要收到通知 暂停期间的配置更改。您应该取消注册 您的广播接收器。当应用恢复时, 首先检查当前的受管配置(如 检查托管配置),然后注册 您的广播接收器,以确保您收到配置更改的通知 发生的事件

向 EMM 发送受管配置反馈

将受管配置更改应用到您的应用后,最佳做法是向 EMM 告知以下事项: 更改的状态Android 支持一项称为关键应用状态的功能, 用于在每次您的应用尝试应用受管配置更改时发送反馈。这个 反馈可以用来确认您的应用已成功设置受管配置, 如果您的应用无法应用指定的更改,请添加错误消息。

EMM 提供商能够检索此反馈,并将其显示在其控制台中,方便 IT 部门使用 管理员查看权限。有关详情,请参阅向 EMM 发送应用反馈 提供关于该主题的信息,包括有关如何为应用添加反馈支持的详细指南。

更多代码示例

ManagedConfigurations 示例进一步演示了如何使用本页介绍的 API。