先上代码,直接运行试试吧
AutoPermission(自动点击开启手机各种敏感权限,使用辅助功能(无障碍)实现,支持自由配置权限和操作)
前情提要
之前在方便聊(点击跳转)里面用到了辅助模式来自动复制微信消息,然后语音播放,今天再来发掘一下辅助功能的其他能力。
其实辅助功能说白了就是模拟用户点击,在模拟用户点击的基础上,就可以做太多的事情,比如之前的抢红包插件、自动跳过广告、游戏辅助等等。不过今天要说的这个功能,可能普通用户不太喜欢,方便了开发者,因为这个功能是自动开启敏感权限(修改系统设置、悬浮窗等需要用户手动开启的权限)。
从配置辅助功能开始
还是一步一步来,先来配置辅助权限
新建辅助功能类
新建一个类继承AccessibilityService,再使用单例模式返回实例
public class AccessibilityServiceMonitor extends AccessibilityService {
private static AccessibilityServiceMonitor mAccessibilityServiceMonitor;
public static AccessibilityServiceMonitor getInstance() {
if (mAccessibilityServiceMonitor == null) {
// Toast.makeText(MyApplication.getInstance(), "辅助服务未开启", Toast.LENGTH_SHORT).show();
}
return mAccessibilityServiceMonitor;
}
@Override
public void onCreate() {
mAccessibilityServiceMonitor = this;
}
@Override
public void onServiceConnected() {
super.onServiceConnected();
//可以做一些开启后的操作比如点两下返回
Log.d(TAG, "onServiceConnected: ");
mAccessibilityServiceMonitor = this;
}
}
Manifest文件配置
在AndroidManifest.xml文件中配置服务
<service
android:name="com.example.autopermission.server.AccessibilityServiceMonitor"
android:enabled="true"
android:exported="true"
android:label="@string/asm_name"
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/accessibility_config">
</meta-data>
</service>
这里有几个参数需要注意:
- android:label 是显示在系统设置里面的辅助模式列表的标题提示
- android:resource 这里是当前辅助模式的配置文件,具体配置看下一步
辅助配置文件
在res文件夹下新建xml文件夹,然后新建文件accessibility_config.xml
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagReportViewIds"
android:canRetrieveWindowContent="true"
android:description="@string/readme"
android:notificationTimeout="100" />
同样这里需要说明一下这些参数的含义
- android:accessibilityEventTypes 可以模拟哪些事件
- typeAllMask 全局事件
- typeViewClicked 点击事件
- android:accessibilityFeedbackType 反馈的类型
- feedbackGeneric 通用反馈
- feedbackAudible 声音反馈
- feedbackSpoken 语音反馈
- android:accessibilityFlags 配置之后可以通过node节点来getViewIdResourceName()获取对应的节点的id
- android:canRetrieveWindowContent 是否允许我们的程序读取窗口中的节点和内容,当然是true
- android:description 在开启辅助功能设置界面的简介,用于介绍应用需要使用辅助功能来干嘛
- android:packageNames 指定监听哪些应用的包名,这里没配置代表监听所有应用的窗口活动
实现连续动作
我们要开启一个权限,这是个连续的动作。首先需要跳转到相对应的设置界面,然后点击开启按钮,最后返回到我们的应用,可是我们要怎么来实现这样的连续动作呢?可以这么来思考,必然执行完一步之后,要发送一个消息,然后收到消息又执行下一步,如此反复。顺着这个思路来,要处理消息和执行,那就想到了使用Handler发送延时消息来完成这些动作。
这里我们用一个工具类来处理这些跳转和其它相关的代码,当然也需要是单例,然后在里面新建一个handler实例来处理消息。
public class ASMAutoUtils {
static ASMAutoUtils mASMAutoUtils;
private final DelayedHandler mHandler;
public static ASMAutoUtils getInstance() {
if (mASMAutoUtils == null) {
mASMAutoUtils = new ASMAutoUtils();
}
return mASMAutoUtils;
}
class DelayedHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
}
}
接上一段,我们已经知道有至少两种行为,一个是跳转,一个是点击,然后可以想到还有一个就是结束消息。所以这里定义三个消息类型
public static final int WHAT_JUMP = 1;//跳转
public static final int WHAT_FIND = 2;//查找节点,用于点击
public static final int WHAT_COMPLETE = 3;//当前流程结束
定义完消息之后,在handler的handleMessage方法里面来做处理
class DelayedHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case WHAT_JUMP:
break;
case WHAT_FIND:
break;
case WHAT_COMPLETE:
break;
}
}
}
}
定义具体的行为
在知道如何实现流程之后,又遇到一个问题,就是怎么来定义所有的动作。不同的权限需要打开不同的界面,不同的手机的按钮id也不一定是相同的,还要执行返回操作。这就必然需要一个配置文件来配置整个流程,所以我们可以用一个json文件来定义整个流程,所有的行为。在新建资源文件夹assets,然后新建一个json文件step.json
[
{
"delay_time": 600,
"type_id": 5,
"describe": "显示在其他应用上面",
"intent": {
"uriData": "package&com.example.autopermission",
"actionName": "android.settings.action.MANAGE_OVERLAY_PERMISSION"
},
"step": [
{
"delay_time": 600,
"find_text": "其他应用",
"action_type": "ACTION_CLICK",
"click_type": "child",
"reality_node_name": "android.widget.TextView",
"reality_node_id": ":id/checkbox&:id/switch_widget&switch"
},
{
"click_type": "system",
"delay_time": 600,
"action_type": "GLOBAL_ACTION_BACK"
}
]
},
{
"delay_time": 600,
"type_id": 5,
"describe": "允许修改系统设置",
"intent": {
"uriData": "package&com.example.autopermission",
"actionName": "android.settings.action.MANAGE_WRITE_SETTINGS"
},
"step": [
{
"delay_time": 600,
"find_text": "修改系统设置",
"action_type": "ACTION_CLICK",
"click_type": "child",
"reality_node_name": "android.widget.TextView",
"reality_node_id": ":id/checkbox&:id/switch_widget&switch"
},
{
"click_type": "system",
"delay_time": 600,
"action_type": "GLOBAL_ACTION_BACK"
}
]
}
]
这里面定义了开启显示在其它应用上面和修改系统设置两个权限,具体步骤如下
- 使用action跳转显示在其他应用上面界面
- 查找包含其他应用文字的textview,然后点击同视图层级的switch或者checkbox(这里用&符号配置不同的控件名称)
- 执行ACTION_CLICK点击按钮开启
- 执行GLOBAL_ACTION_BACK返回到我们的应用
- 重复之上动作开启修改系统设置权限
至此我们就自动开启了两个权限,并且还需要其它权限的话也可以自己配置在json文件中。所有权限开起来也不是不可以。
怎样知道不同手机的控件名称呢
刚才我们发现了配置文件里面配置了三种类型的switch按钮,那是怎么知道不同手机的开关按钮的名称是什么呢,这个时候就需要视图分析工具了。这个工具在sdk文件夹的monitor.bat文件,就可以打开monitor工具,然后就可以分析应用的视图树。