编写:zenlynn 原文:http://developer.android.com/training/enterprise/app-compatibility.html
Android 平台允许设备有 managed profile。managed profile 由管理员控制,它的功能和用户原本的 profile 的功能是分别设置的。通过这种方法,在用户设备上运行的企业所定制应用程序和数据的环境就在企业的控制之下,同时用户还能使用私人的应用程序和 profile。
本节课展示了如何修改你的应用程序,使之能够在有 managed profile 的设备上可靠运行。除了一般应用开发的最佳实践外,你不用做任何事。然而,在有 managed profile 的设备上,最佳实践的其中一些规范变得尤为重要。本文件强调了你所需要了解的问题。
用户经常想在企业环境中使用他们的私人设备。这种情况可能让企业陷入困境。如果用户使用他们的私人设备,企业不得不担心在这个不受控制的设备上的机密信息(例如员工的电子邮件和通讯录)。
为了处理这种情况,Android 5.0(API 21)允许企业设置 managed profile。如果设备有 managed profile,这个 profile 的设置是在企业管理员的控制之下的。管理员可以选择在这个 profile 之下,什么应用程序可以运行,什么设备功能可以允许。
如果一个设备有 managed profile,那么,无论应用程序在哪个 profile 之下运行,都意味着:
在一个有 managed profile 的设备上,intent 是否能从一个 profile 跨越到另一个,存在着限制。大多情况下,一个 intent 在哪个 profile 中创建,就在哪个 profile 中响应。如果那个 profile 中无法响应,就算在其他 profile 中可以响应,这个 intent 也不会被响应,而且创建这个 intent 的应用程序会意外关闭。
profile 管理员可以选择哪个 intent 可以从一个 profile 跨越到另一个。因为是由管理员做决定,所以你无法预先知道哪个 intent 可以跨越边界。管理员设置了这个策略,而且可以在任何时候自由更改。
在你的应用程序启动一个 activity 之前,你应该验证这是可行的。你可以调用
Intent.resolveActivity() 方法来验证。如果无法处理,方法会返回 null。如果方法返回值非空,那么至少有一个方法可以处理这个 intent,所以创建这个 intent 是安全的。这种情况下,或者是因为在当前 profile 中可以响应,或者是因为 intent 被允许跨越到可以处理的其他 profile 中,intent 可以被处理。(更多关于响应 intent 的信息,请查看 Common Intents。)
例如,如果你的应用程序需要设置定时器,就需要检查是否能响应 ACTION_SET_TIMER intent。如果应用程序无法响应这个 intent,就需要采取恰当的行动(例如显示一个错误信息)。
public void startTimer(String message, int seconds) {
// Build the "set timer" intent
Intent timerIntent = new Intent(AlarmClock.ACTION_SET_TIMER)
.putExtra(AlarmClock.EXTRA_MESSAGE, message)
.putExtra(AlarmClock.EXTRA_LENGTH, seconds)
.putExtra(AlarmClock.EXTRA_SKIP_UI, true);
// Check if there's a handler for the intent
if (timerIntent.resolveActivity(getPackageManager()) == null) {
// Can't resolve the intent! Fail this operation cleanly
// (perhaps by showing an error message)
} else {
// Intent resolves, it's safe to fire it off
startActivity(timerIntent);
}
}
有时候应用程序需要授权其他运用程序访问自己的文件。例如,一个图片库应用可能想与图片编辑器共享它的图片。一般共享文件有两种方法:通过文件 URI 或者内容 URI。
一个文件 URI 是由前缀 file:
和文件在设备中存储的绝对路径组成的。然而,因为 managed profile 和私人 profile 有各自的存储区域,所以一个文件 URI 在一个 profile 中是有效的,在其他 profile 中是无效的。这种情况意味着,如果你要在 intent 中放置一个文件 URI,而这个 intent 要在其他 profile 中响应,那么响应方是不能访问这个文件的。
你应该取而代之用内容 URI 共享文件。内容 URI 用一种更安全、更易于分享的方式来识别文件。内容 URI 包括了文件路径,文件提供者,以及文件 ID。你可以通过
FileProvider 为任何文件生成内容 ID。然后,你就可以和(甚至在其他 profile 中的)其他应用程序共享内容 ID。响应方可以使用内容 ID 来访问实际文件。
例如,这里展示了你怎么获得一个指定文件 URI 的内容 URI:
// Open File object from its file URI
File fileToShare = new File(fileUriToShare);
Uri contentUriToShare = FileProvider.getUriForFile(getContext(),
"com.example.myapp.fileprovider", fileToShare);
当你调用 getUriForFile() 方法时,必须包括文件提供者的权限(在这个例子里是
"com.example.myapp.fileprovider"
),在应用程序的 manifest 中,用
\
你要在有 managed profile 的环境中测试你的应用程序,以发现会引起运行失败的问题。在一个有 managed profile 的设备中测试是一个验证你的应用程序正确响应 intent 的好办法:无法响应的时候不创建 intent,不使用无法跨越 profile 的 URI 等等。
我们提供了一个示例应用程序,BasicManagedProfile,你可以用它在一个运行 Android 5.0 或者更高系统的 Android 设备上设置一个 managed profile。这个应用程序为在有 managed profile 的环境中来测试你的应用程序提供了一个简单的方法。你也可以按照下面的方法用这个应用程序来设置你的 managed profile:
如果你通过 USB 线手动安装一个有 managed profile 的应用程序,那么在 managed profile 和非 managed profile 之中都安装有这个应用程序。只要你安装了应用程序,你就能在以下条件下进行测试:
你会发现在有 managed profile 的设备里进行测试有一些技巧。
--user
标识,你可以用之设定运行应用程序的用户。通过设定一个用户,你可以选择是在 managed profile 之中运行,还是在非 managed profile 之中运行。更多信息,请查看 ADB Shell Commands。list users
命令。输出的字符串中第一个数字是用户 ID,你可以用于 --user
例如,为了找到一个设备上的用户,你会运行这个命令:
$ adb shell pm list users
UserInfo{0:Drew:13} running
UserInfo{10:Work profile:30} running
在这里,非 managed profile("Drew")有个 ID 为 0 的用户,而 managed profile 有个 ID 为 10 的用户。要在工作 profile 之中运行一个应用程序,你会用到这样的命令:
$ adb shell am start --user 10 \
-n "com.example.myapp/com.example.myapp.testactivity" \
-a android.intent.action.MAIN -c android.intent.category.LAUNCHER