- 移动开发
- 原生移动
- GUI 自动化
【免费下载链接】SKIP
自动跳过APP开屏广告
本文以 SKIP 官方文档《启用无障碍服务》为骨架,完整讲解在 Android 系统中启用 SKIP 无障碍服务的两步操作(点击屏幕中央按钮、在系统无障碍页面打开「使用"SKIP"」开关),并进一步结合仓库源码剖析服务声明、状态判定与自动点击手势的底层实现。读完后,你不仅能按步骤完成启用,还能理解 SKIP 从「服务连接」到「识别开屏广告并点击跳过」的完整链路,以及遇到「发生故障」状态时该如何恢复。
1. 操作步骤:两步启用无障碍服务
SKIP 依赖 Android 系统的**无障碍服务(Accessibility Service)**来感知当前前台应用的界面节点并模拟点击。启用过程分为两步:
步骤一:点击屏幕中央按钮。打开 SKIP 主界面后,界面顶部是一个占据屏幕中央的宽按钮。当服务未启动时,按钮显示为灰色的「已停止 / 点此启动」;点击该按钮后,SKIP 会直接跳转到系统「无障碍设置」页面(首次启动会先弹出「开始使用」教程提示框,确认后跳转)。
步骤二:点击「使用"SKIP"」。在系统无障碍设置页中找到「SKIP」条目并进入,打开「使用"SKIP"」开关,随后按系统要求确认授权。开启成功后返回 SKIP 主界面,中央按钮会变为「运行中」。
下图分别展示两个操作步骤的位置(原文档 enable-accessibility-service.md 中的配图):
提示:系统页面上「SKIP 简介」一栏显示「若无障碍服务发生故障,可以关闭后再打开」,这与 SKIP 主界面的故障状态提示相互对应,详见 第 5 节。
2. 服务声明:无障碍服务的注册入口
跳过广告能力的前提是系统认可 SKIP 是一个合法的无障碍服务。这一点由两处配置保证:
AndroidManifest.xml 中的服务声明。在 AndroidManifest.xml 中,MyAccessibilityService以如下方式注册:
<service android:name=".service.MyAccessibilityService" android:enabled="true" android:exported="true" 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>三个关键属性缺一不可:
android.permission.BIND_ACCESSIBILITY_SERVICE:系统绑定无障碍服务所需的权限门槛;intent-filter中的android.accessibilityservice.AccessibilityServiceaction:让系统能在「已安装的服务」列表中检索到它;meta-data指向的@xml/accessibility资源文件:描述该服务的能力参数。
accessibility.xml 的能力配置。accessibility.xml 中声明了 SKIP 运行时所需的全部能力:
<accessibility-service android:accessibilityEventTypes="typeAllMask" android:accessibilityFeedbackType="feedbackAllMask" android:accessibilityFlags="flagReportViewIds|flagIncludeNotImportantViews|flagDefault|flagRetrieveInteractiveWindows|flagRequestFilterKeyEvents" android:canPerformGestures="true" android:canRequestFilterKeyEvents="true" android:canRetrieveWindowContent="true" android:description="@string/accessibility_description" android:notificationTimeout="100" />各参数对 SKIP 的实际意义(可结合 MyAccessibilityService.kt 的实现理解):
| 属性 | 取值 | 对 SKIP 的意义 |
|---|---|---|
accessibilityEventTypes | typeAllMask | 接收所有类型的事件,onAccessibilityEvent才能持续被回调,从而反复扫描界面 |
canRetrieveWindowContent | true | 允许通过getCurrentRootNode()获取当前窗口根节点,遍历节点树是定位「跳过」按钮的基础 |
flagReportViewIds/flagIncludeNotImportantViews | 已启用 | 节点会携带viewIdResourceName,SKIP 的「按 ID 跳过」规则依赖此标记;包含非重要视图可避免漏掉广告页元素 |
canPerformGestures | true | 允许调用dispatchGesture模拟点击,这是执行「跳过」动作的核心权限 |
canRequestFilterKeyEvents | true | 允许拦截按键事件,SKIP 用它监听「音量减」键来触发布局检查功能(见onKeyEvent,MyAccessibilityService.kt) |
notificationTimeout | 100 | 单位毫秒,事件回调节流时间,控制扫描频率 |
description | 系统页面上展示的简介文案 | 取自 strings.xml:SKIP 可以帮您自动跳过应用开屏广告,即上文系统设置页「SKIP 简介」中显示的文字 |
3. 主界面按钮:一个由服务状态驱动的按钮
「屏幕中央按钮」并非普通按钮,它的文案、颜色和图标都由无障碍服务状态实时驱动。
入口逻辑。MainActivity.kt 中,StartButton的点击回调为:
StartButton(startAccessibilityViewModel = startAccessibilityViewModel) { if (DataStoreUtils.getSyncData(getString(R.string.store_show_tutorial), true)) { tutorialViewModel.changeDialogState(true) // 首次:弹教程提示框 } else { startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)) // 之后:直达无障碍设置 } }即首次点击会弹出「是否需要前往查看『开始使用』教程」的对话框(TutorialDialog.kt),选择「立即前往」后同样会跳转到Settings.ACTION_ACCESSIBILITY_SETTINGS系统页面——这正对应步骤二所在的界面。
按钮的三态映射。StartAccessibilityViewModel.kt 定义了三种状态对应的按钮样式:
| 服务状态 | 按钮文案 | 外观 | 图标 |
|---|---|---|---|
STOPPED(未启动) | 「已停止 点此启动」 | 灰色0xFF808080 | block |
STARTED(运行中) | 「运行中」 | 深蓝0xFF1E4377 | check_circle |
FAULTED(故障) | 「发生故障 点此重新启动」 | 深红0xFF771E1E | error |
StartButton组合(StartAccessibilityButton.kt)通过collectAsState收集buttonState并渲染到ExtendedFloatingActionButton上,这就是截图中屏幕中央那个大按钮的实现。
4. 启用成功后发生了什么:从服务连接到自动点击
用户在系统页打开「使用"SKIP"」开关后,系统会绑定MyAccessibilityService,源码中的关键路径如下:
1. 服务连接并上报状态。onServiceConnected(MyAccessibilityService.kt)被调用时,立即执行startAccessibilityRepository.changeAccessibilityState(AccessibilityState.STARTED),主界面按钮随之切换为「运行中」。同时服务订阅了「常驻通知栏」「提示」「严格模式」三个开关的 LiveData,供后续行为使用。
2. 持续扫描当前界面。系统按事件持续回调onAccessibilityEvent(MyAccessibilityService.kt),核心流程:
- 通过
getCurrentRootNode()获取前台窗口根节点,取出packageName; - 若前台应用切换,则重置扫描计数
scanTimes与已点击区域集合clickedRect; - 若该应用不在白名单中(
whiteListRepository.isAppInWhiteList),且处于严格模式或scanTimes < 50(即进入应用后的前 50 次扫描窗口内),则调用configLoadRepository.getTargetRect按配置查找「跳过」按钮的Rect坐标; - 找到且该坐标尚未点击过时,切换回主线程执行
click。
3. 用模拟手势完成点击。click方法(MyAccessibilityService.kt)构造一条位于目标Rect中心的零长度路径,封装为GestureDescription后调用dispatchGesture下发;手势完成后若用户开启了「是否允许提示」(tipRepository),会弹出「已为您跳过广告」的 Toast。
4. 命中规则来自哪里。getTargetRect在 ConfigLoadRepository.kt 中并行执行三类匹配任务:skipByTexts(按文本,如「跳过」)、skipByIds(按 viewId)、skipBounds(按屏幕区域),取最先命中者返回坐标。非严格模式下,若配置缺失还会退化为默认匹配文本「跳过」。配置文件的结构与字段含义可进一步参阅 custom-config 系列文档。
此外,onKeyEvent还利用无障碍服务的按键拦截能力实现了第二个入口:当布局检查服务(InspectService)运行中时,按下「音量减」键会触发一次界面节点捕获(MyAccessibilityService.kt),这与 布局检查 文档中「点按音量-执行布局检查」的说明一致。
5. 状态检测与故障恢复
SKIP 如何判断服务处于STARTED / STOPPED / FAULTED三种状态?答案在 AccessibilityStateUtils.kt:
fun getAccessibilityState(): AccessibilityState { val isSettingOn = isAccessibilitySettingsOn() // 系统设置中开关是否打开 val isRunning = isAccessibilitySettingsRunning() // 服务进程是否真正在跑 return when { isSettingOn && isRunning -> AccessibilityState.STARTED isSettingOn && !isRunning -> AccessibilityState.FAULTED else -> AccessibilityState.STOPPED } }两个判定函数的实现细节值得注意:
isAccessibilitySettingsOn(AccessibilityStateUtils.kt)先读取Settings.Secure.ACCESSIBILITY_ENABLED总开关,再解析Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES(以:分隔的已启用服务列表),并匹配以下两种组件写法(兼容带/不带包名前缀的组件名):val serviceNameList = listOf( "com.android.skip/.service.MyAccessibilityService", "com.android.skip/com.android.skip.service.MyAccessibilityService" )isAccessibilitySettingsRunning则直接检查MyAccessibilityService进程实例是否存活。
这正好解释了截图里系统页面那句「若无障碍服务发生故障,可以关闭后再打开」:「发生故障」(FAULTED)= 设置里开关是开的,但服务进程已不在运行(例如被系统省电策略杀死)。恢复方法就是把「使用"SKIP"」开关关掉再打开;返回 SKIP 主界面点击红色的「发生故障 点此重新启动」按钮,同样会带你回到系统无障碍设置页重新开启。
另外,onDestroy(MyAccessibilityService.kt)中会在服务被系统拆除时上报STOPPED状态并顺带停止布局检查服务等伴生服务,保证主界面按钮状态与实际运行状态一致。
6. 启用之后还需要做什么
无障碍服务只负责「跳过」,不负责「保活」。系统(尤其是 MIUI/HyperOS 等定制系统)可能随时回收后台服务,因此官方文档建议接着完成应用保活配置:关闭电池优化、允许自启动、锁定后台任务等,具体步骤参见 background-process-keep-alive.md。主界面的「应用保活」入口即对应该功能(AliveActivity)。
小结
- 两步启用:主界面中央按钮 → 系统「无障碍设置」→ 打开「使用"SKIP"」开关(第 1 节截图所示)。
- 声明位置:服务注册在 AndroidManifest.xml,能力参数在 accessibility.xml,其中
canPerformGestures、canRetrieveWindowContent是跳过广告两大核心能力。 - 运行链路:
onServiceConnected上报 STARTED →onAccessibilityEvent持续扫描根节点 →ConfigLoadRepository.getTargetRect按文本/ID/区域命中坐标 →dispatchGesture模拟点击。 - 故障恢复:按钮显示「发生故障」时,关闭再打开系统开关即可(状态判定逻辑见 AccessibilityStateUtils.kt)。
- 下一步:完成 应用保活配置,确保服务长期存活。
- 移动开发
- 原生移动
- GUI 自动化
【免费下载链接】SKIP
自动跳过APP开屏广告
相关推荐
基于无障碍服务的安卓开屏广告自动跳过:Android-Touch-Helper(开屏跳过)实现原理与使用指南
基于无障碍服务的安卓开屏广告自动跳过:Android Touch Helper(开屏跳过)实现原理与使用指南 Android Touch Helper(应用名"
移动开发GUI 自动化Android-Touch-Helper(开屏跳过):基于无障碍服务的安卓开屏广告自动跳过助手技术全解析
Android Touch Helper(开屏跳过):基于无障碍服务的安卓开屏广告自动跳过助手技术全解析 本文系统解析开源项目 Android Touch He
移动开发GUI 自动化SKIP 上手指南:从安装到无障碍服务自动跳过开屏广告的五步实战
SKIP 上手指南:从安装到无障碍服务自动跳过开屏广告的五步实战 SKIP 是一款免费开源的安卓应用,它借助 Android 无障碍服务自动点击 APP 开屏广
移动开发原生移动GUI 自动化
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考