资讯动态

SKIP 设置功能详解:六大设置项的配置逻辑与源码实现原理

发布时间:2026/10/14 0:16:20 来源:尧图企业网站定制
移动开发原生移动GUI 自动化【免费下载链接】SKIP自动跳过APP开屏广告项目地址https://gitcode.com/gh_mirrors/ski/SKIP点击查看免费下载本文基于 SKIP自动跳过 APP 开屏广告官方文档的「设置功能介绍」页面展开完整覆盖设置页提供的六项功能自动更新、后台任务隐藏、是否允许提示、是否使用严格模式、自定义配置、切换主题。除逐条说明每个开关的行为与使用方式外还会结合 SettingsActivity 等源码讲清每个设置项在 DataStore 中对应的存储键、默认值以及它如何最终影响无障碍服务的点击逻辑与配置加载链路。读完后你可以准确理解每个开关的生效范围与适用场景并能通过源码定位验证其行为。设置页面整体结构设置页由 SettingsActivity 承载采用 Jetpack Compose 构建。onCreate中通过ScaffoldPage依次装配六个组件ScaffoldPage(R.string.settings, { finish() }, { AutoUpdateButton(autoUpdateViewModel) RecentButton(recentViewModel) TipButton(tipViewModel) StrictButton(strictViewModel) CustomButton(configViewModel) { /* 打开自定义配置文档 */ } SwitchThemeButton(switchThemeViewModel) NotificationDialog(notificationDialogViewModel) { ... } })每个设置项均遵循「ButtonCompose 组件 ViewModel状态中转 Repository可选单例状态源」的 MVVM 分层设置值统一通过 DataStoreUtils 持久化到 DataStore。对应的存储键定义在 strings.xml 中设置项DataStore 键默认值自动更新AUTO_UPDATEfalse后台任务隐藏EXCLUDE_FROM_RECENTfalse是否允许提示SKIP_TIPfalse是否使用严格模式STRICT_MODEfalse自定义配置CUSTOM_CONFIG默认配置 URL切换主题CURRENT_THEMEUI_AUTO跟随系统此外设置页右上角菜单中有一项「功能介绍」点击后通过WebViewActivity打开本页文档对应的在线地址即 strings.xml 中的settings_function_intro_url。自动更新开启「自动更新」后应用会在后台每隔 12 小时左右检查「应用版本号」是否有新版本如果有在「关于」页面会显示提示「配置版本号」是否有新版本如果有会主动更新当前的配置文件。源码实现WorkManager 周期任务开关状态由 AutoUpdateViewModel 维护读写 DataStore 键AUTO_UPDATE默认false。真正调度逻辑在 SettingsActivity 中val periodicWorkRequest PeriodicWorkRequestBuilderSyncWorker(12, TimeUnit.HOURS).build() val workManager WorkManager.getInstance(this) autoUpdateViewModel.autoUpdate.observe(this) { when (it) { true - workManager.enqueueUniquePeriodicWork( getString(R.string.worker_sync), // MySyncWorker ExistingPeriodicWorkPolicy.UPDATE, periodicWorkRequest ) false - workManager.cancelUniqueWork(getString(R.string.worker_sync)) } }开启时以唯一工作名MySyncWorker注册一个 12 小时周期的 SyncWorker关闭时取消该唯一工作即立即停止周期性检查。SyncWorker.doWork()每次执行两件事val configPostSchema configReadRepository.readConfig() configReadRepository.changeConfigPostState(configPostSchema) versionRepository.checkVersion()调用 ConfigReadRepository.readConfig() 重新读取并解析当前配置包括自定义配置源刷新配置状态——对应文档中「配置版本号有新版本时主动更新配置文件」调用 ApkVersionRepository 的checkVersion()检查应用新版本——对应「关于」页面的版本提示。需要注意的适用前提WorkManager 的周期任务受系统策略约束如 Doze 模式、省电策略实际触发时刻会有延迟因此文档表述为「12 小时左右」。后台任务隐藏开启「后台任务隐藏」后在后台任务窗口中「SKIP」应用窗口会被隐藏。该项由 RecentButton 展示副标题为「在『最近任务』列表隐藏应用」见settings_background_task_subtitle。状态存于 DataStore 键EXCLUDE_FROM_RECENT默认false。源码实现setExcludeFromRecents实际生效逻辑在 MainActivity 中recentViewModel.excludeFromRecent.observe(this) { exclude - (getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).let { manager - manager.appTasks.forEach { task - task?.setExcludeFromRecents(exclude) } } }即监听开关变化后遍历当前应用的所有ApplicationTask并调用setExcludeFromRecents(exclude)。这是 Android 提供的标准 API效果是在最近任务列表中隐藏该应用的卡片从而避免 SKIP 在后台任务窗口中暴露起到一定的「隐形」效果。从源码结构看该逻辑只在MainActivity前台可见时触发系统会在任务存在时应用该标记。是否允许提示该功能需要开启「允许通知」。开启「是否允许提示」后当成功执行「点击」操作时会显示提示「已为您跳过广告」。提示的触发链路无障碍手势回调提示开关由 TipViewModel / TipRepositorySingleton管理存于 DataStore 键SKIP_TIP默认false。UI 上开/关会显示「需要显示 / 不要显示」settings_tip_yes/settings_tip_no副标题为「执行『跳过』时%1$s提示」。实际提示发生在 MyAccessibilityService 中。服务连接时通过observeForever订阅开关private val tipObserver ObserverBoolean { isShowTip it } // onServiceConnected 中 tipRepository.enable.observeForever(tipObserver)当无障碍服务通过dispatchGesture完成一次点击手势后在GestureResultCallback.onCompleted中判断并弹出 ToastaccessibilityService.dispatchGesture( gesture, object : GestureResultCallback() { override fun onCompleted(gestureDescription: GestureDescription) { super.onCompleted(gestureDescription) if (isShowTip) { MyToast.show(R.string.toast_skip_tip) // 已为您跳过广告 } } }, null )提示文案toast_skip_tip即 strings.xml 中的「已为您跳过广告」。为什么依赖「允许通知」从源码结构看提示采用 Toast/悬浮方式展示其权限基础与通知权限关联。SettingsActivity 中有显式约束tipViewModel.enable.observe(this) { if (it !NotificationManagerCompat.from(MyApp.context).areNotificationsEnabled()) { notificationDialogViewModel.changeDialogState(true) } }即在系统通知权限未开启时尝试打开提示会弹出 NotificationDialog引导用户跳转系统通知设置页Settings.ACTION_APP_NOTIFICATION_SETTINGS同时该回调会调用tipViewModel.changeEnable(false)强制关闭提示开关。另外在onResume中若通知仍未开启也会自动将开关复位为关闭。因此文档中「该功能需要开启『允许通知』」这一前置条件在实现上是硬约束。是否使用严格模式开启「严格模式」SKIP 会完全遵循配置文件中定义的规则因此如果配置文件中没有定义规则的应用就不会执行「点击」操作关闭「严格模式」SKIP 会默认搜索界面中的「跳过」关键字如果找到就会执行「点击」操作。因此即使没有在配置文件中定义规则的应用也可以实现「跳过广告」功能但同时也会存在误触发的情况。开关由 StrictButton 展示文案分别为「完全遵循配置规则」开启与「默认匹配『跳过』关键字」关闭存于 DataStore 键STRICT_MODE默认false。源码实现默认「跳过」规则注入严格模式的核心差异在 ConfigLoadRepository.getTargetRect()suspend fun getTargetRect( rootNode: AccessibilityNodeInfo, activityName: String?, isStrict: Boolean? ): Rect? { val targetAppPackage rootNode.packageName.toString() var targetConfig configLoadSchemaMap[targetAppPackage] if (isStrict ! true) { val defaultSkipTexts listOf( LoadSkipText(text getString(R.string.settings_strict_skip)) // 跳过 ) if (targetConfig null) { targetConfig ConfigLoadSchema(targetAppPackage, defaultSkipTexts) } else if (targetConfig.skipTexts null) { targetConfig.skipTexts defaultSkipTexts } } ... }这段代码精确对应文档的两种行为非严格模式isStrict ! true若配置文件中没有该应用targetConfig null会自动构造一个只包含skipTexts: [{text: 跳过}]的默认规则即对任何应用默认搜索界面文本「跳过」并点击若应用已有配置但没有定义skipTexts也会补上这个默认关键字。这就是「未定义规则的应用也能跳过广告但可能误触发」的来源——任何界面中出现「跳过」文案的节点如「跳过引导」按钮、非广告场景的跳过入口都可能被点击。严格模式不做上述注入只按配置文件中packageName命中的skipTexts/skipIds/skipBounds三类规则查找目标节点未配置的应用不会有任何点击行为。isStrict值来源于 MyAccessibilityService 对StrictRepository.enable的observeForever订阅在onServiceConnected时注册、onDestroy时移除。扫描频率上的附带差异MyAccessibilityService.onAccessibilityEvent中还有一处与严格模式相关的性能保护if (!whiteListRepository.isAppInWhiteList(rootNodePackageName) (isStrict || scanTimes 50)) { // ... 查找目标节点并点击 }从源码结构看在非严格模式下同一应用最多只处理前 50 次无障碍事件scanTimes在应用包名切换时清零这与「开屏广告只出现在启动初期」的场景吻合也降低了持续全文检索的开销严格模式下则不做该次数限制持续按规则匹配。自定义配置点击「自定义配置」可以输入自定义配置规则支持输入纯文本的 YAML 格式或 JSON 格式或可以返回 JSON 或 YAML 文本的 URL 链接副标题即「URL链接 / YAML文本 / JSON文本」。配置规则参考自定义配置文档。源码实现编辑对话框与解析链「自定义配置」行由 CustomButton 实现。点击后弹出Dialog内含一个多行OutlinedTextField初始值从 DataStore 键CUSTOM_CONFIG读取点击帮助图标会通过WebViewActivity打开自定义配置文档页settings_custom_config_url。点击「确定」时if (text.isEmpty()) { DataStoreUtils.removeSync(getString(R.string.store_custom_config)) // 清空则删除键 } else { DataStoreUtils.putSyncData(getString(R.string.store_custom_config), text) } configViewModel.readConfig() // 立即重新加载配置即清空输入框并确定等于恢复默认配置否则保存后立即触发 ConfigViewModel.readConfig() 重新解析无需重启应用。解析链URL → YAML → JSON真正的解析在 ConfigReadRepository按「URL 拉取 → YAML 转 JSON → JSON 反序列化」三级容错链处理suspend fun readConfig() withContext(Dispatchers.IO) { val customContent DataStoreUtils.getSyncData( getString(R.string.store_custom_config), getString(R.string.store_default_config) // 默认配置 URL ) getFromJson(getFromYaml(getFromUrl(customContent))) }getFromUrl用java.net.URL解析输入内容若协议为http/https则通过网络请求抓取文本myApiNetwork.fetchConfigFromUrl否则原样返回——因此纯文本 YAML/JSON 会自然落入下一级处理getFromYaml尝试用 SnakeYAML 将内容按ListConfigReadSchema解析成功则经 Gson 序列化为 JSON 字符串解析失败原样返回兼容本身就是 JSON 的输入getFromJson用 Gson 将最终内容反序列化为ListConfigReadSchema即 ConfigReadSchema 列表每项含packageName、skipTexts、skipIds、skipBounds成功时生成ConfigPostSchema(SUCCESS, md5, list)并对内容计算 MD5 作为配置指纹供版本比对使用任一步失败则返回ConfigPostSchema(FAIL, 未检测到有效的配置, null)。解析成功后由 ConfigViewModel.loadConfig() 调用handleConfig()把每条规则转换为内存中的 ConfigLoadSchemaclick的x,y坐标、bound的l,t,r,b字符串都会被转换为Rect再交给configLoadRepository.loadConfig()供无障碍服务逐事件查询。仓库中的 skip_config_v3.yaml 等 assets 文件展示了配置的实际结构更完整的字段说明见 自定义配置完整参考。切换主题点击「切换主题」可以选择「浅色主题」、「深色主题」、「跟随系统」。源码实现ThemeMode 三态该功能由 SwitchThemeButton 以FlatButtonMenu下拉菜单实现三个选项分别携带 theme_light、theme_dark、theme_auto 图标当前选中项文字以主题色高亮。主题状态封装在 SwitchThemeCarrier 中三态枚举为enum class ThemeMode { UI_LIGHT, UI_DARK, UI_AUTO } data class SwitchThemeCarrier(val themeMode: ThemeMode, val themeName: Int, val themeIcon: Int)SwitchThemeRepositorySingleton从 DataStore 键CURRENT_THEME读取字符串默认UI_AUTO经getThemeCarrier()映射为三态载体ViewModel 将选择写回 DataStore。最终渲染在 AppThemeval darkTheme when(currentTheme.value?.themeMode) { ThemeMode.UI_LIGHT - false ThemeMode.UI_DARK - true else - isSystemInDarkTheme() // UI_AUTO 跟随系统 }即浅色/深色强制指定配色方案「跟随系统」则委托 Compose 的isSystemInDarkTheme()。AppTheme作为各页面的外层 Composable使一次切换即可全局生效同时通过SideEffect同步更新状态栏颜色与浅色/深色状态栏图标外观。小结SKIP 的设置页六项功能可归纳为两条主线行为控制类严格模式、提示、后台任务隐藏直接改变无障碍服务的点击策略或应用可见性其中严格模式决定「是否注入默认『跳过』关键字规则」是准确性与覆盖率的权衡开关配置与更新类自动更新、自定义配置、切换主题前者决定规则来源与新鲜度URL / YAML / JSON 三级解析链 12 小时周期任务后者决定界面呈现。所有设置项默认均为「关闭 / 跟随系统」的保守取值且统一经由 DataStore 持久化、LiveData驱动 UI 刷新源码路径均在 ui/settings 目录下可按本文所列文件逐一对照验证。赞分享移动开发原生移动GUI 自动化【免费下载链接】SKIP自动跳过APP开屏广告项目地址https://gitcode.com/gh_mirrors/ski/SKIP点击查看免费下载相关推荐librealsense 深度相机 SDK 实战指南librealsense 深度相机 SDK 实战指南 你刚把 RealSense 深度相机插上 USB终端里却看不到任何画面设备管理器里还是未知设备——这是智能硬件音视频计算机视觉gitsome配置管理config.py处理用户设置的逻辑gitsome配置管理config.py处理用户设置的逻辑 配置文件与核心类结构 gitsome的用户配置系统核心实现于 gitsome/config.py开发工具版本控制3分钟解锁离线OCR这款免费开源工具如何重塑你的数字工作流3分钟解锁离线OCR这款免费开源工具如何重塑你的数字工作流 你是否曾面对屏幕上的代码片段需要逐字敲打是否处理过数百页扫描文档感到无从下手在数字信息爆OCR桌面应用创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑