Take a look at GW

【Android】解析AccessibilityService(辅助服务)的使用

辅助功能是Android系统提供的一种服务,派生自Service类。这个服务提供了增强的用户界面,目的是为了帮助残障人士。它一般提供了页面元素查找功能和元素点击功能。

通过辅助功能,开发者可以实现一些非常丰富的功能:

抢红包
微信自动回复
检查微信好友
进程清理
判断应用当前状态
防卸载
浏览器劫持
跳过用户授权

关于更多AccessibilityService的安全信息可以查看这篇文章:
https://www.freebuf.com/articles/terminal/114045.html

AccessibilityService(辅助功能类)派生自Service,它是一个服务类。AccessibilityService是一个抽象类,所以要使用辅助功能的话,就要从AccessibilityService类派生一个实例类,完成配置、监听,再根据监听到的元素完成各种动作。

例如,下面这个案例:


MainActivity.java

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import com.example.accessibilityservicetest.R;

public class MainActivity extends Activity {
    private static String TAG="test";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        //如果没开启,就提醒开启辅助功能
        if(!isAccessibilitySettingsOn(this)){
            Intent intent=new Intent(android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS);
            startActivity(intent);
        }
    }
    
    //判断是否开启辅助功能
    private boolean isAccessibilitySettingsOn(Context mContext) {
        int accessibilityEnabled = 0;
        final String service = getPackageName() + "/" + MyCustomAccessibilityService.class.getCanonicalName();
        try {
            accessibilityEnabled = Settings.Secure.getInt(
                    mContext.getApplicationContext().getContentResolver(),
                    android.provider.Settings.Secure.ACCESSIBILITY_ENABLED);
            Log.v(TAG, "accessibilityEnabled = " + accessibilityEnabled);
        } catch (Settings.SettingNotFoundException e) {
            Log.e(TAG, "Error finding setting, default accessibility to not found: "
                    + e.getMessage());
        }
        TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':');
     
        if (accessibilityEnabled == 1) {
            Log.v(TAG, "***ACCESSIBILITY IS ENABLED*** -----------------");
            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();
     
                    Log.v(TAG, "-------------- > accessibilityService :: " + accessibilityService + " " + service);
                    if (accessibilityService.equalsIgnoreCase(service)) {
                        Log.v(TAG, "We've found the correct setting - accessibility is switched on!");
                        return true;
                    }
                }
            }
        } else {
            Log.v(TAG, "***ACCESSIBILITY IS DISABLED***");
        }
     
        return false;
    }
}
MainActivity.java

MyCustomAccessibilityService.java

public class MyCustomAccessibilityService extends AccessibilityService {
    //该方法在初始化辅助功能时调用
    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
    }
    //获取到指定的监听事件
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        //辅助功能的时间类型
        int eventType=event.getEventType();
        //输出事件的字符串type
        String typeStr=event.eventTypeToString(eventType);
        //根据事件类型来分发我们需要的操作,这里以窗口变化为例
        if(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED==eventType){
            //判断我们的辅助功能,是否在约定的界面执行,以设置界面为例
            if("com.android.settings".equals(event.getPackageName())){
                //doSometing
            }
        }else if(AccessibilityEvent.TYPE_GESTURE_DETECTION_START==eventType){
            
        }else{
            //在完成自己的操作时候,可以关闭自己的服务,下次使用再开启
            //API>=24
            //disableSelf()
        }
        //通过event遍历nodeInfo
         AccessibilityNodeInfo info= event.getSource();
        //findFocus(int)
         //getWindows()
         //getRootInActiveWindow()
         
         //遍历节点
         for(int i=0;i<info.getChildCount();i++){
             AccessibilityNodeInfo childNode= info.getChild(i);
             //获取子节点中的某个特定node,一下通过id查找
            List<AccessibilityNodeInfo> list = childNode.findAccessibilityNodeInfosByViewId("com.android" +".settings:id/xxxx");
            // 通过text查找
            //List<AccessibilityNodeInfo> list = info.findAccessibilityNodeInfosByText("xxxx");
            Log.i("InfoType",childNode.getClassName().toString());
            Log.i("InfoText", childNode.getText().toString());
            Log.i("InfoPkgName",childNode.getPackageName().toString());
            Log.i("InfoViewId", childNode.getViewIdResourceName());
            
            //进行点击操作
            for(AccessibilityNodeInfo anodeinfo : list){
                if(anodeinfo.isClickable()){
                    anodeinfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                }
            }
         }
    }
    //辅助功能被中断时候调用该方法
    @Override
    public void onInterrupt() {
    }
}
MyCustomAccessibilityService.java

acessibilityserviceconfig.xml

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service
    android:description="@string/accessibility_description"
    android:accessibilityEventTypes="typeAllMask"
    android:packageNames="com.example.accessibilityservicetest,com.android.settings"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:notificationTimeout="100"
    android:accessibilityFlags="flagDefault"
    android:canRetrieveWindowContent="true"
  xmlns:android="http://schemas.android.com/apk/res/android"/>
acessibilityserviceconfig.xml

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.accessibilityservicetest"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.accessibilityservicetest.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service
            android:name="com.example.accessibilityservicetest.MyCustomAccessibilityService"
             android:label="@string/app_name"
             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/acessibilityserviceconfig"/>
        </service>
    </application>
</manifest>
AndroidManifest.xml


上面的acessibilityserviceconfig.xml文件是关于这次辅助功能的配置信息,在下面做出如下说明:
AccessibilityEventTypes 此服务希望接收的事件类型
constant     value     描述
typeAllMask     ffffffff     所有类型的事件
typeAnnouncement     4000     一个应用产生一个通知事件
typeAssistReadingContext     1000000     辅助用户读取当前屏幕事件
typeContextClicked     800000     view中上下文点击事件
typeGestureDetectionEnd     80000     监测到的手势事件完成
typeGestureDetectionStart     40000     开始手势监测事件
typeNotificationStateChanged     40     收到notification弹出消息事件
typeTouchExplorationGestureEnd     400     触摸浏览事件完成
typeTouchExplorationGestureStart     200     触摸浏览事件开始
typeTouchInteractionEnd     200000     用户触屏事件结束
typeTouchInteractionStart     100000     触摸屏幕事件开始
typeViewAccessibilityFocusCleared     10000     无障碍焦点事件清除
typeViewAccessibilityFocused     8000     获得无障碍的焦点事件
typeViewClicked     1     点击事件
typeViewFocused     8     view获取到焦点事件
typeViewHoverEnter     80     一个view的悬停事件
typeViewHoverExit     100     一个view的悬停事件结束,悬停离开该view
typeViewLongClicked     2     view的长按事件
typeViewScrolled     1000     view的滚动事件,adapterview、scrollview
typeViewSelected     4     view选中,一般是具有选中属性的view,例如adapter
typeViewTextChanged     10     edittext中文字发生改变的事件
typeViewTextSelectionChanged     2000     edittext文字选中发生改变事件
typeViewTextTraversedAtMovementGranularity     20000     UIanimator中在一个视图文本中进行遍历会产生这个事件,多个粒度遍历文本。一般用于语音阅读context
typeWindowContentChanged     800     窗口的内容发生变化,或者更具体的子树根布局变化事件
typeWindowStateChanged     20     新的弹出层导致的窗口变化(dialog、menu、popupwindow)
typeWindowsChanged     400000     屏幕上的窗口变化事件,需要API 21+


accessibilityFeedbackType 此服务提供的反馈类型
constant     value     描述
feedbackAllMask     ffffffff     取消所有的可用反馈方式
feedbackAudible     4     可听见的(非语音反馈)
feedbackGeneric     10     通用反馈
feedbackHaptic     2     触觉反馈(震动)
feedbackSpoken     1     语音反馈
feedbackVisual     8     视觉反馈


accessibilityFlags 辅助功能附加的标志,多个使用 ' | '分隔
constant     value     描述
flagDefault     1     默认的配置
flagEnableAccessibilityVolume     80     这个标志要求系统内所有的音频通道,使用由STREAM_ACCESSIBILTY音量控制USAGE_ASSISTANCE_ACCESSIBILITY
flagIncludeNotImportantViews     2     表示可获取到一些被表示为辅助功能无权获取到的view
flagReportViewIds     10     使用该flag表示可获取到view的ID
flagRequestAccessibilityButton     100     如果辅助功能可用,提供一个辅助功能按钮在系统的导航栏 API 26+
flagRequestEnhancedWebAccessibility     8     此类扩展的目的是为WebView中呈现的内容提供更好的辅助功能支持。这种扩展的一个例子是从一个安全的来源注入JavaScript。如果至少有一个具有此标志的辅助功能服务, 则系统将使能增强的web辅助功能。因此, 清除此标志并不保证该设备不会使能增强的web辅助功能, 因为可能有另一个使能的服务在使用它。
flagRequestFilterKeyEvents     20     能够监听到系统的物理按键
flagRequestFingerprintGestures     200     监听系统的指纹手势 API 26+
flagRequestTouchExplorationMode     4     系统进入触控探索模式。出现一个鼠标在用户的界面
flagRetrieveInteractiveWindows     40     该标志知识的辅助服务要访问所有交互式窗口内容的系统,这个标志没有被设置时,服务不会收到TYPE_WINDOWS_CHANGE事件。


canRequestEnhancedWebAccessibility(boolean)
辅助功能服务是否能够请求WEB辅助增强的属性。例如: 安装脚本以使应用程序内容更易于访问。

canRequestFilterKeyEvents(boolean)
辅助功能服务是否能够请求过滤KeyEvent的属性,是否可以请求KeyEvent事件流。flagRequestFilterKeyEvents搭配使用

canRequestTouchExplorationMode (boolean)
此属性用于,能够让辅助功能服务通过手势,来请求触摸浏览模式,其被触摸的项,将被朗读出来,flagRequestTouchExplorationMode搭配使用

canRetrieveWindowContent (boolean)
辅助功能服务是否能够取回活动窗口内容的属性。 与上边的flagRetrieveInteractiveWindows搭配使用,无法在运行时更改此设置。

description
辅助功能服务目的或行为的简短描述。

notificationTimeout
同一类型的两个辅助功能事件发送到服务的最短间隔(毫秒,两个辅助功能事件之间的最小周期)

packageNames
从此服务能接收到事件的软件包名称 (不适合所有软件包)(多个软件包用逗号分隔)。

settingsActivity
允许用户修改辅助功能的activity组件名称

summary
同description

 

可以通过DDMS来查看手机界面的节点元素的各种信息:

原文链接:https://www.jianshu.com/p/ef01ce654302

posted @ 2018-11-26 11:00  HDWK  阅读(7432)  评论(0编辑  收藏  举报