AccessibilityService主要是帮助残障用户使用android设备和应用,它可以监听用户界面的一些状态转换,例如页面切换、焦点改变、通知、Toast等,并且能模拟完成一系列触摸操作.(市面上通过无障碍实现的功能有:抢红包,apk自动安装,一键清理所有后台进程,自动加好友等等)
AccessbilityService继承之Service,所以也遵循Service的生命周期,只是它只能在设置中手动启动,系统绑定到服务后,会调用它的onServiceConnected()方法. 而当用户手动在设置中关闭服务,或者开发者调用disableSelf()方法时,该服务会被关闭销毁
配置用法:
- 1.继承AccessbilityService
public class MyAccessibilityService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
//接收到系统发送AccessibilityEvent时的回调
}
@Override
public void onInterrupt() {
//服务中断的回调
}
}
- 2.AndroidManifest中注册该服务
<service
android:name=".MyAccessibilityService"
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/accessibility_config" />
</service>
其中:
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"是为了确保只有系统可以绑定该服务
meta-data配置,主要是配置需要监听的事件类型、要监听哪个程序,最小监听间隔等属性
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeNotificationStateChanged|typeWindowStateChanged|typeWindowContentChanged|typeWindowsChanged"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagDefault"
android:canRetrieveWindowContent="true"
android:description="开启此功能,即可使用微信抢红包功能"
android:notificationTimeout="100"
android:packageNames="com.tencent.mm" />
accessibilityEventTypes:设置响应事件的类型,可以监听单击、长按、滑动等,用|隔开;监听所有事件可以用typeAllMask
accessibilityFeedbackType:服务提供的反馈类型,feedbackGeneric通用反馈
accessibilityFlags:辅助功能附加的标志,flagDefault默认的配置
canRetrieveWindowContent:辅助功能服务是否能够取回活动窗口内容的属性
notificationTimeout:响应时间
packageNames:监听的应用包名,不填,默认监听所有应用的事件
判断AccessibilityService服务是否开启
public static boolean isAccessibilitySettingsOn(Context mContext, Class<? extends AccessibilityService> clazz) {
int accessibilityEnabled = 0;
final String service = mContext.getPackageName() + "/" + clazz.getCanonicalName();
try {
accessibilityEnabled = Settings.Secure.getInt(mContext.getApplicationContext().getContentResolver(),
Settings.Secure.ACCESSIBILITY_ENABLED);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}
TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':');
if (accessibilityEnabled == 1) {
String settingValue = Settings.Secure.getString(mContext.getApplicationContext().getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
if (settingValue != null) {
mStringColonSplitter.setString(settingValue);
while (mStringColonSplitter.hasNext()) {
String accessibilityService = mStringColonSplitter.next();
if (accessibilityService.equalsIgnoreCase(service)) {
return true;
}
}
}
}
return false;
}
打开无障碍服务开启页面
startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS))
API:
onAccessibilityEvent(AccessibilityEvent event)的回调返回一个AccessibilityEvent对象 ,通过event.getEventType()获取事件的类型(event.toString()可以获取当前事件的所有信息)
对应事件类型如下:
事件类型: 描述:
TYPE_VIEW_CLICKED View被点击
TYPE_VIEW_LONG_CLICKED View被长按
TYPE_VIEW_SELECTED View被选中
TYPE_VIEW_FOCUSED View获得焦点
TYPE_VIEW_TEXT_CHANGED View文本变化
TYPE_WINDOW_STATE_CHANGED 打开了一个PopupWindow,Menu或Dialog
TYPE_NOTIFICATION_STATE_CHANGED Notification变化
TYPE_VIEW_HOVER_ENTER 一个View进入悬停
TYPE_VIEW_HOVER_EXIT 一个View退出悬停
TYPE_TOUCH_EXPLORATION_GESTURE_START 触摸浏览事件开始
TYPE_TOUCH_EXPLORATION_GESTURE_END 触摸浏览事件完成
TYPE_WINDOW_CONTENT_CHANGED 窗口的内容发生变化,或子树根布局发生变化
TYPE_VIEW_SCROLLED View滚动
TYPE_VIEW_TEXT_SELECTION_CHANGED Edittext文字选中发生改变事件
TYPE_ANNOUNCEMENT 应用产生一个通知事件
TYPE_VIEW_ACCESSIBILITY_FOCUSED 获得无障碍焦点事件
TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED 无障碍焦点事件清除
TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY 在给定的移动粒度下遍历视图文本的事件
TYPE_GESTURE_DETECTION_START 开始手势监测
TYPE_GESTURE_DETECTION_END 结束手势监测
TYPE_TOUCH_INTERACTION_START 触摸屏幕事件开始
TYPE_TOUCH_INTERACTION_END 触摸屏幕事件结束
TYPE_WINDOWS_CHANGED 屏幕上的窗口变化事件,需要API 21+
TYPE_VIEW_CONTEXT_CLICKED View中的上下文点击事件
TYPE_ASSIST_READING_CONTEXT 辅助用户读取当前屏幕事件
常用监听事件: AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED 、 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 和 AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
常用方法:
1.event.getClassName() 获取当前页面的类名
2.AccessibilityNodeInfo nodeInfo = getRootInActiveWindow(); //获取当前整个活动窗口的根节点 返回值记录View的状态信息
3.AccessibilityNodeInfo常用方法:
getParent:获取父节点
getChild:获取子节点
performAction:在节点上执行一个动作
findAccessibilityNodeInfosByText:通过字符串查找节点元素
findAccessibilityNodeInfosByViewId:通过视图id查找节点元素
4.performAction(AccessibilityNodeInfo)触发事件类型:
//点击
performAction(AccessibilityNodeInfo.ACTION_CLICK);
//长按
performAction(AccessibilityNodeInfo.ACTION_LONG_CLICK);
//滚动
performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); //向下滚一下
performAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); //向上滚一下
//填充EditText(API版本需要>18可用方法1,API>21两种方法都可以使用)
//方法1:
ClipboardManager clipboard = (ClipboardManager)this.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("text", "填充内容");
clipboard.setPrimaryClip(clip);
//获得焦点
info.performAction(AccessibilityNodeInfo.ACTION_FOCUS);
粘贴进入内容
info.performAction(AccessibilityNodeInfo.ACTION_PASTE);
//方法2:
Bundle arguments = new Bundle();
arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "填充内容");
info.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
5.除了控件触发事件外,AccessibilityService提供了一个performGlobalAction(),用于执行一些通用的事件(建议handler.postDelay()方式调用):
GLOBAL_ACTION_BACK 点击返回按钮
GLOBAL_ACTION_HOME 点击home
GLOBAL_ACTION_NOTIFICATIONS 打开通知
GLOBAL_ACTION_RECENTS 打开最近应用
GLOBAL_ACTION_QUICK_SETTINGS 打开快速设置
GLOBAL_ACTION_POWER_DIALOG 打开长按电源键的弹框