news 2026/9/17 4:16:27

WebToApp 扩展模块(Extension Modules)配置实战:在「编辑通用配置」中为 APK 应用挂载 JS/CSS 扩展、用户脚本与 MV3 浏览器扩展

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
WebToApp 扩展模块(Extension Modules)配置实战:在「编辑通用配置」中为 APK 应用挂载 JS/CSS 扩展、用户脚本与 MV3 浏览器扩展

WebToApp 扩展模块(Extension Modules)配置实战:在「编辑通用配置」中为 APK 应用挂载 JS/CSS 扩展、用户脚本与 MV3 浏览器扩展

【免费下载链接】web-to-appThe most full featured web-to-app toolkit on Android, a complete APK workshop that runs entirely on your phone项目地址: https://gitcode.com/GitHub_Trending/web/web-to-app

导读

本篇技术指南聚焦 WebToApp 中Extension Modules(扩展模块)这一能力卡片:它位于每个应用的「编辑通用配置(Edit Common Config)」编辑器内,负责把项目内已安装的扩展(JS/CSS 模块、用户脚本、MV3 Chrome 扩展)按应用粒度挂载到生成的 APK 中。读完本文,你将掌握extensionEnabledextensionModuleIdsextensionFabIcon三个配置项的完整语义,理解扩展从「模块库管理 → 应用配置 → WebView 生命周期注入」的完整链路,并能读懂仓库内置模块的module.json清单,动手配置出属于自己应用的扩展组合。

一、功能定位:给“已发布的应用”留的后门

WebToApp 的扩展体系在设计上有一个鲜明特点:应用打包发布之后依然可扩展。扩展不写死在应用逻辑里,而是由统一的ExtensionManager管理、由 WebView 在页面生命周期钩子处注入,因此同一套扩展体系同时服务于“打包前的配置”与“打包后的运行”两个阶段。本文要讲解的正是打包前配置这一环——在「编辑通用配置」的Extension modules卡片里完成三个关键设置。

在编辑器中的入口位置见 编辑通用配置总览:在应用卡片上点击Edit Common Config(Web 类应用直接显示为Edit),在「Extensions & network」分区即可找到Extension Modules卡片。

二、卡片上的三个配置项

该卡片提供三个核心选项,分别对应数据模型WebApp中的三个字段(见 WebApp.kt):

卡片选项对应字段类型与默认值作用
EnableextensionEnabledBoolean = false总开关:仅为当前应用启用/停用整套扩展注入
Selected modulesextensionModuleIdsList<String> = emptyList()选择哪些已安装模块运行在该应用中(按模块id精确匹配)
FAB iconextensionFabIconString? = null扩展面板悬浮按钮(Floating Button)的图标,空值使用默认图标

这三个字段在打包时会被写入 APK 的运行时配置。在 ApkConfigJsonFactory.kt 中可以看到它们被序列化为 JSON 配置项:

"extensionEnabled" to extension.enabled, "extensionFabIcon" to extension.fabIcon, "extensionModuleIds" to extension.moduleIds,

对应的运行时配置块定义在 ApkConfig.kt:

data class ExtensionBlock( val enabled: Boolean = false, val moduleIds: List<String> = emptyList(), val embeddedModules: List<EmbeddedExtensionModule> = emptyList(), val fabIcon: String = "" )

值得注意的是embeddedModules字段:与“按 id 引用已安装模块”不同,它是随 APK 内嵌的模块完整快照,用于保证引用模块的配置在目标设备上一定可用。

三、被选中模块的运行时行为

仅仅在卡片上勾选模块还不够,理解“勾选之后发生了什么”才能正确排错。运行时有两套匹配逻辑叠加:

  1. 应用级过滤:只有extensionModuleIds里列出的模块(且处于 enabled 状态)才会进入候选集;
  2. 页面级过滤:模块自身的urlMatches规则决定它在哪些 URL 上真正执行。

ExtensionManager.generateInjectionCode()(见 ExtensionManager.kt)同时按runAt(注入时机)与sourceType(排除用户脚本/Chrome 扩展,它们走独立的注入通道)过滤后,才把模块代码包裹进带try/catch的 IIFE 注入页面:

val matchingModules = getModulesForUrl(url).filter { it.runAt == runAt && it.sourceType != ModuleSourceType.CHROME_EXTENSION && it.sourceType != ModuleSourceType.USERSCRIPT && it.sourceType != ModuleSourceType.GREASYFORK }

也就是说:即便模块在卡片中被选中,它仍必须满足“URL 匹配”且“运行时机正确”才会生效——这解释了为什么某些模块在特定页面不工作。

运行时机(Run time)

模块数据模型ExtensionModulerunAt字段(ExtensionModule.kt)定义了五种注入时机:

ModuleRunTime触发的 WebView 生命周期事件
DOCUMENT_STARTonPageStarted(文档尚未开始解析)
DOCUMENT_ENDonPageFinished/DOMContentLoaded
DOCUMENT_IDLE页面加载完成之后(load事件)
CONTEXT_MENU长按弹出上下文菜单时
BEFORE_UNLOAD页面卸载之前(beforeunload

从源码看,该字段在ExtensionModule数据类中的默认值为DOCUMENT_END(见 ExtensionModule.kt),这也是 JS Modules 文档 中标注的默认值。

URL 匹配规则(urlMatches)

每个模块还携带一组 URL 匹配规则(Chrome 风格 glob 或正则),见matchesUrl()实现(ExtensionModule.kt):

  • isRegex: false(默认)——Chrome 风格 glob:*匹配任意内容;*://展开为(https?|ftp|file)://*<all_urls>匹配一切 URL;其余正则元字符会被转义。glob 匹配失败时降级为大小写不敏感的contains子串匹配;
  • isRegex: true——Java 正则,带200ms 超时(ExtensionModule.kt),超时视为“不匹配”,防止恶意或低效正则在每次页面加载时卡死 UI 线程;编译后的正则还经过一个容量 64 的有界 LRU 缓存;
  • exclude: true——命中即从结果集中剔除(排除规则优先于包含规则)。

匹配语义:若同时存在 include 与 exclude 规则,先排除后包含;若只有 exclude 规则且未命中,则默认放行。

四、可以挂载哪几类扩展

「Selected modules」的可选范围来自Extension Modules 管理页(入口:主界面→ Extension Modules,见 管理文档)。四类来源会被归一化进同一个内部模型ExtensionModule(见 扩展作者指南):

类型形态典型用途
JS Modulemodule.json清单 +main.js(可选 CSS)带配置 UI 和悬浮面板的自定义功能,能力最强
CSS Module纯样式覆盖(仍需一个main.js桩文件)主题、重排版、深色模式
UserscriptTampermonkey/Greasemonkey 风格.user.js移植现有用户脚本,暴露GM_*API
Chrome MV3Manifest V3 Chrome 扩展移植浏览器扩展,暴露chrome.*API

归一化的关键证据在数据类ExtensionModule(ExtensionModule.kt):它同时包含sourceTypeCUSTOM / USERSCRIPT / CHROME_EXTENSION / GREASYFORK)、manifestJsongmGrantsbackgroundScriptpopupPathworldISOLATED/MAIN)等字段,说明四类扩展共用同一套配置、分享与注入通道。

管理页提供的核心能力(对应 管理文档):

  • List & toggle——按应用开关已安装扩展(对应extensionModuleIds的选择操作);
  • Editor——创建/编辑模块:清单、JS、CSS、配置项与交互面板,语法见 JS Modules;
  • Market——浏览社区模块市场,发布方式见 Publish to the Market;
  • Browser extensions——在线搜索 Chrome Web Store 并安装 MV3 扩展,见 Chrome MV3;
  • AI developer——跳转到 Agent 用 AI 生成扩展。

五、模块清单module.json深度解读

勾选模块前,读懂它的清单有助于判断该模块是否适合你的应用。以仓库内置模块为例,reading-mode 模块清单 完整展示了常见字段:

{ "id": "wta-reading-mode", "name": "Reading Mode", "icon": "menu_book", "category": "READING", "runAt": "DOCUMENT_END", "urlMatches": [ { "pattern": "*", "isRegex": false, "exclude": false } ], "permissions": ["DOM_ACCESS", "CSS_INJECT", "STORAGE"], "configItems": [ { "key": "theme", "name": "Theme", "type": "SELECT", "defaultValue": "light", "options": ["light", "sepia", "dark"] }, { "key": "fontSize", "name": "Font size (px)", "type": "NUMBER", "defaultValue": "18" } ] }

关键字段在 ExtensionModule.kt 中有严格的数据类型约束:

  • category——23 个枚举值之一(CONTENT_FILTERCONTENT_ENHANCESTYLE_MODIFIERTHEMEFUNCTION_ENHANCEAUTOMATIONNAVIGATIONDATA_EXTRACTDATA_SAVEINTERACTIONACCESSIBILITYMEDIAVIDEOIMAGEAUDIOSECURITYANTI_TRACKINGSOCIALSHOPPINGREADINGTRANSLATEDEVELOPEROTHER),每个类别带 Material 图标与多语言名称/描述(ExtensionModule.kt);
  • permissions——31 种权限枚举(如DOM_ACCESSCSS_INJECTSTORAGECOOKIELOCATIONEVAL等),其中dangerous = true的权限(如COOKIENETWORKCAMERAMICROPHONELOCATIONEVALIFRAME)在审核时会额外审查。注意:权限目前是展示性的,运行时并不据此做沙箱隔离
  • configItems——22 种配置控件类型(TEXTTEXTAREANUMBERBOOLEANSELECTMULTI_SELECTRADIOCHECKBOXCOLORURLEMAILPASSWORDREGEXCSS_SELECTORJAVASCRIPTJSONRANGEDATETIMEDATETIMEFILEIMAGE),最终以configValues: Map<String, String>的形式在运行时通过getConfig(key, defaultValue)暴露给脚本(ExtensionModule.kt)。

另一个简洁示例是 hello-world 模块清单:它演示了最小可行的模块结构——greeting(TEXT)与durationMs(NUMBER)两个配置项、DOCUMENT_END运行时机、*全量 URL 匹配。

main.js的编写契约(详见 JS Modules):代码被包裹在带try/catch的 IIFE 中(报错进console.error且不破坏页面),可直接访问__MODULE_INFO____MODULE_CONFIG____MODULE_UI_CONFIG____MODULE_PANEL_HTML__getConfig(key, defaultValue)等全局;因为外层是 IIFE,顶层不能出现return语句

六、FAB 图标与悬浮面板

extensionFabIcon控制扩展面板悬浮按钮的图标。当模块带有panelHtml或调用window.__WTA_MODULE_UI__.register({...})注册时(ExtensionModule.kt 的自动注册逻辑),WebView 内会显示一个悬浮按钮,点击展开该模块的交互面板。uiConfig(ExtensionModule.kt)支持:

配置项默认值说明
typeFLOATING_BUTTONUI 形态,目前仅悬浮按钮
autoHidefalse是否自动隐藏
autoHideDelay3000(毫秒)自动隐藏延迟
initiallyHiddenfalse初始是否隐藏
showOnlyOnMatchtrue是否仅在 URL 匹配时显示

面板 HTML 内通过data-wta-action属性绑定window.__wta_module_action_<name>处理器,并可使用var(--wta-*)主题变量匹配应用主题(见 JS Modules)。

七、扩展的分享、导入与持久化

配置卡片面向“已安装模块”的选择,而模块本身的流转依赖以下机制(见 ExtensionManager.kt):

  • 存储布局:用户模块保存在应用私有目录extension_modules/modules.json;代码与 CSS 以侧车文件形式分离存储(code_<id>.jscss_<id>.csscodefiles_<id>/),modules.json只保留元数据;内置模块的启用状态单独存于builtin_states.json。若modules.json解析失败,管理器会自动把损坏文件备份为modules_backup_<时间戳>.json后再恢复(ExtensionManager.kt);
  • 文件交换:单个模块导出为.wtamod,多模块打包为.wtapkg;导入时会重新生成id并强制builtIn = false
  • 二维码分享码WTA1:(完整 gzip + Base64)与WTA2:(仅携带与默认值的差异字段 + 最高压缩,兼容旧版解码器),单二维码物理上限为 2953 字节(ExtensionModule.kt),超过上限自动切换为 V2 编码。

八、使用中的三个重要注意点

扩展作者指南 明确指出了与浏览器扩展平台的三个行为差异,配置与排错时务必记住:

  1. 用户脚本的GM_*函数不受@grant门控——全部无条件暴露;
  2. Chrome 的ISOLATED/MAIN世界并非真正隔离——Android WebView 只有一个 JS 上下文,隔离是模拟的;
  3. GM_notification仅记录日志;MV3 的“后台 service worker”实际是一个隐藏 WebView,而非真正的 service worker。

九、完整的配置工作流

结合以上全部机制,推荐的最小可用流程如下:

  1. Extension Modules 管理页(主界面→ Extension Modules)安装或创建所需模块(内置模块无需安装);
  2. 打开目标应用的Edit Common ConfigExtension modules卡片;
  3. 打开Enable开关(写入extensionEnabled = true);
  4. Selected modules中勾选需要的模块(写入extensionModuleIds);
  5. 按需修改FAB icon(写入extensionFabIcon);
  6. 保存后重新导出/打包 APK,运行时WebViewManager会按各模块的runAturlMatches在对应页面注入代码。

若某个模块在页面中不生效,优先检查:该模块是否在卡片中被勾选、是否enabled、其urlMatches是否覆盖当前页面、runAt是否与预期时机一致,以及是否属于需要走独立注入通道的用户脚本/Chrome 扩展类型。

十、延伸阅读

  • 编辑器全量能力卡列表:编辑通用配置总览
  • 扩展模块管理页:Extension Modules(管理)
  • 四类扩展总览与注入模型:Extension Authoring
  • JS 模块清单与main.js契约:JS Modules
  • 用户脚本GM_*API 参考:Userscripts
  • 源码级实现:ExtensionModule.kt(数据模型/URL 匹配/分享码)、ExtensionManager.kt(管理/注入)、ApkConfig.kt(打包配置块)
  • 可参考的完整示例清单:modules 目录、模块注册表

【免费下载链接】web-to-appThe most full featured web-to-app toolkit on Android, a complete APK workshop that runs entirely on your phone项目地址: https://gitcode.com/GitHub_Trending/web/web-to-app

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 4:15:20

Redwood芯片设计AI:约束驱动的RTL到版图端到端生成原理与工程边界

1. 这不是又一篇“AI取代工程师”的 hype 文章&#xff0c;而是一份 Redwood 论文的手术刀式解剖Redwood 这个名字最近在芯片设计圈里反复出现&#xff0c;但多数人看到的只是“AI 自动生成 RTL”“24 小时流片”这类标题党短语。我从 2018 年起就在 EDA 工具链上做验证平台搭建…

作者头像 李华
网站建设 2026/9/17 4:15:03

Office 2016零售版转VOL版:从Retail到KMS批量激活完整指南

搞企业办公终端运维的朋友&#xff0c;多少都遇到过 Office 授权这块的糟心事。手里明明是一套官方零售版 Office 2016&#xff0c;结果公司突然通知&#xff1a;所有办公软件必须统一走 KMS 激活&#xff0c;IT 资产盘点也只认批量授权版本。零售版想直接接入企业的 KMS 通道是…

作者头像 李华
网站建设 2026/9/17 4:14:37

修改 ESXi 控制台 HTTP/HTTPS 端口:hostd、nginx 与防火墙全解析

修改 ESXi 主机控制台 HTTP/HTTPS 端口&#xff1a;完整实操与避坑记录做运维这些年&#xff0c;总有那么几个“看似简单、一碰就翻车”的需求&#xff0c;改 ESXi 主机的控制台端口绝对是其中之一。默认情况下&#xff0c;你安装完 ESXi&#xff0c;打开浏览器输入 IP 就能进 …

作者头像 李华
网站建设 2026/9/17 4:11:50

28nm FD-SOI FPGA:低功耗与高性能协同设计实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 4:11:20

老MacBook升级新系统全攻略:OpenCore Legacy Patcher实战指南

手头这台MacBook Pro 13英寸&#xff08;2012年款&#xff09;已经用了快十年&#xff0c;日常写稿、跑脚本、处理Raw照片都还能扛。但App Store里越来越多的软件开始要求macOS 11或更高版本&#xff0c;连浏览器插件都在提醒我“系统太旧”&#xff0c;没法继续留着Catalina原…

作者头像 李华