最近看到一个项目比如说需要允许访问应用权限、以及录屏等权限的时候 在手机运行的时候点击跳转至无障碍界面点击打开无障碍服务,然后调转至设置界面,然后手机就自动的一步一步的打开App所需的权限,看起来特别牛逼和智能的亚子。了解了一下发现通过AccessibilityService这个类可以完成上述需求。但是由于每款手机的设置界面是不相同的,所以需要做不同的机型判断适配机型。我的是在华为 Honor 9i(Android 9.0系统)中完成自动设置权限的功能的。
关于AccessibilityService类我就不做过多的解释了,直接撸代码
1.在清单文件的application中添加:
<service
android:name="com.hxf.childapp.AutoDebugService"
android:enabled="true"
android:exported="true"
android:label="你的包名"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/autodebug"/>
</service>
2.配置需要监听的包名和行为,也就是@xml/autodebug文件:在xml文件夹中创建autodebug文件。
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask|typeWindowStateChanged|typeWindowContentChanged"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagReportViewIds"
android:canPerformGestures="true"
android:notificationTimeout="100"
android:canRetrieveWindowContent="true"
android:packageNames="com.android.settings" />
这里说一下 android:packageNames中的值就是需要监听的应用。
3.创建AutoDebugService类继承自AccessibilityService类:
public class AutoDebugService extends AccessibilityService {
}
4.重写方法:
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
}
需要重写的核心方法 所有事件都是从这个方法监听的,比如界面改变,点击,长按等事件。
5.通过事件判断是否监听:
if (AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED == event.getEventType() || AccessibilityEvent.TYPE_VIEW_CLICKED == event.getEventType()) {
}
此处我是通过界面改变和点击事件进行过滤,逻辑都是写在此回调方法中,
以下就是全部代码,只供参考思路,不同的手机是需要适配的。
public class AutoDebugService extends AccessibilityService {
int index = 0;
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
if (AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED == event.getEventType() || AccessibilityEvent.TYPE_VIEW_CLICKED == event.getEventType()) {
if (step == 0) {
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED == event.getEventType()) {
event("com.android.settings:id/dashboard_container", "帐户");
Log.e("lee", step + "*******");
}
} else if (step == 1) {
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED == event.getEventType()) {
Log.e("lee", step + "*******");
back();
}
} else if (step == 2) {
if (AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED == event.getEventType()) {
back();
}
} else if (step == 3) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED == event.getEventType()) {
event("com.android.settings:id/dashboard_container", "安全和隐私");
}
} else if (step == 4) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
back();
} else if (step == 5) {
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
back();
} else if (step == 6) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
event("com.android.settings:id/dashboard_container", "桌面和壁纸");
} else if (step == 7) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
event("com.android.settings:id/list", "桌面风格");
} else if (step == 8) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
event("com.android.settings:id/normal_l_ui_sector", "标准风格");
} else if (step == 9) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
back();
} else if (step == 10) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
back();
} else if (step == 11) {
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
back();
} else if (step == 12) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
event("com.android.settings:id/dashboard_container", "应用");
} else if (step == 13) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
event("com.android.settings:id/list", "应用分身");
} else if (step == 14) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
check("com.android.settings:id/clone_app_switche");
} else if (step == 15) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
back();
} else if (step == 16) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
back();
} else if (step == 17) {
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
back();
} else if (step == 18) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
event("com.android.settings:id/dashboard_container", "应用");
} else if (step == 19) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
event("com.android.settings:id/list", "应用启动管理");
} else if (step == 20) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
check("com.huawei.systemmanager:id/app_control_switch");
} else if (step == 21) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
back();
} else if (step == 22) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
back();
} else if (step == 23) {
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
back();
} else if (step == 24) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
event("com.android.settings:id/dashboard_container", "系统");
} else if (step == 25) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
event("com.android.settings:id/list", "开发人员选项");
} else if (step == 26) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
event("com.android.settings:id/list", "USB 调试");
} else if (step == 27) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
back();
} else if (step == 28) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
back();
} else if (step == 29) {
Log.e("lee", step + "*******");
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
back();
}
}
}
/**
* 通过Id获取AccessibilityNodeInfo
*
* @param id
* @return
*/
private List<AccessibilityNodeInfo> findNodesById(String id) {
AccessibilityNodeInfo root = getRootInActiveWindow();
if (root != null) {
return root.findAccessibilityNodeInfosByViewId(id);
}
return null;
}
/**
* 通过Text获取AccessibilityNodeInfo
*
* @param text
* @return
*/
private List<AccessibilityNodeInfo> findNodesByText(String text) {
AccessibilityNodeInfo root = getRootInActiveWindow();
if (root != null) {
return root.findAccessibilityNodeInfosByText(text);
}
return null;
}
/**
* 处理事件
*
* @param id
* @param text
*/
private void event(String id, String text) {
List<AccessibilityNodeInfo> byIdList = findNodesById(id);
List<AccessibilityNodeInfo> byTextList = findNodesByText(text);
if (byTextList != null && byTextList.size() > 0) {
AccessibilityNodeInfo info = byTextList.get(0);
if (!info.isChecked()) {
info.getParent().performAction(AccessibilityNodeInfo.ACTION_CLICK);
step++;
} else {
byTextList.get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK);
step++;
}
} else {
if (byIdList != null && byIdList.size() > 0) {
byIdList.get(0).performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
}
}
}
private void check(String id) {
List<AccessibilityNodeInfo> byIdList = findNodesById(id);
if (byIdList != null && byIdList.size() > 0) {
for (int i = 0; i < byIdList.size(); i++) {
if (!byIdList.get(i).isChecked()) {
byIdList.get(i).performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
}
step++;
}
/**
* 返回上一层级
*/
private void back() {
performGlobalAction(GLOBAL_ACTION_BACK);
step++;
}
}
调用的方法,先判断是否打开了无障碍服务: 如果打开了就跳转到设置界面进行一步一步的设置
if (isAccessibilitySettingsOn(AutoDebugService.class.getName())) {//打开了无障碍权限
Intent intent = new Intent(Settings.ACTION_SETTINGS);
startActivity(intent);
}
未打开的话就去打开:
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
startActivityForResult(intent, REQUEST_ACCESSIBLE_PERMISSION);
以上就完成了自动设置权限的功能。 如果不知道视图的id 可以使用sdk自带的DDMS工具查看视图。
|