AccessibilityService根据官方的介绍,是指开发者经过增长相似contentDescription的属性,从而在不修改代码的状况下,让残障人士可以得到使用体验的优化,你们能够打开AccessibilityService来试一下,点击区域,能够有语音或者触摸的提示,帮助残障人士使用App。javascript
固然,如今AccessibilityService已经基本偏离了它设计的初衷,至少在国内是这样,愈来愈多的App借用AccessibilityService来实现了一些其它功能,甚至是灰色产品。html
老规矩,官网镇楼
developer.android.com/guide/topic…
developer.android.com/training/ac…java
要使用AccessibilityService实际上很是简单,通常来讲,只须要如下三步便可。node
public class MyAccessibility extends AccessibilityService {
private static final String TAG = "xys";
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
Log.d(TAG, "onAccessibilityEvent: " + event.toString());
}
@Override
public void onInterrupt() {
}
}复制代码
其中有两个必须实现的方法:onAccessibilityEvent和onInterrupt。android
在onAccessibilityEvent中,咱们能够接收所监听的事件。不熟悉这些事件的话,只须要使用toString把这些信息打出来,本身多看几个Log,就大概可以了解了。git
在资源目录res下新建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="feedbackSpoken" android:canRetrieveWindowContent="true" android:notificationTimeout="1000"/>复制代码
里面有一些比较简单的配置。github
其中 description 为 用户容许应用的辅助功能的说明字符串,这里没有指定所要辅助的应用packageNames,当没有指定时,默认辅助全部的应用,建议你们在使用时,指定须要监听的包名(你能够经过|来进行分隔),而不是全部的包名。typeAllMask是设置响应事件的类型,feedbackGeneric是设置回馈给用户的方式,有语音播出和振动。shell
在AndroidMainifest中注册:数据库
<service
android:name=".MyAccessibility"
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>复制代码
完成以上步骤后,一个AccessibilityService就可使用了,你要知道的是,AccessibilityService具备很高的系统权限,因此,系统不会让App直接设置是否启用,须要用户进入设置-辅助功能中去手动启用,这样在必定程度上,保护了用户数据的安全。
不少人可能对AccessibilityService了解的不是很深刻,因此认为AccessibilityService是在调用一些系统服务来自动执行一些操做,实际上,这个理解不能算错,固然也不全对,我以为你能够把AccessibilityService理解为——『按键精灵』。相信不少开发者都玩过PC上的这款软件,他的做用,就是将你一次操做的整个记录,录制下来,而后就能够根据这个记录,重复的执行这些操做,例如:先点击某个输入框,再输入XXXX,再输入验证码,最后点击某按钮,这些操做若是须要重复执行,那么显然是一套机械的步骤,那么经过按键精灵,记录下这些操做后,直接经过脚本就能够完成这些操做。其实AccessibilityService跟这个是同样的,咱们记录的,实际上就是咱们的操做步骤,或者称之为『脚本』,那么系统在监控整个手机的各类AccessibilityService事件时,就会根据咱们的逻辑来判断该使用哪个脚本。
所以,咱们彻底能够抽象出一个基类AccessibilityService,并抽象出一些脚本的事件,例如,根据Text查找对应的View、点击某个View、滑动、返回等等,因此,我在这里封装了一个BaseAccessibilityService,这里就不贴具体的代码了,你们能够参考个人Github:
不知道从何时开始,AccessibilityService忽然从一个残障人士使用的辅助服务,一跃变成了各类App的黑科技,利用AccessibilityService来作的事情,也愈来愈偏离了AccessibilityService设计的初衷,各类安全问题也随之暴露出来,Google的理想是好的,愿天下都是安分守己的程序员。
这个也许是能考证的最先利用AccessibilityService的使用场景了,最先在一些应用市场中出现,例如用户一次下载了不少App,那么每一个App下载完毕后都会弹出安装界面,并且须要用户手动去处理,确实体验不太好,因此后来就出现了利用Root权限来静默安装App的功能,但如今普通用户Root的需求愈来愈少,因此,AccessibilityService来实现免Root自动安装的黑科技,才走上了桌面。
那么按照咱们前面的思路,要实现自动安装,实际上就是把手动安装的步骤脚本化。通常来讲,咱们要安装一个App,会经过如下几个步骤:
那么这些流程化的操做,咱们就彻底能够经过脚原本实现,下面就是一些简单的代码实现。
调用系统安装Intent:
public void autoInstall(View view) {
String apkPath = Environment.getExternalStorageDirectory() + "/test.apk";
Uri uri = Uri.fromFile(new File(apkPath));
Intent localIntent = new Intent(Intent.ACTION_VIEW);
localIntent.setDataAndType(uri, "application/vnd.android.package-archive");
startActivity(localIntent);
}复制代码
监控安装界面,并根据逻辑处理点击:
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
super.onAccessibilityEvent(event);
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED &&
event.getPackageName().equals("com.android.packageinstaller")) {
AccessibilityNodeInfo nodeInfo = findViewByText("安装", true);
if (nodeInfo != null) {
performViewClick(nodeInfo);
}
}
}复制代码
代码写完才发现,看似很牛逼的自动安装,其实不过十几行代码。惟一复杂的,就是抽象化这些流程了。
抢红包应该是AccessibilityService火起来的最大因素。网上借助AccessibilityService来实现的抢红包插件也是数不胜数,又是一个看上去很牛逼的功能。那么咱们再来分析下,你是怎么抢红包的。
加入你如今在桌面,怎么知道有红包了呢?哦,看通知栏,出现了『微信红包』这几个关键字,而后,你点击这条通知进去,点击红包的那条消息,而后再点击拆红包的按钮,返回,回到桌面。
这样一看,抢红包彻底是一个体力活啊,若是有个机器人能帮助我完成上面的动做,根本不用我抢啊,对的,这个机器人就是AccessibilityService,咱们一样把抢红包流程化。
这每一个步骤,也都不难啊,咱们的工具类中,全部的方法都实现了,惟一要作的,就是写几个ifelse把逻辑拼起来就好了,具体代码就不贴了,毕竟是微信严打的一件事,你们适可而止就行了。
固然,这个Demo一样能够作的更完善一点,例如,增长WakeLock和Keyguard,实如今锁屏状况下的自动抢红包等功能。
在了解了微信抢红包的方式以后,再看看微信自动回复,是否是就更是小菜一碟了?咱们只要把抢红包的流程稍微改一下,就完成了整个功能的实现,不相信?
是否是很是简单?惟一一个有价值的代码以下:
private void notifyWechat(AccessibilityEvent event) {
if (event.getParcelableData() != null && event.getParcelableData() instanceof Notification) {
Notification notification = (Notification) event.getParcelableData();
String content = notification.tickerText.toString();
String[] msg = content.split(":");
name = msg[0].trim();
text = msg[1].trim();
PendingIntent pendingIntent = notification.contentIntent;
try {
pendingIntent.send();
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
}
}复制代码
一个简单的Trick而已,借用notification.contentIntent来唤起Notification对应的App。
实际上,咱们能作的事情还有不少,当咱们拿到对应的聊天信息时,能够经过聊天对象的筛选,来实现对『特别对象的监控』,例如你离开的时候,能够设置给你的老婆自动回复『亲爱的我在忙呢,等等哈』,而对其它人自动回复『滚,LZ忙』。再例如,能够对聊天信息进行分词、识别,从而实现对内容的精准回复,固然,这里还须要使用到一些第三方的语言分析软解,这里就不详解了,总之,没有想不到。
那么再好比去年比较火的一个方法,经过拉好友进群组来检查是否还有好友关系。PC、Chrome上已经有不少软件来作这个检查了,其核心原理,都是经过拉群组的方式来作。那么在手机上,一样能够经过这种方式来实现,若是如今你还不知道该怎么作,那么后面的文章就没有看的必要了……
你们应该都用过冯老师的『绿色守护』,这个App的最基本无Root功能,就是经过在应用管理界面『结束进程』的方式来中止一个后台运行的App,你们都知道天朝的App,基本都是全家桶,因此这种方式对释放系统资源确实仍是有必定的帮助的,那么咱们就来看看简单的实现。
核心原理很是简单,在应用详情页面,经过中止服务来禁止App服务。OK,那么咱们要作的,实际上,就是下面的流程:
流程要比抢红包什么的简单多了,下面列出2个关键代码,你们应用详情界面:
public void cleanProcess(View view) {
for (String mPackage : mPackages) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", mPackage, null);
intent.setData(uri);
startActivity(intent);
}
}复制代码
监控详情页面,进行中止操做:
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED &&
event.getPackageName().equals("com.android.settings")) {
CharSequence className = event.getClassName();
if (className.equals("com.android.settings.applications.InstalledAppDetailsTop")) {
AccessibilityNodeInfo info = findViewByText("强行中止");
if (info.isEnabled()) {
performViewClick(info);
} else {
performBackClick();
}
}
if (className.equals("android.app.AlertDialog")) {
clickTextViewByText("肯定");
performBackClick();
}
}
}复制代码
这个App惟一的难点,应该就剩下怎么把UI作的好看一点了。
另外,还有一个兼容性的问题,你们都懂的,国内各类第三方的ROM厂家,常常会修改一些系统的Activity,甚至不一样系统版本同一个功能的Activity都有可能不同,因此,使用AccessibilityService的一个比较大的麻烦就是兼容性的处理,须要使用dumpsys和uiautomator这些工具来进行详细的分析,这些工具的使用以及分析方法,在个人新书《Android群英传:神兵利器》中都有详细的讲解,想深刻了解的开发者能够参考下。
借助AccessibilityService一样能够作一些比较有用的事情,例如监控App当前的状态,例如前台、后台的切换,经过TYPE_WINDOW_STATE_CHANGED便可进行判断,特别是在5.0以上,原先的getRunningTasks这个方法被升级到系统权限。
固然,AccessibilityService或多或少会存在一些性能问题,因此如今并不推荐使用这种方式来监控应用状态,更多的是经过activitylifecyclecallbacks来实现对App状态的跟踪与监控。
其实一旦咱们了解了AccessibilityService的使用原理,那么就很难作到不逾矩,毕竟这里的诱惑太大了,当我写到这里时,甚至有种毛骨悚然的感受,因此这里申明:
本文全部内容仅供学习、技术交流,由此产生的各类问题,均与本人无关。
据我所知,已经有些App或者称之为恶意软件实现了这样的功能,这个功能难吗,不难,估计都不超过20行代码,但确实很恶心,特别是对一些普通、小白用户,压根都不知道AccessibilityService是什么,莫名其妙你让我启用,写的可能比较好看,什么帮助你清理系统,优化资源,但实际上,在后面作一些见不得人的事情。
咱们来分析下如何实现,当用户想要卸载你的App的时候,通常会来到设置界面,找到你的App而后选择卸载,那么若是咱们监控这个页面,若是发现是本身的App,就直接退出,这样不就没法卸载了吗?是的,代码以下,没几行代码:
private String mDefenseName = "微信";
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
super.onAccessibilityEvent(event);
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED &&
event.getPackageName().equals("com.android.settings")) {
CharSequence className = event.getClassName();
if (className.equals("com.android.settings.SubSettings")) {
AccessibilityNodeInfo nodeInfo = findViewByText("应用程序信息");
if (nodeInfo != null && findViewByText(mDefenseName) != null) {
performBackClick();
}
}
}
}复制代码
那么有人要说了,若是是用的一些第三方ROM,直接在桌面就能卸载呢?一样的,只不过会稍微麻烦点,须要判断的东西更多了,要处理的兼容性更复杂了而已。
这里不得不说,虽然国内各类第三方ROM百花齐放、肆意妄为,但这也给AccessibilityService形成了很大的兼容性处理难题,因此对一些恶意的使用AccessibilityService的App也造成了很大的限制。
实际上并不局限于浏览器,各类App都能被劫持,由于AccessibilityService监控的是全局App,良心点的可能会指定包名进行监控。因此,咱们能够监控任意一个App,例如浏览器,一旦打开,咱们就输入指定的网址,或者是一打开一些App,就输入一些查询内容,这里我以鄙司的沪江网校为例,进入后直接进行搜索。
算了代码仍是不贴了,彻底都是Copy前面的内容。
呵呵呵,这个你还真是想多了,系统再天真也不会把这个权限开放给你,全部的设置为password类型的EditText都是没法被监控的,系统还算有点良心。
这里我只列举了一些很是简单的Hack方式,但实际上,还有不少,例如经过拉取指定网站的内容后自动安装App并模拟点击等,固然,AccessibilityService也能够用在自动化测试中,这彻底就是一把双刃剑,是利是弊,彻底取决于使用他的人。
通常来讲,AccessibilityService是须要用户手动操做受权才能够执行的,可是,若是是在Root的状况下,或者是在ADB链接PC的状况下,甚至都不用用户受权,就能够完成AccessibilityService的受权操做。
Root的状况就不说了,经过修改Setting的数据库就能够更改这个设置了,固然,有Root的状况下,就根本不须要AccessibilityService了。
在没有Root的状况下,若是PC经过ADB发出指令,一样是能够自动完成受权的,这个能够参考360的一篇文章:
我这里就很少说了,你们看看就懂了,并无太多的技术含量,应该算是系统的一个小的漏洞。
前面咱们分析了那么多AccessibilityService好的很差的使用方法,实际上,总结下就这么几步。
经过上面的这些方式,基本就能够实现一些固定流程的操做自动化了。关于AccessibilityService的工具类,我放到了Github上,虽然功能已经比较全了,但尚未通过不少的兼容性测试,同时,碍于时间和精力的关系,给出的Demo示例也很少,但愿你们能够多提PR,共同完善。
欢迎你们关注个人微信公众号: