Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android-Accessibility(辅助功能) #14

Open
jeffrey1995 opened this issue Aug 18, 2016 · 0 comments
Open

Android-Accessibility(辅助功能) #14

jeffrey1995 opened this issue Aug 18, 2016 · 0 comments

Comments

@jeffrey1995
Copy link
Owner

最近开发用到了辅助功能,赶紧整理下来。先介绍一下Accessibility:
对于那些由于视力、听力或其它身体原因导致不能方便使用Android智能手机的用户,Android提供了Accessibility功能和服务帮助这些用户更加简单地操作设备,包括文字转语音、触觉反馈、手势操作、轨迹球和手柄操作。开发者可以搭建自己的Accessibility服务,这可以加强可用性,例如声音提示,物理反馈,和其他可选的操作模式。
随着Android版本的不断升级,Android Accessibility功能也越来越强大,Android 4.0版本以前,系统辅助服务功能比较单一,仅仅能过单向获取窗口元素信息,比如获取输入框用户输入内容。到Android 4.1版本以后,系统辅助服务增加了与窗口元素的双向交互,此时可以通过辅助功能服务操作窗口元素,比如点击按钮等。
由于系统辅助服务能够实时获取您当前操作应用的窗口元素信息,这有可能给你带来隐私信息的泄露风险,比如获取非密码输入框的输入内容等。同时通过辅助功能也可以模拟用户自动化点击应用内元素,也会带来一定的安全风险。

下面来实际操作一下(AndroidStudio)

1.在res文件下创建一个xml文件夹,在文件夹下创建一个phone_accessibilit.xml:


文件中定义了一些关于辅助功能服务的相关属性

2.创建MyAccessibilityService

同时在manifest文件中填写service的相关信息。

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <service
        android:name=".MyAccessibilityService"
        android:label="@string/acc_service_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/phone_accessibility" />
    </service>
</application>

MyAccessibilityService:

public class MyAccessibilityService extends AccessibilityService {
private static int ACTION_STEP = 0;

@Override
public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
    try {
        processAccessibilityEnvent(accessibilityEvent);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public void processAccessibilityEnvent(AccessibilityEvent event) {
    if (event.getSource() == null) {
        Log.d("accessibility", "null");
        return;  //如果event没有内容,直接返回.
    }

    Log.d("accessibility", event.getPackageName().toString());

    if (event.getPackageName().equals("com.mrtian.example.accessibilitytest")) {    //通过包名,分别处理
        //查找对应id的View结点
        List<AccessibilityNodeInfo> nodes = event.getSource().findAccessibilityNodeInfosByViewId("com.mrtian.example.accessibilitytest:id/button_01");
        if (nodes != null && !nodes.isEmpty()) {
            Log.d("accessibility", "button1 :" + "click");
            AccessibilityNodeInfo node1;
            for (int i = 0; i < nodes.size(); i++) {
                node1 = nodes.get(i);
                if (node1.getClassName().equals("android.widget.Button") && node1.isEnabled()) {
                    //如果发现该结点,做一个点击操作
                    node1.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                }
            }
        }
        //通过id查找结点
        List<AccessibilityNodeInfo> list = event.getSource().findAccessibilityNodeInfosByViewId("com.qihoo.appstore:id/search_list_view");
        if (list != null && !list.isEmpty()) {
            //做一个下拉操作
            list.get(0).performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
        }

        //做一个下拉通知栏的操作
        //this.performGlobalAction(AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS);

    }

}
@Override
public void onInterrupt() {

}

}
为了给出思路,我做了一个简单的演示,不停点击界面中的一个button。button的数字不停增加。

开启辅助功能后,程序就会不断回调onAccessibilityEvent函数,参数AccessibilityEvent accessibilityEvent,accessibilityEvent.getSource可以得到整个页面的信息。

通过event.getPackageName()得到应用程序的包名,可以判断包名做出不同的操作。

event.getSource().findAccessibilityNodeInfosByViewId/ByText可以通过文本或者id找到相应的控件结点,拿到结点以后就可以做一些操作,比如点击、下拉、触摸...返回值是一个AccessibilityNodeInfo的list,AccessibilityNodeInfo是结点信息,对应方法getParent,getChildren可以得到父子结点。

有了这个就可以做很多事情,建议:

1.可以设置一个静态变量来控制操作的步骤。
2.利用DDMS可以查看当当前布局树,可以查看每个结点的id、Text、clickable等属性。
3.利用Handler的postDelayed来做一些延时操作。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant