Android Accessibility -- 抖音自动化-实现无障碍【转载】

2,880 阅读3分钟

目录结构
在这里插入图片描述

  1. 在Android (AndroidManifest.xml) 中配置
<service
    android:name="com.example.myapplication.TestAccessibilityService"
    android:enabled="true"
    android:exported="true"
    android:label="抖音小助手"
    android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
    tools:ignore="MissingClass">
    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService" />
    </intent-filter>
    <meta-data
        android:name="android.accessibilityservice"
        android:resource="@xml/accessibility_service_config" />
</service>

AndroidManifest.xml 整体配置文件


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.myapplication">
    <uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"
        tools:ignore="ProtectedPermissions" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyApplication">

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <intent-filter >
                <action android:name="com.ss.android.sdk.snssdk1128" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>

            <intent-filter >
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="snssdk1128" />
            </intent-filter>
        </activity>
        <service
            android:name="com.example.myapplication.TestAccessibilityService"
            android:enabled="true"
            android:exported="true"
            android:label="抖音小助手"
            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
            tools:ignore="MissingClass">
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService" />
            </intent-filter>
            <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/accessibility_service_config" />
        </service>
    </application>

</manifest>

accessibility_service_config.xml 配置

android:packageNames 一定要配置抖音的包名 不然监听不了

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/accessibility_service_description"
android:packageNames="com.example.android.apis,com.tencent.mm,com.tencent.mobileqq,com.ss.android.ugc.aweme"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFlags="flagDefault"
    android:accessibilityFeedbackType="feedbackAllMask"
    android:notificationTimeout="2000"
    android:canRetrieveWindowContent="true"
    android:canPerformGestures="true"
    android:canRequestFilterKeyEvents="true"
    android:canRequestEnhancedWebAccessibility="true"
    android:settingsActivity="com.example.myapplication.TestAccessibilityService"
    />

MainActivity.java

package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import java.util.List;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button btn = findViewById(R.id.barrierFree);

        Button st = findViewById(R.id.start);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!TestAccessibilityService.isStart()) {
                    Log.e("TAG", "onCreate:初始化" );
                    try {
                        startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));
                        Log.e("TAG", "onCreate:初始化  try" );
                    } catch (Exception e) {
                        Log.e("TAG", "onCreate:初始化  catch" );
                        startActivity(new Intent(Settings.ACTION_SETTINGS));
                        e.printStackTrace();
                    }
                }
            }
        });

        st.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
//抖音
                boolean exist1 = checkAppInstalled(MainActivity.this, "com.ss.android.ugc.aweme");
                //抖音极速版
                //boolean exist1 = checkAppInstalled(getContext(), "com.ss.android.article.video");
                //抖音火山版
                //boolean exist1 = checkAppInstalled(getContext(), "com.ss.android.ugc.live");
                if (exist1) {
                    Intent intent = new Intent();
                    //抖音 打开个人中心  104248958804 需要去获取抖音的UserId
//            intent.setData(Uri.parse("snssdk1128://user/profile/104248958804"));
                    // 打开首页
                    intent.setData(Uri.parse("snssdk1128://feed?refer=web&gd_label=1"));
                    //抖音极速版
                    //intent.setData(Uri.parse("snssdk1112://user/profile/104248958804"));
                    //抖音火山版
                    //intent.setData(Uri.parse("snssdk1112://profile?id=104248958804"));
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);
                } else {
                    Toast.makeText(MainActivity.this, "请先安装此应用", Toast.LENGTH_SHORT).show();
                }
            }
        });

    }

    private boolean checkAppInstalled(Context context, String pName) {
        if (pName == null || pName.isEmpty()) {
            return false;
        }
        final PackageManager packageManager = context.getPackageManager();
        List<PackageInfo> info = packageManager.getInstalledPackages(0);
        if (info == null || info.isEmpty()) {
            return false;
        }
        for (int i = 0; i < info.size(); i++) {
            if (pName.equals(info.get(i).packageName)) {
                return true;
            }
        }
        return false;
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="horizontal">

   <Button
       android:id="@+id/barrierFree"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="打开无障碍"/>

   <Button
       android:id="@+id/start"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="开始执行"/>
</LinearLayout>

TestAccessibilityService.java

package com.example.myapplication;
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.GestureDescription;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import androidx.annotation.RequiresApi;
import java.util.List;

public class TestAccessibilityService extends AccessibilityService {
    private final String TAG = getClass().getName();

    public static TestAccessibilityService mService;
    public List<AccessibilityNodeInfo> list2 = null;
    public List<AccessibilityNodeInfo> list3 = null;
    public List<AccessibilityNodeInfo> list4 = null;
    public List<AccessibilityNodeInfo> list5 = null;
    public List<AccessibilityNodeInfo> list6 = null;
    public List<AccessibilityNodeInfo> list7 = null;
    public List<AccessibilityNodeInfo> list8 = null;
    public List<AccessibilityNodeInfo> list9 = null;
    public List<AccessibilityNodeInfo> list10 = null;
    public List<AccessibilityNodeInfo> list11 = null;
    public String st = "";
    //初始化
    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
        Log.e(TAG, "onServiceConnected:"+"O(∩_∩)O~~\r\n锁定中..." );
        mService = this;
    }

    //实现辅助功能
    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
//        System.out.println("Event Occurred");

        AccessibilityNodeInfo rootNodeInfo = getRootInActiveWindow();
//        Log.e(TAG, rootNodeInfo.toString());

        int eventType = event.getEventType();
        String packageName = event.getPackageName().toString();
        String className = event.getClassName().toString();
        //Log.d(Config.TAG,"packageName = " + packageName + ", className = " + className);

        switch (eventType) {
            case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
                //事件源:跳转到新的页面,或者弹出了window,dialog等
                Log.e(TAG, "AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED跳转到新的页面");
                if (className.equals("com.ss.android.ugc.aweme.main.MainActivity")){
                    // 关闭首页提示青年弹窗
                    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
                        list8 = rootNodeInfo.findAccessibilityNodeInfosByViewId("com.ss.android.ugc.aweme:id/a-5");
                    }
                    if (null != list8) {
                        for (AccessibilityNodeInfo info : list8) {
                            info.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                        }
                    }

                    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
                        list2 = rootNodeInfo.findAccessibilityNodeInfosByViewId("com.ss.android.ugc.aweme:id/hox");
                    }
                    if (null != list2) {
                        for (AccessibilityNodeInfo info : list2) {
                            Log.e(TAG, info.toString() );
                            info.getParent().getParent().performAction(AccessibilityNodeInfo.ACTION_CLICK);
                        }
                    }
                }
                if (className.equals("com.lynx.tasm.behavior.KeyboardMonitor")){
                    //点击输入框
                    Log.e(TAG, "执行了输入框" );
                    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
                        list3 = rootNodeInfo.findAccessibilityNodeInfosByViewId("com.ss.android.ugc.aweme:id/et_search_kw");
                    }
                    if (null != list3) {
                        for (AccessibilityNodeInfo nodeInfo : list3) {
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                                Bundle arguments = new Bundle();
                                arguments.putCharSequence(
                                        AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "111111");
                                nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
                            }
                        }
                    }
                }

            case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
                Log.e(TAG, "AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED某个view的内容发生的变化");
            case AccessibilityEvent.TYPE_VIEW_SCROLLED:
                Log.e(TAG, "onServiceConnected:"+"实现辅助功能" );
                Log.d("TAG","packageName = " + packageName + ", className = " + className);

                if (className.equals("com.lynx.tasm.behavior.KeyboardMonitor")){
                    Log.e(TAG, "执行了搜索按钮" );
                    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
                        list5 = rootNodeInfo.findAccessibilityNodeInfosByViewId("com.ss.android.ugc.aweme:id/rzy");
                    }
                    if (null != list5) {
                        for (AccessibilityNodeInfo info : list5) {
                            clickByNode(this, info);
                        }
                    }
                }
                if (className.equals("androidx.recyclerview.widget.RecyclerView")){
                    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
                        list6 = rootNodeInfo.findAccessibilityNodeInfosByText("用户");
                    }
                    if (null != list6) {
                        for (AccessibilityNodeInfo info : list6) {
                            Log.e(TAG, info.toString());
                            clickByNode(this, info.getParent());
                        }
                    }
                    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
                        list7 = rootNodeInfo.findAccessibilityNodeInfosByText("关注");
                    }
                    if (null != list7) {
                        for (AccessibilityNodeInfo info : list7) {
                            Log.e(TAG, info.toString());
                        }
                    }
                }
//
//获取根节点
        AccessibilityNodeInfo rootNode = getRootInActiveWindow();
        //匹配Text获取节点
        List<AccessibilityNodeInfo> list1 = rootNode.findAccessibilityNodeInfosByText("match_text");
        //匹配id获取节点
        List<AccessibilityNodeInfo> list2 = rootNode.findAccessibilityNodeInfosByViewId("match_id");
        //获取子节点
        AccessibilityNodeInfo infoNode = rootNode.getChild(index);
        }

    }

    /**
     * 实现位置坐标点击
     * @param service
     * @param nodeInfo
     * @return
     */
    @RequiresApi(api = Build.VERSION_CODES.N)
    public static boolean clickByNode(AccessibilityService service, AccessibilityNodeInfo nodeInfo) {

        if (service == null || nodeInfo == null) {
            return false;
        }

        Rect rect = new Rect();
        nodeInfo.getBoundsInScreen(rect);
        int x = rect.centerX();
        int y = rect.centerY();
        Log.e("acc_", "要点击的像素点在手机屏幕位置::" + rect.centerX() + " " + rect.centerY());
        Point point = new Point(x, y);
        GestureDescription.Builder builder = new GestureDescription.Builder();
        Path path = new Path();
        path.moveTo(point.x, point.y);
        builder.addStroke(new GestureDescription.StrokeDescription(path, 0L, 100L));
        GestureDescription gesture = builder.build();

        boolean isDispatched = service.dispatchGesture(gesture, new AccessibilityService.GestureResultCallback() {
            @Override
            public void onCompleted(GestureDescription gestureDescription) {
                super.onCompleted(gestureDescription);
//                LogUtil.d(TAG, "dispatchGesture onCompleted: 完成...");
            }

            @Override
            public void onCancelled(GestureDescription gestureDescription) {
                super.onCancelled(gestureDescription);
//                LogUtil.d(TAG, "dispatchGesture onCancelled: 取消...");
            }
        }, null);

        return isDispatched;
    }

    @Override
    public void onInterrupt() {
        Log.e(TAG, "onInterrupt: "+"(;′⌒`)\r\n功能被迫中断" );
        mService = null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy: "+"%>_<%\r\n功能已关闭" );
        mService = null;
    }

    // 公共方法

    /**
     * 辅助功能是否启动
     */
    public static boolean isStart() {
        return mService != null;
    }
}

@RequiresApi(api = Build.VERSION_CODES.N)
class MyCallBack extends AccessibilityService.GestureResultCallback {

    public MyCallBack() {
        super();
    }

    @Override
    public void onCompleted(GestureDescription gestureDescription) {
        super.onCompleted(gestureDescription);

    }

    @Override
    public void onCancelled(GestureDescription gestureDescription) {
        super.onCancelled(gestureDescription);

    }
}

抖音userid获取方式

1、首先打开手机上的抖音软件,点击右下角的“我"。

2、进入手机抖音我页面后,点击右上角的三横按钮。

3、弹出来的内容里,再点击“设置"。

4、双击抖音版本地方的空白处。

5丶多双击几次就会出现抖音uⅰd信息,点击uⅰd即可复制了。

本文转自 blog.csdn.net/weixin_4177…,如有侵权,请联系删除。