说在前面的话
为什么会把AccessibilityService叫做Android 中的另类钩子呢?搞过windows的都知道,钩子的含义就是能够监听到一切你想监听的内容,而Android中的AccessibilityService也可以监听到我们需要的某些功能。
用法
简介
AccessibilityService是一个辅助类,可以监听我们手机的焦点,窗口变化,按钮点击等等。实现它的服务需要在手机设置里面->辅助功能在这里面找到你自己实现的辅助类,然后打开它就可以进行我们一系列的监听了。
实例
现在我们要实现这样一个功能,当用户点击了安装包过后自动完成安装,因为在系统中,点击过安装包过后会弹出一个确认安装的选择界面。我们需要做的就是监听到安装的窗口弹出来过后就模拟用户点击确定操作,最后点击安装完成。这个过程j就需要用到我们的AccessibilityService来操作。
这里我先贴出代码然后慢慢的解释吧。首先我们还是新建一个类继承AccessibilityService。
public class WindowAccessibilitySeivice extends AccessibilityService
{
final String TAG = WindowAccessibilitySeivice.class.getSimpleName();
String installPackge[] = { "com.android.packageinstaller" };
@Override
protected void onServiceConnected()
{
super.onServiceConnected();
//可用代码配置当前Service的信息
// AccessibilityServiceInfo info = new AccessibilityServiceInfo();
// info.packageNames = installPackge; //监听过滤的包名
// info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK; //监听哪些行为
// info.feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN; //反馈
// info.notificationTimeout = 100; //通知的时间
// setServiceInfo(info);
}
@SuppressLint("NewApi")
private void findAndPerformAction(String text)
{
// 查找当前窗口中包含“安装”文字的按钮
if(getRootInActiveWindow()==null)
return;
//通过文字找到当前的节点
List<AccessibilityNodeInfo> nodes = getRootInActiveWindow().findAccessibilityNodeInfosByText(text);
for (int i = 0; i < nodes.size(); i++)
{
AccessibilityNodeInfo node = nodes.get(i);
// 执行按钮点击行为
if (node.getClassName().equals("android.widget.Button")&&node.isEnabled())
{
node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
}
@SuppressLint("NewApi")
@Override
public void onAccessibilityEvent(AccessibilityEvent event)
{
if (event.getSource() != null)
{
findAndPerformAction("安装");
findAndPerformAction("下一步");
findAndPerformAction("完成");
}
}
@Override
public void onInterrupt()
{
}
}
onAccessibilityEvent
这里面最重要的部分就是onAccessibilityEvent这个回调函数,当我们注册了监听事件的时候,当有事件发生就会通知我们这个函数,但是一定要注意这个函数通知是异步的,当然很多朋友就会问这个是怎么通知到这里来的呢?他是通过AccessibilityDelegate这个代理类,发送出来的,这个类有个方法sendAccessibilityEvent可以发送事件。那这个类又怎么和我们的窗口联系呢?这里举个例子。比如我们的View类里面有个setAccessibilityDelegate这个方法,是不是这下一切都明了了呢?然后就是调用我们的find函数去当前节点里面找到我们需要的节点信息,通过模拟点击事件来安装我们的软件,当然如果是输入框也是可以模拟输入的哦。
onServiceConnected
在这个回调函数里面可以配置我们当前的Service的信息,可以看我上面的代码都写得很清楚。但是记得也可以在我们的xml里面配置我们的Service的信息,这里我也是在xml里面配置的信息。在我们的res文件夹下面新建一个文件夹xml然后在里面新建一个xml文件accessibility.xml。
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackGeneric"
android:canRetrieveWindowContent="true"
android:description="@string/testaccessibility"
android:packageNames="com.android.packageinstaller"
android:notificationTimeout="100" />
这里需要提醒的是配置的时候packageNames这个就是你要监听的包名,这里我们需要监听的是安装的信息,所以包名就是com.android.packageinstaller,可以有多个用逗号隔开,accessibilityEventTypes这个是监听的事件。
记得配置我们的Service在Mainfiset清单里面。
<service
android:name="com.bobo.accessbility.WindowAccessibilitySeivice"
android:description="@string/testaccessibility"
android:label="accessibility"
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" />
</service>
写到这里基本上就可以安装和使用了。如果需要看更多的Demo可以看SDKdemo里面的com.example.android.apis.accessibility这个包下面的东西。
这里给出当前demo的下载地址传送门