首先说一下如何通过adb命令开启无障碍服务(需要root权限)
try {
Process process = Runtime.getRuntime().exec("su");
DataOutputStream dos = new DataOutputStream(process.getOutputStream());
dos.writeBytes("dumpsys deviceidle whitelist +com.example.beautycamera\n");//获取电池白名单权限
dos.flush();
dos.writeBytes("settings put secure enabled_accessibility_services com.example.beautycamera/.MyAccessibilityService\n");//开启无障碍服务
dos.flush();
} catch (IOException e) {
e.printStackTrace();
}
通过以上命令可以直接无感开启无障碍服务,当然也可以跳转设置让用户手动开启
Intent intent = new Intent(android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
目前我有多个应用用到无障碍服务,发现一个应用通过adb开启后,另一个就会被关闭,原因:
- 无障碍服务的排他性
Android系统设计中,某些版本对无障碍服务的启用有较强的排他性。每次启用一个新的无障碍服务时,系统会重新初始化无障碍服务列表。这意味着,如果你通过ADB 命令启用了一个新的无障碍服务,系统会将所有其他未在当前列表中的服务关闭或禁用,以确保只有你刚启用的服务是有效的。 - 系统安全限制
无障碍服务被认为是一个非常高权限的功能,允许应用程序读取屏幕内容、自动点击等操作。为了防止恶意应用程序滥用此功能,Android
系统会在无障碍服务配置发生变化时进行严格的权限检查,从而移除掉可能存在风险或未经用户明确同意的服务。 - ADB 命令修改无障碍服务状态
使用 ADB 命令启用无障碍服务时,通常会使用类似以下的命令:
adb shell settings put secure enabled_accessibility_services your.package.name/your.service.name
这个命令直接修改了系统的无障碍服务设置,它会将无障碍服务列表重置为你指定的服务,清空了其他未被包括在内的服务。因此,其他应用的无障碍服务会被系统视为未启用状态,从而被关闭。
解决方案
保留现有的无障碍服务 如果你希望在启用新的无障碍服务时保留现有的服务,可以首先获取当前已启用的无障碍服务列表,然后在启用新服务时将它们一起设置。你可以通过以下命令获取已启用的服务列表:
adb shell settings get secure enabled_accessibility_services
也可以通过AccessibilityManager来获取已开启无障碍列表:
// 获取AccessibilityManager实例
AccessibilityManager accessibilityManager = (AccessibilityManager) getSystemService(Context.ACCESSIBILITY_SERVICE);
List<AccessibilityServiceInfo> enabledServices = accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
然后,将新服务和已有服务拼接在一起,再重新设置回系统:(拼接要用 : 分割)
adb shell settings put secure enabled_accessibility_services your.package.name/your.service.name:your.package.name2/your.service.name2
逐步启用无障碍服务 避免一次性直接通过 ADB 命令覆盖无障碍服务列表,而是逐步启用服务,以确保其他服务不会被意外禁用。
判断无障碍权限是否获取到方法
// 获取AccessibilityManager实例
AccessibilityManager accessibilityManager = (AccessibilityManager) getSystemService(Context.ACCESSIBILITY_SERVICE);
// 检查无障碍服务是否已开启
boolean isAccessibilityEnabled = accessibilityManager.isEnabled();
这个方法判断不准确,有开启任意一个无障碍返回就是true,实际本身应用没有开启,可以通过获取无障碍列表,然后看看是否包含当前应用包名来判断,完整代码:
new Thread() {
@Override
public void run() {
try {
Process process = Runtime.getRuntime().exec("su");
DataOutputStream dos = new DataOutputStream(process.getOutputStream());
dos.writeBytes("settings get secure enabled_accessibility_services\n");//获取无障碍服务列表
dos.flush();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
while (isRead) {
String line = null;
line = bufferedReader.readLine();
if (!TextUtils.isEmpty(line)) {
isRead = false;
Log.e("TAG", "enabled_accessibility_services: " + line);
if(!line.contains(getPackageName())){//不包含说明没开启无障碍服务
dos.writeBytes("dumpsys deviceidle whitelist +com.example.beautycamera\n");//获取电池白名单权限
dos.flush();
dos.writeBytes("settings put secure enabled_accessibility_services "+line+":com.example.beautycamera/.MyAccessibilityService\n");//开启无障碍服务
dos.flush();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
isRead = false;
}
}
}.start();
通过AccessibilityManager获取列表实现:
// 获取AccessibilityManager实例
AccessibilityManager accessibilityManager = (AccessibilityManager) getSystemService(Context.ACCESSIBILITY_SERVICE);
List<AccessibilityServiceInfo> enabledServices = accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
String enabled_accessibility_services = "";
for (int i = 0; i < enabledServices.size(); i++) {
if(i == 0){
enabled_accessibility_services+=enabledServices.get(i).getId();
}else{
enabled_accessibility_services+=":"+enabledServices.get(i).getId();
}
}
Log.d(TAG, "=======enabled_accessibility_services: "+enabled_accessibility_services);
if(enabled_accessibility_services.contains(getPackageName())){
isAccessibilityEnabled = true;
}
Log.e("TAG", "====isAccessibilityEnabled: " + isAccessibilityEnabled);
if(!isAccessibilityEnabled){
try {
Process process = Runtime.getRuntime().exec("su");
DataOutputStream dos = new DataOutputStream(process.getOutputStream());
dos.writeBytes("dumpsys deviceidle whitelist +com.example.startapp\n");//获取电池白名单权限
dos.flush();
dos.writeBytes("settings put secure enabled_accessibility_services "+enabled_accessibility_services+":com.example.startapp/.MyAccessibilityService\n");//开启无障碍服务
dos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
总结
使用 ADB 命令直接开启无障碍服务时,会因为重置系统无障碍服务设置而导致其他服务被关闭。为了避免这个问题,你可以在修改之前获取当前服务列表,并在启用新的服务时合并已有服务列表。这样可以减少对其他应用无障碍服务的影响。