Android 平台允许设备拥有工作配置文件(有时称为托管配置文件)。工作配置文件由 IT 管理员控制,其可用功能与用户主配置文件的功能分开设置。这种方法允许组织控制公司特定应用和数据在用户设备上运行的环境,同时仍允许用户使用其个人应用和配置文件。
本课程将向您展示如何修改您的应用程序,使其在具有工作配置文件的设备上可靠运行。您无需执行任何操作,只需遵循普通的应用程序开发最佳实践即可。但是,其中一些最佳实践在具有工作配置文件的设备上变得尤为重要。本文档重点介绍您需要注意的问题。
概述
用户通常希望在企业环境中使用其个人设备。这种情况可能会给组织带来难题。如果用户可以使用自己的设备,则组织必须担心机密信息(例如员工电子邮件和联系人)存储在组织无法控制的设备上。
为了解决这种情况,Android 5.0(API 级别 21)允许组织设置工作配置文件。如果设备具有工作配置文件,则该配置文件的设置由 IT 管理员控制。IT 管理员可以选择允许哪些应用使用该配置文件,并且可以控制该配置文件可用的设备功能。
如果设备具有工作配置文件,则无论应用在哪个配置文件下运行,都会对设备上运行的应用产生影响。
- 默认情况下,大多数意图不会从一个配置文件跨越到另一个配置文件。如果在一个配置文件上运行的应用触发了一个意图,而该配置文件上没有该意图的处理程序,并且由于配置文件限制,该意图不允许跨越到另一个配置文件,则请求将失败,应用可能会意外关闭。
- 配置文件 IT 管理员可以限制工作配置文件上可用的系统应用。此限制也可能导致工作配置文件上某些常用意图没有处理程序。
- 由于个人和工作配置文件具有单独的存储区域,因此在一个配置文件上有效的文件 URI 在另一个配置文件上无效。任何在一个配置文件上触发的意图都可能在另一个配置文件上进行处理(取决于配置文件设置),因此将文件 URI 附加到意图是不安全的。
防止意图失败
在具有工作配置文件的设备上,对意图是否可以从一个配置文件跨越到另一个配置文件存在限制。在大多数情况下,当触发意图时,它会在触发它的同一个配置文件上进行处理。如果该配置文件上没有该意图的处理程序,则该意图将不会被处理,触发它的应用可能会意外关闭——即使另一个配置文件上存在该意图的处理程序。
配置文件管理员可以选择允许哪些意图从一个配置文件跨越到另一个配置文件。由于 IT 管理员做出此决定,因此您无法预先知道哪些意图允许跨越此边界。IT 管理员设置此策略,并且可以随时更改它。
在您的应用启动活动之前,您应该验证是否存在合适的解决方案。您可以通过调用Intent.resolveActivity()
来验证是否存在可接受的解决方案。如果没有办法解析意图,则该方法将返回null
。如果该方法返回非 null 值,则至少有一种方法可以解析意图,并且可以安全地触发该意图。在这种情况下,意图可能是可解析的,因为当前配置文件上存在处理程序,或者因为允许意图跨越到另一个配置文件上的处理程序。(有关解析意图的更多信息,请参阅常用意图。)
例如,如果您的应用需要设置计时器,则需要检查是否存在ACTION_SET_TIMER
意图的有效处理程序。如果应用无法解析意图,则应采取适当的操作(例如显示错误消息)。
Kotlin
fun startTimer(message: String, seconds: Int) { // Build the "set timer" intent val timerIntent = Intent(AlarmClock.ACTION_SET_TIMER).apply { 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(packageManager) == 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) } }
Java
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:
前缀开头,后跟设备存储上文件的绝对路径。但是,由于工作配置文件和个人配置文件使用单独的存储区域,在一个配置文件上有效的文件 URI 在另一个配置文件上无效。这意味着,如果您将文件 URI 附加到 intent,并且该 intent 在另一个配置文件上处理,则处理程序将无法访问该文件。
相反,您应该使用内容 URI共享文件。内容 URI 以更安全、更可共享的方式标识文件。内容 URI 包含文件路径,还包含提供文件的权限以及标识文件的 ID 号。您可以使用FileProvider
为任何文件生成内容 ID。然后,您可以与其他应用(即使在另一个配置文件上)共享该内容 ID。接收方可以使用内容 ID 来访问实际文件。
例如,以下是如何获取特定文件 URI 的内容 URI 的方法:
Kotlin
// Open File object from its file URI val fileToShare = File(fileUriToShare) val contentUriToShare: Uri = FileProvider.getUriForFile( context, "com.example.myapp.fileprovider", fileToShare )
Java
// 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"
),该权限在应用清单的<provider>
元素中指定。有关使用内容 URI 共享文件的更多信息,请参阅共享文件。
监听通知
应用通常提供NotificationListenerService
子类来接收系统关于通知更改的回调。带有工作配置文件的设备可能会影响NotificationListenerService
与您的应用一起工作的方式。
在工作配置文件中
您不能使用在工作配置文件中运行的应用的NotificationListenerService
。当您的应用在工作配置文件中运行时,系统会忽略您的应用的NotificationListenerService
。但是,在个人配置文件中运行的应用可以监听通知。
在个人配置文件中
当您的应用在个人配置文件中运行时,您可能无法收到在工作配置文件中运行的应用的通知。默认情况下,所有个人配置文件应用都会接收回调,但 IT 管理员可以允许列入白名单一个或多个个人配置文件应用,允许它们监听通知更改。然后,系统会阻止未列入白名单的应用。在 Android 8.0(API 级别 26)或更高版本中,管理工作配置文件的设备策略控制器 (DPC) 可能会使用DevicePolicyManager
方法setPermittedCrossProfileNotificationListeners()
阻止您的应用监听工作配置文件的通知。您的应用仍然会接收关于在个人配置文件中发布的通知的回调。
测试您的应用与工作配置文件的兼容性
您应该在工作配置文件环境中测试您的应用,以捕获会导致您的应用在带有工作配置文件的设备上失败的问题。特别是,在工作配置文件设备上进行测试是确保您的应用正确处理 intent 的好方法:不触发无法处理的 intent,不附加无法跨配置文件工作的 URI,等等。
我们提供了一个示例应用TestDPC,您可以使用它在运行 Android 5.0(API 级别 21)及更高版本的 Android 设备上设置工作配置文件。此应用为您提供了一种在工作配置文件环境中测试应用的简单方法。您还可以使用此应用配置工作配置文件,如下所示:
- 指定托管配置文件上可用的默认应用
- 配置允许从一个配置文件跨到另一个配置文件的 intent
如果您通过 USB 数据线手动将应用安装到具有工作配置文件的设备上,则该应用将安装在个人配置文件和工作配置文件上。安装应用后,您可以在以下条件下测试应用:
- 如果 intent 通常由默认应用(例如相机应用)处理,请尝试在工作配置文件上禁用该默认应用,并验证应用是否正确处理此问题。
- 如果您触发 intent 并期望它由其他应用处理,请尝试启用和禁用该 intent 从一个配置文件跨到另一个配置文件的权限。验证应用在两种情况下是否都能正常运行。如果 intent 不允许跨配置文件,请在应用配置文件上有合适的处理程序和没有合适的处理程序的情况下验证应用的行为。例如,如果您的应用触发与地图相关的 intent,请尝试以下每种情况:
- 设备允许地图 intent 从一个配置文件跨到另一个配置文件,并且另一个配置文件(应用未运行的配置文件)上有合适的处理程序。
- 设备不允许地图 intent 跨配置文件,但应用配置文件上有合适的处理程序。
- 设备不允许地图 intent 跨配置文件,并且设备配置文件上没有合适的地图 intent 处理程序。
- 如果您将内容附加到 intent,请验证 intent 在其应用配置文件上处理以及跨配置文件时是否都能正常运行。
在工作配置文件上进行测试:技巧和窍门
在工作配置文件设备上进行测试时,您可能会发现一些技巧很有帮助。
- 如前所述,当您在工作配置文件设备上侧载应用时,它会安装在两个配置文件上。如果需要,您可以从一个配置文件中删除应用,而将其保留在另一个配置文件中。
- Android 调试桥 (adb) shell 中可用的大多数活动管理器命令都支持
--user
标志,允许您指定要以哪个用户身份运行。通过指定用户,您可以选择是以非托管主用户身份还是工作配置文件身份运行。有关更多信息,请参阅ADB Shell 命令。 - 要查找设备上的活动用户,请使用 adb 包管理器的
list users
命令。输出字符串中的第一个数字是用户 ID,您可以将其与--user
标志一起使用。有关更多信息,请参阅ADB Shell 命令。
例如,要查找设备上的用户,您将运行以下命令:
$ adb shell pm list users UserInfo{0:Drew:13} running UserInfo{10:Work profile:30} running
在这种情况下,主用户 (“Drew”) 的用户 ID 为 0,工作配置文件的用户 ID 为 10。要在工作配置文件中运行应用,您将使用以下命令:
$ adb shell am start --user 10 \ -n "com.example.myapp/com.example.myapp.testactivity" \ -a android.intent.action.MAIN -c android.intent.category.LAUNCHER