设备管理器?
Android 2.2 介绍了通过提供设备管理器来支持企业级应用的开发。设备管理器API提供了系统级别的一些功能,允许企业使用一些安全敏感的应用来开发更多内部的应用。
官方介绍:https://developer.android.com/guide/topics/admin/device-admin.html#overview
示例
首先,我们需要在配置文件中声明一个DeviceAdminReceiver的继承类,这里命名为MyDeviceReceiver。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <!-- 把receiver去掉覆盖安装即可正常删除apk --> <receiver android:name=".MyDeviceReceiver" android:label="@string/app_name" android:permission="android.permission.BIND_DEVICE_ADMIN"> <!-- 需要声明权限 --> <meta-data android:name="android.app.device_admin" android:resource="@xml/device_admin_sample" /> <intent-filter> <!--此处必须设定该Action,不设定则无法启动设备管理器--> <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" /> </intent-filter> </receiver>
|
- 需要声明android.permission.BIND_DEVICE_ADMIN权限,确保系统可以与Receiver正常交互。
- android.app.action.DEVICE_ADMIN_ENABLED是Receiver必须设定的。否则无法提示用户打开设备管理器开关。可以在代码中通过监听onEnabled()获取用户的操作。
- android:resource=”@xml/device_admin_sample”声明需要使用到的属性。可以从DeviceAdminInfo中获取相关的信息。
我们看下xml/device_admin_sample.xml里面的声明(这些声明可以按需选择,也可以不要):
1 2 3 4 5 6 7 8 9 10 11 12
| <device-admin xmlns:android="http://schemas.android.com/apk/res/android"> <uses-policies> <limit-password /> <watch-login /> <reset-password /> <force-lock /> <wipe-data /> <expire-password /> <encrypted-storage /> <disable-camera /> </uses-policies> </device-admin>
|
之后看看MyDeviceReceiver:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class MyDeviceReceiver extends DeviceAdminReceiver { @Override public CharSequence onDisableRequested(Context context, Intent intent) {
return "请不要关闭"; } @Override public void onEnabled(Context context, Intent intent) { Log.d("MyDeviceReceiver", intent != null ? intent.toString() : "null intent"); super.onEnabled(context, intent); } }
|
在自定义的Receiver中可以通过监听用户操作来添加我们需要的处理逻辑。
最后,在启动页中引导用户跳转到激活页面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_what_the_hell); DevicePolicyManager devicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); ComponentName deviceComponentName = new ComponentName("com.uc.ronrwin.devicepolicymanager", "com.uc.ronrwin.devicepolicymanager.MyDeviceReceiver"); boolean isAdminActivie = devicePolicyManager.isAdminActive(deviceComponentName); if (!isAdminActivie) { Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN); intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, deviceComponentName); intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "(自定义区域2)"); startActivity(intent); } }
|
这样我们的demo就完成了。
启动时关于属性的描述:

当激活之后,该应用将不能被操作:

如果一定要卸载,则需要到”Security”->”Device administrators”中取消激活:


如果点击“DEACTIVATE”,则会出现我们之前定义的弹框内容:

点击OK之后,该应用就可以卸载了。
设备策略
我们通过下面的方式获取DevicePolicyManager对象:
1 2
| DevicePolicyManager mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
|
以前一篇文章所述,我们还是原来的demo定义:
1 2 3
| ComponentName deviceComponentName = new ComponentName("com.uc.ronrwin.devicepolicymanager", "com.uc.ronrwin.devicepolicymanager.MyDeviceReceiver");
|
设置密码
下面的代码提示用户设置密码:
1 2 3
| Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD); mDPM.setPasswordQuality(deviceComponentName, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); startActivity(intent);
|
设置密码质量
有多个选项可供选择:
- PASSWORD_QUALITY_ALPHABETIC:密码至少包含字母(Password)
- PASSWORD_QUALITY_ALPHANUMERIC:密码至少包含数字和字母(Password)
- PASSWORD_QUALITY_NUMERIC:密码至少包含数字(PIN、Password)
- PASSWORD_QUALITY_COMPLEX:密码至少包含数字、字母和特殊字符
- PASSWORD_QUALITY_SOMETHING:至少包含一类密码(Pattern、PIN、Password)
- PASSWORD_QUALITY_UNSPECIFIED:默认方式,所有方式可用(None、Swipe、Pattern、PIN、Password)
设置密码要求包含内容
- setPasswordMinimumLetters()
- setPasswordMinimumLowerCase()
- setPasswordMinimumUpperCase()
- setPasswordMinimumNonLetter()
- setPasswordMinimumNumeric()
- setPasswordMinimumSymbols()
设置密码最小长度
1 2
| int pwLength = 8; mDPM.setPasswordMinimumLength(deviceComponentName, pwLength);
|
设置最大密码错误重试次数
1 2
| int maxFailedPw = 5; mDPM.setMaximumFailedPasswordsForWipe(deviceComponentName, maxFailedPw);
|
设置密码失效时间
1 2
| long pwExpiration; mDPM.setPasswordExpirationTimeout(deviceComponentName, pwExpiration);
|
禁止使用旧密码个数
1 2
| int pwHistoryLength = 5; mDPM.setPasswordHistoryLength(deviceComponentName, pwHistoryLength);
|
锁住设备
1 2
| long timeMs = 1000L*Long.parseLong(mTimeout.getText().toString()); mDPM.setMaximumTimeToLock(deviceComponentName, timeMs);
|
或者可以直接锁屏
恢复出厂设置(慎用)
禁止使用摄像头
1
| mDPM.setCameraDisabled(deviceComponentName, true);
|
存储加密
1
| mDPM.setStorageEncryption(deviceComponentName, true);
|
总结
该功能一定程度上影响了安卓的安全,建议开发者慎用。
如果我们强制不让卸载,则需要在Receiver的onDisableRequested中作一些处理。可以参考http://2bab.me/2015/02/09/app-cannot-be-uninstalled/这篇文章的方式(强制锁屏绕过弹框操作)。