Android Accessibility大致解析,通过adb运行纯java代码打开应用的辅助功能

Android的辅助功能accessibility的具体文档可以查看:google accessibility说明文档
accessibility是一个非常强大的功能,可以实现监听手机上的各种事件,比如窗口的变化,查找屏幕上当前显示的文字,以及模拟点击等功能,并且通过accessibility可以完成很多一般应用无法完成事件,比如发送物理或虚拟返回键的指令是通过如下代码实现的
:

new Thread() {
    public void run() {
        try {
            Instrumentation inst = new Instrumentation();
            inst.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();

该指令是需要在系统进程中运行的应用使用才会生效的命令,不过如果使用辅助功能就可以通过发送全局操作触发该操作.这样就可以完成在非root的手机上实现悬浮球的返回键的功能.

另外辅助功能还可以实现各种脚本和无root权限伪静默安装.绿色守护的非root模式和uc的静默安装还有那些抢红包的应用都是用该方式实现的,不过如果一些恶意应用拿到了辅助功能的权限是灾难性的.

辅助功能的开启关闭是在Android的系统设置中的辅助功能或者叫无障碍选项中.

如何编写一个辅助功能服务
1.创建一个class继承于AccessibilityService,会强制重写2个方

/**
 * 当系统检测到一个匹配你辅助服务过滤器中设置参数的AccessibilityEvent时,调用该方法,运行时多次调用
 *
 * @param event 在用户交互使用时系统返回的event事件
 */
@Override
public void onAccessibilityEvent(AccessibilityEvent event)

/**
 * 当你的服务对系统事件的反馈被中断时,调用该方法。该方法同上面方法一样,也是被多次调用的
 */
@Override
public void onInterrupt()

2.接下来有2种选择

  1. 可以在res中创建xml文件夹,创建一个xml文件,文件名随意,在xml文件中对辅助服务进行配置,格式大致如下:
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeNotificationStateChanged"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:accessibilityFlags="flagReportViewIds"
    android:description="@string/app_name"
    android:notificationTimeout="100"
    android:canRetrieveWindowContent="true"
    android:packageNames="com.nesscurie.accessibility" />
  1. 重写onServiceConnected() (当应用成功连接到你的辅助性服务时,系统调用该方法)在该方法中进行配置
AccessibilityServiceInfo serviceInfo = new AccessibilityServiceInfo();
serviceInfo.eventTypes = ...;
serviceInfo.feedbackType = ...;
serviceInfo.notificationTimeout = ...;
serviceInfo.packageNames = new String[]{...};  
serviceInfo.flags =  ...;
setServiceInfo(serviceInfo);

各属性解释:

accessibilityEventTypes / eventTypes 事件类型
typeAllMask / AccessibilityEvent.TYPES_ALL_MASK 全局事件响应
typeViewClicked / AccessibilityEvent.TYPE_VIEW_CLICKED 点击事件
accessibilityFeedbackType / feedbackType 反馈方式
feedbackGeneric / AccessibilityServiceInfo.FEEDBACK_GENERIC 通用的反馈
feedbackAudible / AccessibilityServiceInfo.FEEDBACK_AUDIBLE 声音反馈
feedbackSpoken / AccessibilityServiceInfo.FEEDBACK_SPOKEN 语音反馈
notificationTimeout / notificationTimeout 响应毫秒值
packageNames 监听的应用的包名,可指定多个包名,xml文件中使用,隔开
accessibilityFlags / flags 用于之后node.getViewIdResourceName()的权限
description 辅助功能的描述

canRetrieveWindowContent 从一个AccessibilityEvent中调查完全视图层级的能力隐式地暴露私有用户信息给你的辅助服务,必须通过配置XML文件请求这个级别的访问权,不在你的服务配置xml文件中包含这个设置,那么对getSource()的调用会失败。

3.在manifest中注册辅助功能的服务

<service
    android:name=".MyAccessibilityService"
    android:label="我的辅助功能"
    android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService" />
    </intent-filter>
</service>

name:对应的是自定义service的包名

label:对应了在系统辅助功能开关界面中,你的service的名字

description:则是点击对应的服务进入开关界面后,该服务的简介

permission:对应的权限(亦可在service中单独写出来)

<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"/>

intent-filter:指定了执行的组件为辅助功能类

如果是使用xml文件配置的辅助服务,还需要在service节点下添加meta-data节点,在resource指定自己编写的xml文件

<meta-data
    android:name="android.accessibilityservice"
    android:resource="@xml/accessibility_config" />

4.接下来就可以在onAccessibilityEvent(AccessibilityEvent event)处理各种事件:
可以使用 event.getEventType()来获取各种事件消息:
基本窗口view的变化都可以使用这个type来监听:
AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED

打开popupwindow,菜单,对话框时候会触发:
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED

更加精确的代表了基于当前event.source中的子view的内容变化:
AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED

窗口的变化:
AccessibilityEvent.TYPE_WINDOWS_CHANGED

当前event的节点信息.有两种方式获取:
使用event获取:
AccessibilityNodeInfo nodeInfo = event.getSource();

在accessibility中直接获取:
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();

使用完要记得调用recycle();进行释放以免内存泄漏
nodeInfo.recycle();

接下来就可以使用下面的方法来获取对应的所有节点的集合
findAccessibilityNodeInfosByViewId(String str)
findAccessibilityNodeInfosByText(String str)

获取id的方法:
使用DDMS的hierarchy View来查找对应的viewId,但是有很多手机是没有办法获取,只会提示:Unable to get view server version from device XXXXX

在这个时候,在AccessibiltiyService的配置中添加的flag。flagReportViewIds就可以派上用场了

在窗口改变时,获取并遍历所有的node,即打印出node对应的文字和id

传入方法id的格式为: 应用的包名 + “:id/“ + 获取到的id

获取到节点之后即可使用节点进行点击等各种事件:
performAction(AccessibilityNodeInfo.ACTION_CLICK)

//AccessibilityNodeInfo中有各种各样的事件以常量的形势声明.
除了使用节点进行调用还可以调用全局事件:
返回键
performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
HOME键
performGlobalAction(AccessibilityService.GLOBAL_ACTION_HOME);
最近打开应用列表
performGlobalAction(AccessibilityService.GLOBAL_ACTION_RECENTS);
打开通知栏
performGlobalAction(AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS);
锁屏
performGlobalAction(AccessibilityService.GLOBAL_ACTION_POWER_DIALOG);
设置
performGlobalAction(AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS);

判断对应的辅助功能有没有打开的方法:

public boolean isAccessibilitySettingsOn(Context mContext) {
    int accessibilityEnabled = 0;
    final String service = getPackageName() + "/" + MyAccessibilityService.class.getCanonicalName();  //这里改成自己的class
    try {
        accessibilityEnabled = Settings.Secure.getInt(mContext.getApplicationContext().getContentResolver(),
                Settings.Secure.ACCESSIBILITY_ENABLED);
    } catch (Settings.SettingNotFoundException ignored) {
    }
    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;
}

这个方法就是通过获取系统设置的存储辅助功能的数据库的内容提供者,然后查看已开的辅助功能的包名+类名
是否有自己,有就表示开了.(后面的用java程序悄悄打开对应的辅助功能其实就是去修改这个值)

打开系统设置辅助功能的界面:

Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
startActivity(intent);

辅助功能的介绍就是这些,下面开始使用adb运行java程序悄悄打开辅助功能:系统设置的各个选项通过数据库形式进行保存,通过user为shell的高权限将系统设置存储的配置进行修改.
在此之前先写一个简单的辅助功能应用:
编写一个类继承AccessibilityService,只在onStartCommand做一个返回键的全局操作

public class MyAccessibilityService extends AccessibilityService {

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {

    }

    @Override
    public void onInterrupt() {

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
        return super.onStartCommand(intent, flags, startId);
    }
}

xml配置最普通的内容

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeNotificationStateChanged"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:accessibilityFlags="flagDefault"
    android:description="@string/app_name"
    android:notificationTimeout="100"
    android:canRetrieveWindowContent="true"
    android:packageNames="com.nesscurie.accessibility" />

在清单文件进行注册

<service
    android:name=".MyAccessibilityService"
    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>

在Activity的xml文件中设置一个button,为了方便,声明onClick属性为onClick,在activity中编写onClick方法为如下内容

public void onClick(View view) {
    if (!isAccessibilitySettingsOn(this)) {
        Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
        startActivity(intent);
        return;
    }
    startService(new Intent(this, MyAccessibilityService.class));
}

部署到设备上,打开应用点击按钮可以发现打开了系统设置的辅助功能的界面,开启对应的辅助功能,回到app,可以发现点击按钮后触发了返回键的功能.

关闭该应用辅助功能,接下来就是编写能修改系统设置的纯java代码:使用adb的settings命令将设置的数据库中对应字段改变

public class Temp {
    public static void main(String[] args) {
        System.out.println("running");
        //这里是包名+辅助功能类名
        String cmd1 = "settings put secure enabled_accessibility_services com.nesscurie.accessibility/com.nesscurie.accessibility.MyAccessibilityService";
        
        String cmd2 = "settings put secure accessibility_enabled 1";
        execShell(cmd1);
        execShell(cmd2);
    }
    
    //运行命令行的方法
    private static void execShell(String cmd) {
        try {
            Process p = Runtime.getRuntime().exec(cmd);
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    p.getInputStream()));
            String readLine = br.readLine();
            while (readLine != null) {
                System.out.println(readLine);
                readLine = br.readLine();
            }
            if (br != null) {
                br.close();
            }
            p.destroy();
            p = null;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用上一篇中的方法,将代码编译为.class后转为.dex,push到手机中,比如data/local/tmp目录:

adb shell
cd data/local/tmp
app_process -Djava.class.path=Temp.dex data/local/tmp Temp
可以看到打印出runnig后,系统设置的该应用的辅助功能界面刷新为开,本来是需要系统权限(设置运行在系统进程中,具有系统权限)才能进行修改的选项,就这么悄悄的打开了.

辅助功能是一个非常强大的功能,不仅能为不少不方便的人群提供使用手机的方式,还可以带来不少特殊的体验.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ADBAndroid Debug Bridge)是Android开发工具包中的一个工具,用来与连接到计算机的Android设备进行通信和调试。辅助功能是一种功能,帮助用户克服使用设备时的各种障碍。 要通过ADB自动打开辅助功能,可以按照以下步骤进行操作: 1. 首先,确保已经在计算机上安装了ADB工具,并且手机已经通过USB数据线与计算机连接。 2. 打开命令提示符(Windows系统)或终端(Mac或Linux系统)。 3. 输入命令“adb devices”并按下回车键,以确保ADB可以正确识别和连接到手机。 4. 使用命令“adb shell”进入手机的shell环境。 5. 输入以下命令来启用辅助功能adb shell settings put secure enabled_accessibility_services com.android.settings/com.android.settings.accessibility.AccessibilitySettings 这个命令将在手机的安全设置中将“enabled_accessibility_services”参数设置为“com.android.settings/com.android.settings.accessibility.AccessibilitySettings”。 6. 按下回车键以执行命令。 7. 退出手机的shell环境。可以输入“exit”命令再按下回车键。 现在,辅助功能已经被启用,用户可以在手机的设置中找到并配置不同的辅助功能选项。这些选项可能包括语音识别、文字放大、颜色反转等功能,以帮助用户更好地使用设备。 注意:在进行上述操作时,请确保手机已经连接到计算机并处于开启状态。此外,ADB命令可能因操作系统版本和设备型号的不同而有所不同,需要根据具体情况进行调整。 ### 回答2: adbAndroid Debug Bridge(Android调试桥)的缩写,是一个使用命令行界面与Android设备进行通信的工具。辅助功能是一种可以帮助有特殊需求的用户更好地使用设备的功能。 要使用adb自动打开辅助功能,可以通过以下步骤实现: 1. 首先,确保电脑上已经安装了adb,并且已经将adb的路径添加到系统的环境变量中,以便在任何位置都可以直接使用adb命令。 2. 连接Android设备到电脑,确保设备已经通过USB调试模式连接到电脑上。 3. 打开命令提示符(Windows)或终端(Mac和Linux),输入adb devices命令,查看设备是否正确连接。 4. 使用adb shell命令进入设备的shell模式。 5. 输入以下命令来打开辅助功能设置界面: ``` adb shell am start -n com.android.settings/.AccessibilitySettings ``` 此命令会启动设备上的设置应用,并直接跳转到辅助功能设置界面。 6. 在辅助功能设置界面中,可以根据需要启用或关闭特定的辅助功能。 以上就是使用adb自动打开辅助功能的步骤。通过adb命令,我们可以远程操作设备并进行各种设置。辅助功能可以帮助那些有特殊需求的用户更好地使用设备,提高其使用体验和便利性。 ### 回答3: adbAndroid Debug Bridge(Android 调试桥)的缩写,是一个用于与 Android 设备进行通信和调试的命令行工具。在开发和调试过程中,adb 可以执行各种操作,包括自动打开辅助功能。 要使用 adb 自动打开辅助功能,首先需要确保 adb 工具已经正确安装并配置好了环境变量。然后按照以下步骤进行操作: 1. 连接 Android 设备到电脑,确保设备已启用开发者选项和 USB 调试模式。 2. 打开终端或命令提示符,输入 adb devices 命令,以确保设备已成功连接到 adb。 3. 输入 adb shell 命令进入设备的 shell 环境。 4. 输入以下命令以模拟辅助功能的自动打开adb shell settings put secure enabled_accessibility_services com.package.name/com.package.name.ServiceName 其中,com.package.name 是你想要打开辅助功能所在的应用程序包名,ServiceName 是辅助功能服务的类名。 5. 执行完上述命令后,重新启动设备,辅助功能将自动启用。 请注意,上述命令中的 com.package.name 和 ServiceName 需要根据实际情况进行替换,具体的包名和类名可以在 AndroidManifest.xml 文件中找到。 通过以上步骤,我们可以使用 adb 快速自动打开辅助功能,方便进行 Android 设备的调试和测试工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值