SKIP 应用白名单:让指定应用完全免疫自动点击的功能指南与源码解析
发布时间:2026/10/14 22:48:37 锦皓数字建站

移动开发原生移动GUI 自动化【免费下载链接】SKIP自动跳过APP开屏广告项目地址https://gitcode.com/gh_mirrors/ski/SKIP点击查看免费下载本文围绕 SKIP 的「应用白名单」功能展开它用于列出设备上所有已安装的应用并允许用户把不想被 SKIP 干预的应用加入白名单。读完本文你不仅能掌握白名单的操作方式含「显示系统应用」开关还能理解它从 DataStore 持久化到无障碍服务点击拦截的完整实现链路。功能概述白名单解决什么问题SKIP 的核心职责是通过无障碍服务自动点击目标控件来跳过应用开屏广告。但自动点击并不总是安全的——对某些应用例如支付类、系统类或需要人工交互的应用SKIP 的自动点击可能造成干扰。应用白名单功能就是为此设计的隔离开关其行为规则为白名单页面会列出所有已经安装的应用页面右上角菜单中提供「显示系统应用」选项由于系统应用数量较多该选项默认不勾选当把一个应用加入白名单即把它的开关打开后SKIP 就不会对该应用执行任何「点击」动作无论该应用是否在配置文件中定义了跳过规则因此白名单可以用来防止 SKIP 对某些应用的干扰。也就是说白名单的优先级高于配置规则即使配置文件中为某个应用写好了skipIds/skipTexts规则只要该应用的包名出现在白名单中SKIP 的自动点击逻辑就会整体跳过它。功能入口与页面结构白名单入口位于主界面MainActivity.kt 中的WhiteListButton通过startActivity跳转到WhiteListActivity。WhiteListActivity.kt 是一个基于 Jetpack Compose 的页面整体结构分为两部分内容区Column上方是搜索栏SearchTextField下方是应用列表AppListColumn右上角菜单包含「功能介绍」和「显示系统应用」两个菜单项。对应地该页面注入了 5 个 ViewModel各自承担独立职责ViewModel职责源码位置AppListViewModel应用列表的分页加载与刷新AppListViewModel.ktShowSystemViewModel「显示系统应用」勾选状态ShowSystemViewModel.ktWhiteListViewModel白名单开关的变更与持久化WhiteListViewModel.ktSwitchThemeViewModel全局主题切换位于ui/settings/theme目录SearchViewModel搜索关键字状态SearchViewModel.kt在onCreate中Activity 建立了两处状态联动见 WhiteListActivity.ktshowSystemViewModel.isShowSystem变化时调用appListViewModel.reloadData(it, searchViewModel.getQuery())重新加载列表searchViewModel.query变化时调用appListViewModel.reloadData(showSystemViewModel.getIsShowSystem(), it)按新关键字刷新。因此无论用户勾选「显示系统应用」还是输入搜索词列表都会以两者组合作为条件整体重建。菜单中的「显示系统应用」由 ShowSystemButton.kt 渲染为一个Checkbox其默认值在ShowSystemViewModel中初始化为false——这与文档中「因为系统应用较多所以默认是不列出的」的描述完全一致。此外菜单里的「功能介绍」项会打开WebViewActivity加载官方文档页面字符串常量定义在 strings.xmlwhitelist应用白名单、whitelist_show_system显示系统应用、whitelist_dot存储键前缀WHITELIST_DOT等。应用列表系统应用过滤、搜索与分页列表数据的获取实现在 AppListRepository.kt其getData(currentPage, pageSize, isShowSystem, query)方法分三步处理第一步读取全部已安装应用private val appInfos: MutableListApplicationInfo by lazy { MyApp.context.packageManager.getInstalledApplications(PackageManager.GET_META_DATA) }应用信息只通过PackageManager枚举一次并缓存在内存中by lazy后续过滤、搜索、分页都在这份缓存上进行。第二步按「是否显示系统应用」过滤val apps if (isShowSystem) { appInfos } else { appInfos.filter { (it.flags and ApplicationInfo.FLAG_SYSTEM) 0 } }从源码结构看这里判断的是ApplicationInfo.FLAG_SYSTEM标志位默认未勾选「显示系统应用」时只要应用带有系统应用标志就被过滤掉勾选后则展示完整列表。第三步按关键字过滤并分页截取val filteredApps if (query.isNotEmpty()) { apps.filter { it.loadLabel(pkgManager).toString().contains(query, ignoreCase true) } } else { apps } val fromIndex currentPage * pageSize val toIndex minOf(fromIndex pageSize, filteredApps.size) return filteredApps.subList(fromIndex, toIndex) .map { AppListItem( it.loadLabel(pkgManager).toString(), // 应用名 it.packageName, // 包名白名单的判定依据 it.loadIcon(pkgManager), // 图标 whiteListRepository.isAppInWhiteList(it.packageName) // 白名单状态 ) }搜索是按应用显示名loadLabel做忽略大小写的子串匹配且每行都会实时查询该包名是否已在白名单中isAppInWhiteList用于渲染开关的初始状态。数据模型见 AppListItem.kt包含appName、packageName、appIcon、checked四个字段。分页由 Paging3 驱动AppListViewModel.kt 中PagingConfig设置pageSize 20且enablePlaceholders falsereloadData会先invalidate()旧的AppListPagingSource再创建携带新isShowSystem/query参数的新Pager。翻页逻辑在 AppListPagingSource.kt 中以页码为 key返回空页时nextKey置null表示没有更多数据。列表 UIAppListColumn.kt用LazyColumncollectAsLazyPagingItems渲染并处理了加载中、「加载更多...」与加载失败三种LoadState。搜索框 SearchTextField.kt 是一个 56dp 高、圆角 16dp 的OutlinedTextField输入即触发SearchViewModel.changeQuery。白名单状态的存储DataStore 中的布尔键值对白名单的持久化是整个功能中最值得注意的部分。每个应用的白名单状态并不是存在一个数组里而是以「前缀 包名」为键的独立布尔键写入 Preferences DataStoreWhiteListViewModel.kt 中开关变更时执行fun updateWhiteList(packageName: String, checked: Boolean) { whiteListRepository.updateWhiteList(packageName, checked) // 1. 先更新内存态 viewModelScope.launch { withContext(Dispatchers.IO) { DataStoreUtils.putData(getString(R.string.whitelist_dot) packageName, checked) // 2. 再落盘 } } }即最终写入的键形如WHITELIST_DOTcom.jd.app.reader前缀常量WHITELIST_DOT定义在 strings.xml值为true/false由 DataStoreUtils.kt 的saveBooleanData写入名为SKIPAPPDataStore的 Preferences 文件见 DataStoreUtils.kt。读取侧在 WhiteListRepository.kt 中它是一个Singleton进程内只初始化一次Singleton class WhiteListRepository Inject constructor() { private val _whiteList: MutableListString by lazy { runBlocking { initWhitelist().toMutableList() } } private suspend fun initWhitelist() withContext(Dispatchers.IO) { val allPreferences MyApp.context.dataStore.data.first() allPreferences.asMap() .filter { it.key.name.startsWith(getString(R.string.whitelist_dot)) it.value true }.keys.map { it.name.substringAfter(getString(R.string.whitelist_dot)) } } // ... }其初始化逻辑是把 DataStore 中所有键名以WHITELIST_DOT开头且值为true的键筛选出来去掉前缀后即得到已加入白名单的包名集合缓存为内存中的_whiteList。之后updateWhiteList(packageName, checked)勾选时向列表添加包名取消勾选时移除仅改内存态落盘由 ViewModel 负责isAppInWhiteList(packageName)通过indexOf(packageName) ! -1判断包名是否在白名单中。这种「前缀键 布尔值」的设计让每个应用的白名单状态可以独立读写、互不干扰新增/移除应用也无需重建整个存储结构。拦截机制白名单应用如何被「完全放行」白名单真正生效的位置在无障碍服务的事件回调中。MyAccessibilityService.kt 的onAccessibilityEvent是 SKIP 每次屏幕事件到达时的入口其中第 95 行是整个自动点击流程的总闸val rootNodePackageName rootNode.packageName.toString() if (rootNodePackageName ! appPackageName) { scanTimes 0 clickedRect.clear() appPackageName rootNodePackageName } if (!whiteListRepository.isAppInWhiteList(rootNodePackageName) (isStrict || scanTimes 50)) { // 通过配置查找目标控件 rect找到后 dispatchGesture 执行点击 ... }可以确认以下几点白名单检查发生在最外层!whiteListRepository.isAppInWhiteList(rootNodePackageName)为假时整段「查配置 → 找 rect → 发点击手势」的逻辑直接不执行。这与文档中「不会对这个应用执行任何点击的动作无论是否在配置中定义」的语义一致——白名单优先级高于配置文件中packageName/skipIds/skipTexts/skipBounds的规则配置示例见 skip_config_v2.yaml。判定依据是当前焦点窗口的根节点包名SKIP 以rootInActiveWindow的packageName识别「当前前台应用」前台应用切换时会重置scanTimes并清空已点击区域缓存clickedRect保证白名单判定始终针对当前所在应用。点击动作本身通过无障碍手势派发命中目标后会构造一条 100ms 的GestureDescription用dispatchGesture完成模拟点击见 MyAccessibilityService.kt。白名单应用因为走不到这一步天然免疫所有此类点击。另外从源码结构看isStrict严格模式与scanTimes 50扫描次数上限是与白名单并列的两道控制条件但它们只影响「是否继续尝试匹配点击」而白名单是唯一能彻底关闭某应用点击行为的用户级开关。小结相关文件索引关注点文件功能说明文档docs/guide/white-list/intro.md白名单页面搜索栏 列表 菜单app/src/main/java/com/android/skip/ui/whitelist/WhiteListActivity.kt白名单内存态 DataStore 键解析app/src/main/java/com/android/skip/ui/whitelist/WhiteListRepository.kt开关持久化写入app/src/main/java/com/android/skip/ui/whitelist/WhiteListViewModel.kt已安装应用枚举、系统应用过滤、搜索、分页app/src/main/java/com/android/skip/ui/whitelist/list/AppListRepository.ktPaging3 分页配置app/src/main/java/com/android/skip/ui/whitelist/list/AppListViewModel.ktDataStore 工具与SKIPAPPDataStoreapp/src/main/java/com/android/skip/util/DataStoreUtils.kt点击拦截入口白名单判定app/src/main/java/com/android/skip/service/MyAccessibilityService.kt字符串常量WHITELIST_DOT等app/src/main/res/values/strings.xml总结来说SKIP 的白名单是一个「按包名一票否决」的隔离机制——UI 层通过PackageManager枚举应用并用 Paging3 分页展示状态层用WHITELIST_DOT前缀布尔键写入 Preferences DataStore执行层则在无障碍事件回调的最外圈用isAppInWhiteList短路整个点击流程从而保证被加入白名单的应用永远不会收到 SKIP 发出的任何自动点击。赞分享移动开发原生移动GUI 自动化【免费下载链接】SKIP自动跳过APP开屏广告项目地址https://gitcode.com/gh_mirrors/ski/SKIP点击查看免费下载相关推荐深入理解Riva-Translate-4B-Instruct-v1.1的聊天模板自定义翻译指令的终极技巧深入理解Riva Translate 4B Instruct v1.1的聊天模板自定义翻译指令的终极技巧 Riva Translate 4B InstructAutoClicker自动点击器完全使用指南AutoClicker自动点击器完全使用指南 AutoClicker是一款功能强大的桌面应用程序专门用于自动化鼠标点击任务。该工具基于C 和WPF技术开发提桌面应用GUI 自动化NocoBase 多应用应用单点登录子应用自动登录、用户名映射与自动注册实践NocoBase 多应用应用单点登录子应用自动登录、用户名映射与自动注册实践 应用单点登录App SSO是 NocoBase 多应用场景下的一项认证能力低代码后端前端人工智能AI 应用工作流自动化创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。