Android锁屏错误密码监听遇设备管理员权限报错,求修复方案
开发一款安全应用,需求是用户输入锁屏错误密码时发送通知。搜索相关方案时找到的链接均失效,参考commonsguy的DeviceAdmin示例项目实现后,应用无法正常运行,持续抛出安全错误:No active admin owned by uid 10418 for policy #0。
相关代码如下:
MainActivity代码
ComponentName cn=new ComponentName(this, AdminReceiver.class); DevicePolicyManager mgr= (DevicePolicyManager)getSystemService(DEVICE_POLICY_SERVICE); if (mgr.isAdminActive(cn)) { int msgId; if (mgr.isActivePasswordSufficient()) { msgId=R.string.compliant; } else { msgId= R.string.not_compliant; } Toast.makeText(this, msgId, Toast.LENGTH_LONG).show(); } else { Intent intent= new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN); intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, cn); intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, getString(R.string.device_admin_explanation)); startActivity(intent); } finish();
AdminReceiver类代码
public class AdminReceiver extends DeviceAdminReceiver { @Override public void onEnabled(Context ctxt, Intent intent) { ComponentName cn = new ComponentName(ctxt, AdminReceiver.class); DevicePolicyManager mgr = (DevicePolicyManager) ctxt.getSystemService(Context.DEVICE_POLICY_SERVICE); mgr.setPasswordQuality(cn, DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC); onPasswordChanged(ctxt, intent); } @Override public void onPasswordChanged(Context ctxt, Intent intent) { DevicePolicyManager mgr = (DevicePolicyManager) ctxt.getSystemService(Context.DEVICE_POLICY_SERVICE); int msgId; if (mgr.isActivePasswordSufficient()) { msgId = R.string.compliant; } else { msgId = R.string.not_compliant; } Toast.makeText(ctxt, msgId, Toast.LENGTH_LONG).show(); } @Override public void onPasswordFailed(Context ctxt, Intent intent) { Toast.makeText(ctxt, R.string.password_failed, Toast.LENGTH_LONG) .show(); } @Override public void onPasswordSucceeded(Context ctxt, Intent intent) { Toast.makeText(ctxt, R.string.password_success, Toast.LENGTH_LONG) .show(); } }
XML配置文件(res/xml/device_admin.xml)
<device-admin xmlns:android="http://schemas.android.com/apk/res/android"> <uses-policies> <limit-password/> <watch-login/> </uses-policies> </device-admin>
请问该如何修复这个问题?
这个错误的核心原因是调用DevicePolicyManager的API时,传入的ComponentName对应的设备管理员未被激活,或者权限验证不通过,可从以下几个方面排查修复:
1. 确认AdminReceiver在AndroidManifest中正确注册
必须在Manifest中给AdminReceiver添加android.app.action.DEVICE_ADMIN_ENABLED的intent-filter,并且关联device-admin的xml配置,示例如下:
<receiver android:name=".AdminReceiver" android:description="@string/app_name" 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" /> <intent-filter> <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" /> </intent-filter> </receiver>
注意:android:permission="android.permission.BIND_DEVICE_ADMIN"是必填项,缺失会导致管理员无法被系统识别激活。
2. 避免直接调用onPasswordChanged方法
在onEnabled中直接调用onPasswordChanged(ctxt, intent)是错误的,此时传入的Intent并非密码变更触发的合法Intent,会导致DevicePolicyManager权限验证异常。正确做法是提取公共密码检查逻辑:
@Override public void onEnabled(Context ctxt, Intent intent) { ComponentName cn = new ComponentName(ctxt, AdminReceiver.class); DevicePolicyManager mgr = (DevicePolicyManager) ctxt.getSystemService(Context.DEVICE_POLICY_SERVICE); mgr.setPasswordQuality(cn, DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC); // 调用公共检查方法,而非直接触发onPasswordChanged checkPasswordCompliance(ctxt); } // 提取公共密码检查逻辑 private void checkPasswordCompliance(Context ctxt) { DevicePolicyManager mgr = (DevicePolicyManager) ctxt.getSystemService(Context.DEVICE_POLICY_SERVICE); int msgId = mgr.isActivePasswordSufficient() ? R.string.compliant : R.string.not_compliant; Toast.makeText(ctxt, msgId, Toast.LENGTH_LONG).show(); } @Override public void onPasswordChanged(Context ctxt, Intent intent) { checkPasswordCompliance(ctxt); }
3. 验证设备管理员激活结果
启动添加管理员的Intent后,需在onActivityResult中确认激活状态,避免在未激活时执行需要管理员权限的操作:
修改MainActivity代码,替换startActivity为startActivityForResult并添加结果回调:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ComponentName cn=new ComponentName(this, AdminReceiver.class); DevicePolicyManager mgr= (DevicePolicyManager)getSystemService(DEVICE_POLICY_SERVICE); if (mgr.isAdminActive(cn)) { int msgId = mgr.isActivePasswordSufficient() ? R.string.compliant : R.string.not_compliant; Toast.makeText(this, msgId, Toast.LENGTH_LONG).show(); finish(); } else { Intent intent= new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN); intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, cn); intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, getString(R.string.device_admin_explanation)); startActivityForResult(intent, 1001); } } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 1001) { if (resultCode == RESULT_OK) { Toast.makeText(this, R.string.admin_enabled, Toast.LENGTH_LONG).show(); } else { Toast.makeText(this, R.string.admin_not_enabled, Toast.LENGTH_LONG).show(); } finish(); } }
4. 适配Android版本权限
Android 10及以上对设备管理员权限验证更严格,需在Manifest中声明必要权限:
<uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
注:该权限为系统权限,普通应用无法直接获取,仅用于声明用途。
内容的提问来源于stack exchange,提问作者Berkay Isıkoglu

