AccessibilityService讲解
来源:互联网 发布:《南风知我意》 编辑:程序博客网 时间:2024/05/17 09:08
1.概念
AccessibilityService它运行在后台,而且当AccessibilityEvents事件被触发的时候系统会自动回调AccessibilityService中的相关方法。这些AccessibilityEvents事件表示用户界面上的一些状态的改变,例如:焦点发生变化,一个button被点击等等。AccessibilityService可以根据自己的需要查询活动窗口的内容(也就是说,界面中产生的任何变化都会产生一个时间,并由系统通知给AccessibilityService.这就像监视器监视着界面的一举一动,一旦界面发生变化,立刻发出警报。)我们要开发AccessibilityService需要继承AccessibilityService类并且实现里面的抽象方法即可。
1.5使用AccessibilityService类步骤
别看我下面写这么多,其实AccessibilityService用起来非常简单步骤如下:
1.继承AccessibilityService类,重写里面的方法(下面有介绍)2.在AndroidMainifest中注册(具体使用参考下面第3条)3.添加配置文件(具体使用参考下面第4条)
下面我们对继承AccessibilityService类里面需要重写的几个重要方法进行简单介绍:
1.onAccessibilityEvent()必须重写。通过这个函数可以接收系统发送来的AccessibilityEvent,接收来的AccessibilityEvent是经过过滤的,过滤是在配置工作时设置的。 2.onInterrupt()必须重写。这个在系统想要中断AccessibilityService返给的响应时会调用。在整个生命周期里会被调用多次。3.onServiceConnected()可选。在系统成功连接上这个AccessibilityService会调用。在这个方法里你可以做一下初始化工作。4.onUnbind()可选。在系统将要关闭这个AccessibilityService会被调用。在这个方法中进行一些释放资源的工作。
代码如下:
public class RobService extends AccessibilityService { @Override public void onAccessibilityEvent(AccessibilityEvent event) {} @Override public void onInterrupt() {} @Override protected void onServiceConnected() { } }
下面我们对继承AccessibilityService类里面需要重写的几个重要方法进行简单介绍:
1.onAccessibilityEvent()必须重写。通过这个函数可以接收系统发送来的AccessibilityEvent,接收来的AccessibilityEvent是经过过滤的,过滤是在配置工作时设置的。 2.onInterrupt()必须重写。这个在系统想要中断AccessibilityService返给的响应时会调用。在整个生命周期里会被调用多次。3.onServiceConnected()可选。在系统成功连接上这个AccessibilityService会调用。在这个方法里你可以做一下初始化工作。4.onUnbind()可选。在系统将要关闭这个AccessibilityService会被调用。在这个方法中进行一些释放资源的工作。
2.生命周期
要理解该中服务的生命周期只需要记住以下三点即可:
1.该种服务完全由系统管理,并遵循已有的服务周期.2.开启一个服务只能由用户在设置中打开,而关闭则只能由用户在设置中关闭或者服务本身通过diableSelf()方法关闭(当然,现在有些第三放软件也可以强制关闭该类型服务)3.系统绑定该服务之后,会调用onServiceConnected()方法,这个方法可以被重写,在其中,你可以做一些初始化的操作.
3.声明AccessibilityService
声明一个AccessibilityService和在menifest中声明其他service一样,但是必须做2件事情:
1.配置<intent-filter>,其name为固定的2.声明BIND_ACCESSIBILITY_SERVICE权限,以便系统能够绑定该服务(4.1版本后要求)
注意:任何一点配置错误,系统都检测不到该服务,因此在menifest中其固定配置如下:
<service android:name=".MyAccessibilityService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService" /> </intent-filter> . . . </service>
4.配置
官网是这样解释的:
AccessibilityService可以添加一些配置信息,目的是接收一些特定的事件.例如:监听特定的包、检索windows内容、在给定的时间范围内只允许从每种类型获取事件一次等等。
android给我们提供2种配置方法:
方法1:meta-data标签方式:
在manifest声明的servce中提供一个meta-data标签,然后通过android:resource指定相应的配置文件(在res目录下创建xml文件,并在其中创建配置文件accessibilityservice.xml):
<service android:name=".MyAccessibilityService"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService" /> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibilityservice" /></service>
接下来我们看看accessibilityservice.xml中有什么信息:
<?xml version="1.0" encoding="utf-8"?> <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeNotificationStateChanged|typeWindowStateChanged|typeWindowContentChanged" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagDefault" android:canRetrieveWindowContent="true" android:notificationTimeout="100" android:packageNames="com.tencent.mm" />
注意:此方法可以设置所有属性。我们在只需要仿照该配置文件根据自己的需求进行修改即可.
方法2:调用setServiceInfo(AccessibilityServiceInfo)方式:
注意
1.这个方法可以在任何时候调用,动态的去改变service配置信息2.这个方法只能用来配置动态属性,如:eventTypes,feedbackType,flags,notificationTimeout,packageNames
通常是在onServiceConnected()进行配置,如下代码:
@Overrideprotected void onServiceConnected() { AccessibilityServiceInfo serviceInfo = new AccessibilityServiceInfo(); serviceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK; serviceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC; serviceInfo.packageNames = new String[]{"com.tencent.mm"}; serviceInfo.notificationTimeout=100; setServiceInfo(serviceInfo);}
在这里涉及到了AccessibilityServiceInfo类,做个说明:
AccessibilityServiceInfo该类被用于配置AccessibilityService信息,该类中包含了大量用于配置的常量字段及用来xml 属性,比如常见的android:accessibilityEventTypes,android:canRequestFilterKeyEvents,android:packageNames等等,更多信息参见官方文档
这里,简单的对重要属性进行说明:
accessibilityEventTypes:表示该服务对界面中的哪些变化感兴趣,即哪些事件通知,比如窗口打开,滑动,焦点变化,长按等.具体的值可以在AccessibilityEvent类中查到,如typeAllMask表示接受所有的事件通知.accessibilityFeedbackType:表示反馈方式,比如是语音播放,还是震动canRetrieveWindowContent:表示该服务能否访问活动窗口中的内容.也就是如果你希望在服务中获取窗体内容的化,则需要设置其值为true.notificationTimeout:接受事件的时间间隔,通常将其设置为100即可.packageNames:表示对该服务是用来监听哪个包的产生的事件
5.检索窗口内容
仅仅知道事件的信息是不够的,我们还希望通过事件来获取发出该事件(事件源)的信息,比如Button按钮被点击时它的text.一个服务可以配置为可以检索窗口内容,即获取窗口内容.整个窗口内容本质上是关于AccessibilityWindowInfo和AccessibilityNodeInfo的树结构,我称之为内容树.(类似View Tree,但由不完全相同)
需要注意,该服务可能配置了只检测了部分事件,而不是全部事件,这就意味着,当内容树发生变化后,该服务可能并不知道,即该服务无法及时的了解当前的内容树是否发生了变化.比如说,你的服务只检测了点击事件,但是此时界面的输入焦点已经变化,这样整个结点树也发生了变化,但是你的服务却不知道,此时你在结点中拿到的窗口内容可能已经不是最新的了.因此,如果你想及时的获知当前窗口的内容,那么就在配置的时候,设置监听全部事件.
正如上面所提到的,要想获取窗口内容,,在配置AccessibilityService时需设置canRetrieveWindowContent为true.之后,便可以通过AccessibilityEvent.getSource(),findFocus(int),getWindow()或者getRootInActiveWindow()获取窗口内容.
6.启动服务
当我们做完以上操作,便可将app安装到手机.安装成功后,在设置->辅助功能中便可以找到我们的服务.该服务默认处在关闭状态,需要手动开启.
7.获取事件信息
上面我们说道,onAccessibilityEvent(AccessibilityEvent event)是该服务的核心方法,其中参数event封装来自界面相关事件的信息,比如我们可以获得该事件的事件类型,进而根据起类型选择不同的处理方式:
public void onAccessibilityEvent(AccessibilityEvent event) { int eventType = event.getEventType(); switch (eventType) { case AccessibilityEvent.TYPE_VIEW_CLICKED: //界面点击 break; case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED: //界面文字改动 break; }}
这里我们对AccessibilityEvent进行简单的说明:
当用户发生发生变化时,系统会发送一系列的AccessibilityEvent事件,比如按钮被电击时会发送TYPE_VIEW_CLICKED类型的事件.
getEventType() 事件类型 getSource() 获取事件源对应的结点信息 getClassName() 获取事件源对应类的类型,比如点击事件是有某个Button产生的,那么此时获取的就是Button的完整类名 getText()获取事件源的文本信息,比如事件是有TextView发出的,此时获取的就是TextView的text属性.如果该事件源是树结构,那么此时获取的是这个树上所有具有text属性的值的集合 isEnabled()事件源(对应的界面控件)是否处在可用状态getItemCount()如果事件源是树结构,将返回该树根节点下子节点的数量
系统不断的产生各种事件,有些是界面控件产生的,有些是系统产生的.对于由界面控件的产生的事件,通常我们将该控件称之为事件源.并不是所有的事件都能通过getSource()方法获取到事件源,比如像通知消息类型的事件(TYPE_NOTIFICATION_STATE_CHANGED).
**注意:**onAccessibilityEvent回调函数非常重要,当我们注册了监听事件的时候,当有事件发生就会通知我们这个函数,但是一定要注意这个函数通知是异步的,
8. 检测服务是否开启
介绍了一些AccessibilityService的基础知识之后,再补充一点关于检测某个服务是否开启的知识.通常来说大体有一下两种方法:
方法一:借助服务管理器AccessibilityManager来判断,但是该方法不能检测app本身开启的服务.
private boolean enabled(String name) { AccessibilityManager am = (AccessibilityManager) getSystemService(Context.ACCESSIBILITY_SERVICE); List<AccessibilityServiceInfo> serviceInfos = am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_GENERIC); List<AccessibilityServiceInfo> installedAccessibilityServiceList = am.getInstalledAccessibilityServiceList(); for (AccessibilityServiceInfo info : installedAccessibilityServiceList) { Log.d("MainActivity", "all -->" + info.getId()); if (name.equals(info.getId())) { return true; } } return false;}
既然谈到了AccessibilityManager,那么在这里我们就做个简单的介绍:
AccessibilityManager是系统级别的服务,用来管理AccessibilityService服务,比如分发事件,查询系统中服务的状态等等,更多信息参考官方文档
getAccessibilityServiceList() 获取服务列表(api 14之后废弃,用下面的方法代替)getInstalledAccessibilityServiceList() 获取已安装到系统的服务列表getEnabledAccessibilityServiceList(int feedbackTypeFlags) 获取已启用的服务列表isEnabled() 判断服务是否启用sendAccessibilityEvent(AccessibilityEvent event) 发送事件
方法二:我们知道大部分的系统属性都在settings中进行设置,比如wifi,蓝牙状态等,而这些信息主要是存储在settings对应的的数据库中(system表和serure表),同样我们也可以通过直接读取setting设置来判断相关服务是否开启:
private boolean checkStealFeature1(String service) { int ok = 0; try { ok = Settings.Secure.getInt(getApplicationContext().getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED); } catch (Settings.SettingNotFoundException e) { } TextUtils.SimpleStringSplitter ms = new TextUtils.SimpleStringSplitter(':'); if (ok == 1) { String settingValue = Settings.Secure.getString(getApplicationContext().getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); if (settingValue != null) { ms.setString(settingValue); while (ms.hasNext()) { String accessibilityService = ms.next(); if (accessibilityService.equalsIgnoreCase(service)) { return true; } } }
9.我们把AccessibilityServic用歪了
官网上明确说明了,AccessibilityServic是用来帮助残障人使用的。google大神们的想法是非常好的,但是现在对它的使用越来越偏离了它的设计初衷。AccessibilityServic用途非常广泛,下面我们就来总结一下:
1.apk自动安装。
2.微信抢红包和自动回复
3.防卸载自己的app
4.监控密码框(呵呵,这个你真想多了,系统还算有点良心,所有的设置为password类型的EditText都是无法被监控的。)
5.浏览器地址栏劫持、搜索劫持、桌面点击劫持以及防卸载等(参考这篇文章)
参考文献
1.深入了解AccessibilityService
2.官网
3.AccessibilityService从入门到出轨
结尾
AccessibilityServic是一把双刃剑,希望大家能正确对待它。
自己在技术上依旧是个小渣渣,加油勉励自己!
- AccessibilityService讲解
- AccessibilityService
- AccessibilityService
- AccessibilityService
- AccessibilityService
- AccessibilityService
- AccessibilityService
- AccessibilityService
- AccessibilityService ClassNotFoundExcepiton
- AccessibilityService简介
- Accessibilityservice学习
- android-AccessibilityService
- AccessibilityService详解
- Android AccessibilityService
- AccessibilityService详解
- 理解AccessibilityService
- android.accessibilityservice包介绍
- android AccessibilityService的用法
- linux mysql远程连接
- jquery eq
- 你不知道的javascript(六)
- ubuntu12.04 卸载wine的windows程序
- C++中GB2312字符串和UTF-8之间的转换
- AccessibilityService讲解
- 一流大学、一流学科
- Effective Java学习笔记一(静态工厂方法、JavaBeans模式、builder模式)
- 80端口被占用了怎么办
- JAVA面向对象知识点详解
- Prime Ring Problem HDU - 1016
- 深入理解HTTP协议、HTTP协议原理分析
- js关闭当前页面刷新父页面
- 窗口不同初始化以及单次实例化的方案