本文基于 https://developer.android.google.cn/work/managed-profiles 翻译而成
Work Profile(工作面)或称为managed profile(被管理面)。
一个work profile由IT admin控制
一个work profile的可用功能基于用户的primary profile分别设置
Work profile功能允许组织控制公司特制应用和数据在用户设备上的运行环境,同时仍允许用户使用其个人的应用和profiles
用户经常使用其个人设备处理公司事务(Users often want to use their personal devices in an enterprise setting.)。该情形可能使公司面临一种困境,即由于个人设备不受控制,公司不得不担心机密信息通过用户个人设备被泄露出去。
如果设备有了work profile,则存在以下可能的影响。
默认大部分intent是无法跨越profile的。如果一个应用(app)发出的intent在其所在的profile中不存在,且不被允许跨越profile调用,则该应用(app)会因为请求intent失败而异常终止。
IT admin也能限制work profile中哪些应用(app)是有效的,这种限制也会造成work profile中的应用(app)无法处理常用intent请求
由于工作profile和个人profile使用独立的存储空间,所以一个profile的文件URI在另一个profile中往往是无效的,所以附带文件URI参数的intent请求是不安全的。
(第一段赘述前文,略)
Profile admin可控制哪些intent可跨越profile。用户无法预知这些设定,且IT admin可随时改变这些策略。
在应用(app)启动一个activity前,应该调用Intent.resolveActivity()
来验证是否intent可被接受。如果不能接受,则该调用返回空(null),如果返回非空,则说明该profile内存在至少一个有效activity来处理该intent请求,或是该intent被允许跨越profile被处理
例如,如果要设置时钟,需要先验证是否能处理ACTION_SET_TIMER
。如果不能,应该给予适当的处理,如显示错误消息。
Kotlinfun 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) } } |
Javapublic void startTimer(String message, int seconds) { |
有时一个应用(app)需要给予其他应用(app)对自身文件的访问权限,例如。一个图库app向图片编辑app共享其文件。一般采用两种实现方式:file URI和content URI。
“file URI”是一个以”file:”为前缀,后接文件绝对路径的字符串。但不同profile使用独立的存储空间,所以一个profile的 “file URI”在另一个profile中往往是无效的,将导致无法访问。
为解决该问题,你应该使用content URI,它以更安全的方式实现文件共享。它不仅含有文件路径,还有content ID。你可以用FileProvider
来生成这个ID。通过共享content ID,其他app即使不在相同的profile,也可以访问到实际的文件。以下是例子。
Kotlin// Open File object from its file URI |
Java// Open File object from its file URI |
当你调用 getUriForFile()
方法,你必须包含文件提供者的authority,上面的例子中是com.example.myapp.fileprovider。详情请参考Sharing Files。
一个应用(app)往往提供NotificationListenerService
子类来接受系统的回调。含work profile的设备可能影响该工作机制。
你无法使用NotificationListenerService
服务,系统会忽略work profile中应用的NotificationListenerService
。
运行在personal profile的应用无法收到work profile的应用发出的通知,除非IT admin将其列入白名单。
从Android8.0(API level 26)起,DPC(device policy Controller)管理work profile,它提供DevicePolicyManager方法setPermittedCrossProfileNotificationListeners()
阻止你的应用(app)监听来自work profile的通知。
Google提供例程BasicManagedProfile,你能用它在Android5.0(API level 21)及更高版本设备上设置一个work profile。它提供简单的方法测试你的app在work profile环境中的表现。你也能用它来配置work profile
如果你通过usb连接手动安装一个应用(app),则该应用(app)即安装在personal profile,也安装在work profile。安装完成后,你能在以下条件下测试它。
在测试中使用以下小技巧可能对你有所帮助。
例如,先运行以下指令列出设备上所有用户:
$ adb shell pm list users UserInfo{0:Drew:13} running UserInfo{10:Work profile:30} running |
本例中主用户("Drew")的用户ID是0, work profile 的用户ID是10。 要在work profile中执行app,你应按照如下方式调用命令:
$ adb shell am start --user 10 \ -n "com.example.myapp/com.example.myapp.testactivity" \ -a android.intent.action.MAIN -c android.intent.category.LAUNCHER |