• Stars
    star
    133
  • Rank 272,600 (Top 6 %)
  • Language
    Java
  • Created over 7 years ago
  • Updated almost 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

演示辅助功能基本流程和使用,通过简单的例子看懂辅助功能原理。我们可以使用辅助功能帮助我们做一些有意思的事情,比如抢红包插件(但是微信不准),帮助用户开启权限(这个还不错哟)

AccessibilitySample

本文主要介绍辅助功能的使用

  1. 辅助功能基本原理
  2. 辅助功能基本配置和框架搭建
  3. 辅助功能实战解析

一、辅助功能基本原理

  辅助功能(AccessibilityService)其实是一个Android系统提供给的一种服务,本身是继承Service类的。这个服务提供了增强的用户界面,旨在帮助残障人士或者可能暂时无法与设备充分交互的人们。

  从开发者的角度看,其实就是提供两种功能:查找界面元素,实现模拟点击。实现一个辅助功能服务要求继承AccessibilityService类并实现它的抽象方法。自定义一个服务类AccessibilitySampleService(这个命名可以随意),继承系统的AccessibilityService并覆写onAccessibilityEvent和onInterrupt方法。编写好服务类之后,在系统配置文件(AndroidManifest.xml)中注册服务。完成前面两个步骤就完成了基本发辅助功能服务注册与配置,具体的功能实现需要在onAccessibilityEvent中完成,根据onAccessibilityEvent回调方法传递过来的AccessibilityEvent对象可以对事件进行过滤,结合AccessibilitySampleService本身提供的查找节点与模拟点击相关的接口即可实现权限节点的查找与点击。

二、辅助功能基本配置和框架搭建

创建自定义辅助功能服务类

import android.accessibilityservice.AccessibilityService;
import android.view.accessibility.AccessibilityEvent;

import com.accessibility.utils.AccessibilityLog;
public class AccessibilitySampleService extends AccessibilityService {

    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
    }

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        // 此方法是在主线程中回调过来的,所以消息是阻塞执行的
        // 获取包名
        String pkgName = event.getPackageName().toString();
        int eventType = event.getEventType();
		// AccessibilityOperator封装了辅助功能的界面查找与模拟点击事件等操作
        AccessibilityOperator.getInstance().updateEvent(this, event);
        AccessibilityLog.printLog("eventType: " + eventType + " pkgName: " + pkgName);
        switch (eventType) {
            case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
                break;
        }
    }

    @Override
    public void onInterrupt() {

    }
}

注册辅助功能服务

// 注册辅助功能服务
<service android:name=".AccessibilitySampleService"
	android:label="@string/accessibility_tip"
	android:exported="true"
	android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
	android:process=":BackgroundService">
	<intent-filter>
		<action android:name="android.accessibilityservice.AccessibilityService" />
	</intent-filter>
	// 通过xml文件完成辅助功能相关配置,也可以在onServiceConnected中动态配置
	<meta-data
		android:name="android.accessibilityservice"
		android:resource="@xml/accessibility_config"/>
</service>

上面android:label="@string/accessibility_tip"是配置此辅助功能服务在系统辅助功能页面里面显示的名字。

accessibility_config文件内容如下:

<?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/accessibility_desc"
    android:notificationTimeout="100" />

跳转到系统辅助功能页面,开启辅助功能服务

  完成上面配置之后,辅助功能服务就注册成功了,在系统辅助功能页面就能找到这个服务,但是默认是关闭的,也就是说,这个服务要开始为我们服务,还需要去系统界面开启那个开关。下面是跳转到辅助功能页面的代码,跳转过去之后,手动点击开关按钮。开关打开之后,这个辅助功能服务就开始工作了,系统开始回调onAccessibilityEvent方法。我们可以在onAccessibilityEvent方法中处理查找节点与点击操作。

public class OpenAccessibilitySettingHelper {
    private static final String ACTION = "action";
    private static final String ACTION_START_ACCESSIBILITY_SETTING = "action_start_accessibility_setting";

    public static void jumpToSettingPage(Context context) {
        try {
            Intent intent = new Intent(context,  AccessibilityOpenHelperActivity.class);
            intent.putExtra(ACTION, ACTION_START_ACCESSIBILITY_SETTING);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent);
        } catch (Exception ignore) {}
    }
}

下图是小米手机开启辅助功能的界面

三、辅助功能实战解析

实现界面自动点击操作,动画有点模糊,将就看吧

界面节点查找与模拟点击

  AccessibilityOperator封装了辅助功能的界面查找与模拟点击事件等操作,下面介绍几个关键的技术点。

界面节点查找操作

  AccessibilityNodeInfo提供两种查找View节点的方法

1. 根据View的ID精确查找,但是要求SDK_INT >= 18才能用

 /**
 * 根据View的ID搜索符合条件的节点,精确搜索方式;
 * 这个只适用于自己写的界面,因为ID可能重复
 * api要求18及以上
 * @param viewId
 */
public List<AccessibilityNodeInfo> findNodesById(String viewId) {
    AccessibilityNodeInfo nodeInfo = getRootNodeInfo();
    if (nodeInfo != null) {
        if (Build.VERSION.SDK_INT >= 18) {
            return nodeInfo.findAccessibilityNodeInfosByViewId(viewId);
        }
    }
    return null;
}

2. 根据View的Text文本进行模糊查找

/**
 * 根据Text搜索所有符合条件的节点, 模糊搜索方式
 */
public List<AccessibilityNodeInfo> findNodesByText(String text) {
    AccessibilityNodeInfo nodeInfo = getRootNodeInfo();
    if (nodeInfo != null) {
       return nodeInfo.findAccessibilityNodeInfosByText(text);
    }
    return null;
}

模拟界面操作

1. 普通的View事件模拟(ACTION_CLICK)

private boolean performClick(List<AccessibilityNodeInfo> nodeInfos) {
    if (nodeInfos != null && !nodeInfos.isEmpty()) {
        AccessibilityNodeInfo node;
        for (int i = 0; i < nodeInfos.size(); i++) {
            node = nodeInfos.get(i);
            // 获得点击View的类型
            AccessibilityLog.printLog("View类型:" + node.getClassName());
            // 进行模拟点击
            if (node.isEnabled()) {
                return node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
            }
        }
    }
    return false;
}

2. 全局事件模拟(返回键:AccessibilityService.GLOBAL_ACTION_BACK)

public boolean clickBackKey() {
    return performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
}

private boolean performGlobalAction(int action) {
    return mAccessibilityService.performGlobalAction(action);
}

More Repositories

1

SmartPopupWindow

提供关于PopupWindow使用过程中遇到的一些特殊问题的解决方案,例如:PopupWindow不响应点击外部消失和返回键消失的解决方法;PopupWindow精确计算要显示位置原理和方法;实现带箭头的上下文菜单遇到的坑;Android7.0 PopupWindow的兼容问题;屏幕旋转时调用PopupWindow update方法更新位置失效的问题及解决方案
Java
659
star
2

FingerprintRecognition

指纹识别,除了api>=23的支持指纹识别的设备,还支持api<23的具有指纹识别硬件支持的设备(前提是这些设备兼容了Google官方的标准接口),部分厂商(魅族,三星等)低版本需要接入他们的SDK进行适配
Java
339
star
3

FTPSync

Java FTP 上传下载文件(支持直接上传下载一个目录)
Java
123
star
4

FavoriteForAndroid

Android收藏夹,整理一些比较有用的文章,工具
83
star
5

PhoneStateListen

Android来去电监听,电话挂断
Java
76
star
6

SmartAlertPop

封装一个独立弹窗Module,这里的弹窗包括普通的Dialog方式弹框和WindowManager方式弹窗,主要是方便做项目重构,统一对弹窗进行管理,方便维护,拓展。如果你在对项目UI进行整体改版,需要对大量对话框和WindowManager弹窗进行UI适配的时候,此项目中的方法将非常适用
Java
38
star
7

AndroidRotateAnim

Android旋转动画+Android圆形进度条组合
Java
32
star
8

AppStartUpSpeedOpt

Android app 启动速度优化模拟,主要介绍一个App从启动到首屏绘制过程中可优化的点
Java
30
star
9

AndroidDrawClassic

android绘制基础总结:使用Android自身的drawable绘制,实现大多数基础图形的绘制,减少图片的使用,从而减少apk体积与内存占用。使用Android提供的绘图api实现丰富的自定义View控件
Java
26
star
10

AndroidAnimationDemos

Andorid动画案例(有普通动画,属性动画,自己实现onDraw的自绘动画):1. 模拟开关开启动画; 2. 3D旋转动画; 3. 圆形进度特效; 4. 多功能圆形进度百分比控件
Java
11
star
11

TinkerSample

一步步接入微信热更新框架Tinker
Java
2
star
12

FloatingWindow

Android悬浮窗那些事儿:悬浮窗,悬浮窗权限,应用外弹窗(后台弹窗),应用内弹窗(前台弹窗),悬浮Toast,反射系统Toast。
Java
2
star
13

WidgetForAndroid

未完待续~~~封装好的一些实用的自定义控件:进度条,日期选择器,开关按钮
Java
1
star