编写:zenlynn 原文:http://developer.android.com/training/enterprise/app-restrictions.html
如果你为企业市场开发 app ,你可能需要满足企业政策的特殊要求。应用程序的限制允许企业管理员远程设定 app 。这种能力对于部署了 managed profile 的企业 app 来说,尤其有用。
例如,一个企业可能需要核准的 app 允许企业管理员:
这个指南展示了如何在你的 app 实现这个配置设定。
注意:由于历史原因,这些配置设定被称为限制,并在文件与类中使用这个术语(例如 RestrictionsManager)。然而,这些限制实际上可以实现各种各样的配置选项,并不只是限制 app 的功能。
app 定义了管理员可以远程设定的限制和配置选项。限制提供者可以随意改变配置设定。如果你的 app 运行在企业设备上的 managed profile 中 ,企业管理员可以改变该 app 的限制。
限制提供者是运行在同一个设备上的另一个 app 。这个 app 通常是由企业管理员控制。企业管理员向限制提供者 app 传达限制的改变。这个 app 就相应地改变你的 app 的限制。
提供外部可配置的限制:
你的 app 支持任何你想要定义的限制。你在限制文件中声明 app 的限制,在 manifest 中声明限制文件。创建一个限制文件允许其他 app 检查你的 app 提供的限制。企业移动管理(EMM)合作者可以通过 Google Play 接口来读取你的 app 的限制。
为了定义你的 app 的远程配置选项,把以下元素放在你的 manifest 中的 \
<meta-data android:name="android.content.APP_RESTRICTIONS"
android:resource="@xml/app_restrictions" />
在 res/xml
文件夹中创建一个名为 app_restrictions.xml
的文件。该文件的结构在 RestrictionsManager的参考文献中有所 描述。该文件有一个单独的顶级的 <restrictions>
元素,这个元素包括一个 <restriction>
子元素对应 app 的每一个配置选项。
注意:不要创建限制文件的地区化版本。你的 app 只允许有一个限制文件,这样你的 app 在所有地区的限制才会保持一致。
在一个企业环境中,EMM 一般会使用该限制的框架为 IT 管理员生成远程控制台,所以管理员可以远程配置你的 app 。
例如,假设你的 app 可以被远程配置允许或禁止它在蜂窝连接下下载数据。你的 app 就会有一个像这样的 <restriction>
元素:
<?xml version="1.0" encoding="utf-8"?>
<restrictions xmlns:android="http://schemas.android.com/apk/res/android" >
<restriction
android:key="download_on_cell"
android:title="@string/download_on_cell_title"
android:restrictionType="bool"
android:description="@string/download_on_cell_description"
android:defaultValue="true" />
</restrictions>
RestrictionsManager 的参考文献中记载了 android:restrictionType
元素所支持的类型。
注意:Goole Play for Work 不支持
bundle
和bundle_array
限制类型。
使用每个限制的 android:key
属性从限制 bundle 中读取它的值。为此,每个限制必须有一个独特的 key 字符串,并且不能被地区化。它必须用一个 string 直接量指明。
注意:如在资源地区化所说,在一个产品 app 中,
android:title
和android:description
应该从地区化资源文件中提取出来。
限制提供者可以询问 app 来找到该 app 可用限制的细节,包括它们的描述文本。限制提供者和企业管理员可以在任何时候,甚至 app 没有在运行的时候,改变它的限制。
当其他 app 改变你的 app 的限制设定时,你的 app 不会被自动通知。反而需要你在 app 启动或恢复的时候检查有哪些限制,并且监听系统 intent 来发现当你的 app 运行的时候限制是否发生改变。
为了知道当前限制设定,你的 app 使用一个 RestrictionsManager 对象。你的 app 应该在以下时候检查当前限制:
为了获得一个 RestrictionsManager 对象,使用 getActivity() 取得当前 activity,然后调用 activity 的 Activity.getSystemService() 方法:
RestrictionsManager myRestrictionsMgr =
(RestrictionsManager) getActivity()
.getSystemService(Context.RESTRICTIONS_SERVICE);
一旦你有了 RestrictionsManager,你可以通过调用它的 getApplicationRestrictions() 方法取得当前的限制设定:
Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();
注意:方便起见,你也可以用 UserManager 取得当前限制,调用 UserManager.getApplicationRestrictions() 即可。这个方法与 RestrictionsManager.getApplicationRestrictions() 起到完全相同的作用。
getApplicationRestrictions() 方法需要从数据存储区获得数据,所以要尽量少用。不要每次你需要知道当前限制的时候就调用这个方法。你应该只在你的 app 启动或恢复的时候调用,并且缓存所取得的限制 bundle。然后,如监听 app 配置的改变中所说,在你的 app 活动的时候,监听 ACTION_APPLICATION_RESTRICTIONS_CHANGED intent 来发现限制是否改变。
当你的 app 使用 RestrictionsManager.getApplicationRestrictions() 检查限制时,我们建议你检查企业管理员是否把键值对 KEY_RESTRICTIONS_PENDING 设置为 true。如果设置了,你应该阻止用户使用这个 app,并提示他们联系他们的企业管理员。然后,这个 app 应该继续正常运行,注册 ACTION_APPLICATION_RESTRICTIONS_CHANGED 广播。
Figure 1. 在注册广播之前检查限制是否暂挂
getApplicationRestrictions() 方法返回一个 Bundle,其中包含了被设置的每个限制的键值对。这些值的类型是 Boolean
, int
, String
, String[]
, Bundle
, Bundle[]
。只要你有了限制 Bundle ,你就可以用标准的 Bundle 方法针对数据类型来检查当前的限制设置,比如 getBoolean() 或者 getString()。
注意:限制 Bundle 为每个被限制提供者显式设置的限制都包括了一个条目。但是,你不能只因为你在限制 XML 文件中定义了一个默认值,就假定这个限制就会在 bundle 里出现。
你基于当前的限制设定,为你的 app 采取合适的行动。比如,如果你的 app 有一个限制架构来指明是否它能在蜂窝连接(就像在定义 app的 限制的例子里一样)中下载,而你发现限制设置为 false,那么你不得不禁止数据下载,除非设备在 Wi-Fi 连接下,正如下面的实例代码所展示的:
boolean appCanUseCellular;
if appRestrictions.containsKey("downloadOnCellular") {
appCanUseCellular = appRestrictions.getBoolean("downloadOnCellular");
} else {
// here, cellularDefault is a boolean set with the restriction's
// default value
appCanUseCellular = cellularDefault;
}
if (!appCanUseCellular) {
// ...turn off app's cellular-download functionality
// ...show appropriate notices to user
}
注意:该限制架构必须向前向后兼容,因为 Google Play for Work 对于每个 app 只给予 EMM 一个版本的限制架构。
每当 app 的限制被改变,系统就创建 ACTION_APPLICATION_RESTRICTIONS_CHANGED intent。你的 app 必须监听这个 intent,这样你就能在限制设定改变的时候改变 app 的行为。
注意:ACTION_APPLICATION_RESTRICTIONS_CHANGED intent 只发送给动态注册的监听者,而不发送给在 app manifest 里声明的监听者。
以下代码展示了如何为这个 intent 动态注册一个广播接收者:
IntentFilter restrictionsFilter =
new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
// Get the current restrictions bundle
Bundle appRestrictions =
myRestrictionsMgr.getApplicationRestrictions();
// Check current restrictions settings, change your app's UI and
// functionality as necessary.
}
};
registerReceiver(restrictionsReceiver, restrictionsFilter);
注意:一般来说,当你的 app 中止时不需要被通知限制的改变。相反,这个时候你需要注销你的广播接收者。当 app 恢复时,你首先要检查当前的限制(正如在检查 app 的限制中所讨论的),然后注册你的广播接收者,以保证在 app 活动期间如果有限制改变你会被通知。