likes
comments
collection
share

基于无障碍服务实现自动跳过APP启动页广告

作者站长头像
站长
· 阅读数 1

基于无障碍服务实现自动跳过APP启动页广告 实现原理AccessibilityService模拟点击

项目Demo地址github.com/AndroidLMY/…

一. res目录下新建xml文件夹新建文件accessibility.xml

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeWindowStateChanged|typeNotificationStateChanged|typeViewTextSelectionChanged|typeViewClicked"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:canRetrieveWindowContent="true"
    android:accessibilityFlags="flagDefault|flagRetrieveInteractiveWindows"
    android:canRequestTouchExplorationMode="true"
    android:description="@string/app_name"
    android:notificationTimeout="100"/>

清单文件中service中配置引用文件

         <service
            android:name=".SkipService"
            android:label="Automaticskip"
            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" />
        </service>

清单文件权限如下:

    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

二. 新建服务SkipService继承AccessibilityService类

package com.androidlmy.automaticskip;

import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;

import java.util.List;

/**
 * @功能:
 * @Creat 2019/12/2 10:16
 * @User Lmy
 * @Compony zaituvideo
 */
public class SkipService extends AccessibilityService {
    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
        AccessibilityServiceInfo config = new AccessibilityServiceInfo();
        //配置监听的事件类型为界面变化|点击事件
        config.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_VIEW_CLICKED;
        config.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
        if (Build.VERSION.SDK_INT >= 16) {
            config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
        }
        setServiceInfo(config);
    }

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        final AccessibilityNodeInfo nodeInfo = event.getSource();//当前界面的可访问节点信息
        if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {//界面变化事件
            ComponentName componentName = new ComponentName(event.getPackageName().toString(), event.getClassName().toString());
            ActivityInfo activityInfo = tryGetActivity(componentName);
            boolean isActivity = activityInfo != null;

            if (isActivity) {
                Log.d("WindowChange", "当前运行包名" + nodeInfo.getPackageName());
                switch (nodeInfo.getPackageName().toString()) {
                    case "com.netease.cloudmusic":
                        new Handler().postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                skip(nodeInfo.findAccessibilityNodeInfosByViewId("com.netease.cloudmusic:id/c3l"));
                            }
                        }, 500);
                        break;
                   case "cn.xiaochuankeji.zuiyouLite":
                        new Handler().postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                skip(nodeInfo.findAccessibilityNodeInfosByViewId("cn.xiaochuankeji.zuiyouLite:id/btn_skip"));
                            }
                        }, 2000);
                        break;
             
                    default: {
                        List<AccessibilityNodeInfo> nodeInfoList = nodeInfo.findAccessibilityNodeInfosByText("跳过");
                        for (AccessibilityNodeInfo info : nodeInfoList) {
                            CharSequence charSequence = info.getText();
                            if (charSequence != null) {
                                String msg = charSequence.toString();
                                if (msg.contains("跳过")) {
                                    info.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                                    Toast.makeText(this, "跳过广告", Toast.LENGTH_SHORT).show();
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private void skip(List<AccessibilityNodeInfo> nodeInfoList) {
        Log.d("WindowChange", "数据" + nodeInfoList.size());
        if (nodeInfoList != null && nodeInfoList.size() > 0) {
            nodeInfoList.get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK);
            Toast.makeText(getApplicationContext(), "跳过广告", Toast.LENGTH_SHORT).show();
        }
    }

    private ActivityInfo tryGetActivity(ComponentName componentName) {
        try {
            return getPackageManager().getActivityInfo(componentName, 0);
        } catch (PackageManager.NameNotFoundException e) {
            return null;
        }
    }

    @Override
    public void onInterrupt() {
    }
}

主要代码

nodeInfo.findAccessibilityNodeInfosByViewId("com.netease.cloudmusic:id/c3l")

根据已知控件id查找网易云启动页的控件  下面会介绍如何获取控件的id

private void skip(List<AccessibilityNodeInfo> nodeInfoList) {
        Log.d("WindowChange", "数据" + nodeInfoList.size());
        if (nodeInfoList != null && nodeInfoList.size() > 0) {
            nodeInfoList.get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK);
            Toast.makeText(getApplicationContext(), "跳过广告", Toast.LENGTH_SHORT).show();
        }
    }
 nodeInfoList.get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK);

模拟点击从而实现自动跳过启动页广告

MainActivity代码如下:开启无障碍功能和启动服务

package com.androidlmy.automaticskip;

import androidx.appcompat.app.AppCompatActivity;

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 android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private Intent intent;
    private TextView text1;
    private TextView text2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intent = new Intent(MainActivity.this, SkipService.class);
        startService(intent);
        text1 = findViewById(R.id.text1);
        text2 = findViewById(R.id.text2);
        text1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (!isAccessibilitySettingsOn(MainActivity.this, SkipService.class.getCanonicalName())) {
                    Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
                    startActivity(intent);
                    //跳转设置打开无障碍
                } else {
                    intent = new Intent(MainActivity.this, SkipService.class);
                    startService(intent);
                    //启动服务
                }
            }
        });
        text2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                stopService(intent);
            }
        });
    }

    /**
     * 检测辅助功能是否开启
     *
     * @param mContext
     * @return boolean
     */

    private boolean isAccessibilitySettingsOn(Context mContext, String serviceName) {
        int accessibilityEnabled = 0;
        // 对应的服务
        final String service = getPackageName() + "/" + serviceName;
        //Log.i(TAG, "service:" + service);
        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;
    }
}

三.获取软件启动页面跳过按钮的id

打开安装SDK目录下tools文件夹 D:\webapp\SDK\android\tools找到monitor.bat双击打开

基于无障碍服务实现自动跳过APP启动页广告

基于无障碍服务实现自动跳过APP启动页广告

点击跳过按钮控件右侧可以看到控件的id为com.netease.cloudmusic:id/c6b 这样就得到了控件的id

其他软件可能会遇到无id的时候可以使用文字查找遍历

微博的是一张图片。。。。暂时还不知道如何处理。。希望对你们有点启发

项目地址:github.com/AndroidLMY/…

目前支持的app有:网易云音乐,百度网盘,皮皮搞笑,资源猫 ,华为应用市场,生活助手(flyme), 在途视频, 腾讯视频,斗鱼直播