Files
wehub-resource-sync f4ed7901c3
Module Market Check / Validate modules/ (push) Failing after 1s
Android CI Build / check (push) Failing after 1s
Module Market Publish / Generate submissions.json (push) Failing after 1s
Android CI Build / package-apks (push) Has been skipped
chore: import upstream snapshot with attribution
2026-07-13 12:29:44 +08:00

16 KiB
Raw Permalink Blame History

Contributing to WebToApp

Thanks for taking the time to help. WebToApp moves fastest when contributions stay small and well-scoped — pick one of the lanes below and ignore the rest.

English · 简体中文

This guide targets WebToApp 2.1.8 (versionCode 47).


Lanes

You want to… Go to Effort
Publish a JS/CSS module to the in-app Module Market modules/README.md hours
File a bug, request a feature, or ask a question GitHub Issues minutes
Fix a bug or build a feature in the Android client This guide ↓ days

If you're not sure which lane fits, open an issue or a discussion first. There is no need to write code before there's agreement on the shape of the change.


Module Market submissions

The fastest way to ship something useful to every WebToApp user is to publish a module. The canonical Module Market guide lives in modules/README.md. Use that file for the full schema, field rules, reviewer checklist, and CI validation details. The short version here is only meant to help you pick the right contribution lane:

  1. Fork the repo.
  2. Add modules/<your-module>/module.json and main.js (plus style.css if you need CSS).
  3. Add an entry to modules/registry.json.
  4. Open a PR.

The market has no backend. Clients read registry.json and submissions.json, and only merged modules show up in the catalog. Module changes are validated in CI by .github/scripts/ci/validate_modules.py:

python3 .github/scripts/ci/validate_modules.py

Code contributions

Before you write code

  • Search issues for prior discussion of the same idea.
  • For non-trivial changes, open an issue first describing the problem and the approach you have in mind. This is much cheaper than rewriting after review.
  • Avoid adding new dependencies. The list in app/build.gradle.kts is intentionally restrained — the project signs and packages APKs in-process, and the host pins targetSdk = 28 on purpose because generated apps rely on fork+exec native runtimes. New dependencies need a strong justification.

Local setup

You'll need:

  • Android Studio Hedgehog or newer
  • JDK 17
  • The Gradle wrapper pins Gradle 9.4.1 — no system Gradle install required
git clone https://github.com/shiaho777/web-to-app.git
cd web-to-app
./gradlew assembleDebug

The repo has three Gradle modules: app (the full builder and host), shell (the runtime-only host embedded in generated APKs), and clone-host (the host code used by app cloning). Shared runtime code is authored in app and synchronized into shell, so changes there usually need both :app and :shell to compile.

Run the checks before submitting:

./gradlew :app:compileDebugKotlin
./gradlew :shell:compileDebugKotlin
./gradlew :app:testDebugUnitTest

Native code (node_launcher, go_exec_loader, the APK optimizer) builds via CMake per-ABI and needs the Android NDK + CMake installed through the SDK Manager. CI installs cmake;3.22.1 and ndk;28.2.13676358.

Where things live

Area Path
App types & central config (AppType, WebApp) app/src/main/java/com/webtoapp/data/model/
On-device APK builder / signer app/src/main/java/com/webtoapp/core/apkbuilder/
Server runtimes (Node / PHP / Python / Go / WordPress) app/src/main/java/com/webtoapp/core/{nodejs,php,python,golang,wordpress}/
WebView engine, native bridge, fingerprint disguise app/src/main/java/com/webtoapp/core/{webview,engine,appearance}/
Extension modules, Module Market, AI Coding app/src/main/java/com/webtoapp/core/{extension,market,aicoding}/
Compose UI screens & design system app/src/main/java/com/webtoapp/ui/
DI graph (source of truth) app/src/main/java/com/webtoapp/di/AppModule.kt

Coding conventions

WebToApp leans on the Kotlin and Jetpack Compose patterns already in the codebase. A few rules worth calling out:

  • This codebase ships without comments. Source files are kept comment-free by convention — let clear names and small functions carry the intent. Don't add //, /* */, or KDoc blocks; if a block needs a comment to be understood, prefer rewriting it. (Strings inside code, e.g. URLs, are obviously fine.)
  • Build new UI on the Wta design system. Everything renders through com.webtoapp.ui.design. The older Premium* / Enhanced* / Settings* components are retained as permanent alias layers over the Wta internals — don't add new ones, and you don't need to rip them out. A build-time audit (.github/scripts/audit_ui_design_system.py, wired into build.gradle.kts) tracks legacy UI debt against .github/scripts/ui_design_allowlist.txt.
  • Reuse the design tokens in ui/design/WtaTokens.kt for spacing, radius, alpha, and elevation. Don't hard-code numbers.
  • Strings must cover all 10 supported languages. UI copy lives in core/i18n/Strings.kt (facade object Strings + in-file StringsAStringsE, split only for the JVM constant pool). Supported: Chinese, English, Arabic, Portuguese, Spanish, French, German, Russian, Japanese, Korean. Every new or changed user-facing when (Strings.lang) block must have real translations for all 10 branches — do not leave pt/es/fr/de/ru/ja/ko as English placeholders. Brand names and pure format tokens may match English. If you truly cannot translate one language, use English there and flag it in the PR. StringsKtTranslationParityTest currently enforces the core three and forbids hardcoded else -> "..."; full 10-way coverage is still required by project convention.
  • No new top-level singletons unless you discuss it first. The DI graph in di/AppModule.kt is the source of truth.
  • The Native Bridge is capability-gated. Any method exposed to web content via @JavascriptInterface must be guarded by the per-capability allow-list (NativeBridgeCapabilities). Never expose a native capability to arbitrary pages without a gate. PRs that bypass this will be rejected.
  • Preview and packaged runtime are two paths. Bridges and WebView hooks must be registered (and injected, when applicable) both for in-app preview (WebViewManager / WebViewActivity) and for generated APKs (ShellActivity). Shared runtime sources are authored only under app/ and synced into shell/ via ./gradlew :shell:syncShellRuntimeSources --rerun-tasks — do not hand-edit generated shell/ trees.
  • Avoid catching Exception to silence errors. If recovery is impossible, log via AppLogger and re-throw or return a failed Result.

Security

Anything touching the WebView, file IO, APK signing, or the native bridge has downstream impact on every generated app, so it gets extra scrutiny. Specifically, PRs will be declined if they:

  • store or expose credentials/secrets to web content,
  • widen the native surface exposed to arbitrary pages without a capability gate,
  • weaken APK signing, isolation, or the fingerprint-disguise defaults,
  • bundle unrelated changes inside a large diff.

Commit messages

We don't enforce Conventional Commits, but a clear subject line and a wrapped body that explains why the change exists make reviews much faster. Example:

ModuleMarket: cache registry.json for an hour

Repeatedly hitting raw.githubusercontent.com on every screen open is wasteful
and triggers GitHub's anonymous rate limit on slow connections. Cache the
parsed registry under cache/module_market/ and treat anything fresher than
an hour as authoritative; the refresh button always bypasses the cache.

Pull requests

  • Branch from main. Keep PRs focused — one logical change per PR.
  • Describe the user-visible effect in the PR body, not just the code change.
  • If your PR touches the build system, native code, or APK packaging, attach the output of ./gradlew :app:assembleDebug (or note the failure if it fails on your machine).
  • CI runs on every PR. A green CI is required before merge.

Reviewer expectations

Maintainer reviews look for:

  • Correctness. Does the change do what the PR description says?
  • Safety. See Security above.
  • Scope discipline. Drive-by refactors expand the review surface. Land them in a separate PR.
  • Style fit. See Coding conventions above.

Code of conduct

Feedback is required to be precise. "This code is garbage" is acceptable only when accompanied by which code, why, and what would be less so. The maintainer (shiaho) has on file a standing waiver covering criticism of himself, his judgment, and his life choices. Praise unaccompanied by a working patch is logged and otherwise disregarded.


贡献 WebToApp(中文)

非常感谢你愿意花时间。WebToApp 的迭代速度取决于"小而聚焦"的贡献——下面三条路 里挑一条走,其他的先忽略。

本指南对应 WebToApp 2.1.8versionCode 47)。

你想做什么?

你想…… 路径 投入
给应用内的 模块市场 提交一个 JS/CSS 模块 modules/README.md 几小时
报 Bug、提 Feature、问问题 GitHub Issues 几分钟
修 Bug 或在 Android 客户端里做新功能 见下方代码贡献小节 几天

不确定走哪条,先开 issue 或 discussion——动手前对齐方向,比写完再返工便宜 得多。

模块市场贡献

让你的工作触达每一个用户最快的方式就是提一个模块。Schema、审核 Checklist 和 CI 校验细节的主文档是 modules/README.md。这里仅保 留一个极简入口,方便你先判断自己是不是走这条贡献路线:

  1. Fork 本仓库
  2. 新建 modules/<你的模块>/module.jsonmain.js(需要 CSS 时再加 style.css
  3. modules/registry.json 里加一行索引
  4. 提 PR

市场没有后端。客户端读取 registry.jsonsubmissions.json,只有已合 并的模块才会在市场出现。模块改动会经过 CI 的 .github/scripts/ci/validate_modules.py 校验,提 PR 前建议先本地跑:

python3 .github/scripts/ci/validate_modules.py

代码贡献

动手前

  • issues 里先搜一下 类似讨论
  • 较大的改动请先开 issue 说明要解决的问题和方案
  • 谨慎引入新依赖app/build.gradle.kts 的依赖列表刻意保持精简——本项目 全程在设备内签名打包 APK,并特意把 targetSdk 锁在 28,因为生成应用依赖 forkexec 原生运行时。新依赖需要充分理由。

本地环境

  • Android Studio Hedgehog 或更新版本
  • JDK 17
  • Gradle wrapper 已锁定 Gradle 9.4.1,无需系统安装 Gradle
git clone https://github.com/shiaho777/web-to-app.git
cd web-to-app
./gradlew assembleDebug

仓库有三个 Gradle 模块:app(完整构建器和宿主)、shell(嵌入生 成 APK 的运行时宿主)和 clone-host(应用克隆使用的宿主代码)。共享运 行时代码以 app 为唯一事实来源,再同步到 shell,所以改动这部分通常至少 要保证 :app:shell 都能编译。

提交前请跑通:

./gradlew :app:compileDebugKotlin
./gradlew :shell:compileDebugKotlin
./gradlew :app:testDebugUnitTest

原生代码(node_launchergo_exec_loader、APK 优化器)按 ABI 经 CMake 编译,需要通过 SDK Manager 安装 Android NDK + CMake。CI 安装的是 cmake;3.22.1ndk;28.2.13676358

代码大致位置

区域 路径
应用类型与核心配置(AppTypeWebApp app/src/main/java/com/webtoapp/data/model/
设备端 APK 打包 / 签名 app/src/main/java/com/webtoapp/core/apkbuilder/
服务端运行时(Node / PHP / Python / Go / WordPress app/src/main/java/com/webtoapp/core/{nodejs,php,python,golang,wordpress}/
WebView 引擎、原生桥、指纹伪装 app/src/main/java/com/webtoapp/core/{webview,engine,appearance}/
扩展模块、模块市场、AI 编程 app/src/main/java/com/webtoapp/core/{extension,market,aicoding}/
Compose UI 与设计系统 app/src/main/java/com/webtoapp/ui/
DI 依赖图(单一事实来源) app/src/main/java/com/webtoapp/di/AppModule.kt

代码风格

  • 本仓库不写注释。 源码按约定保持无注释——用清晰的命名和小函数表达意图。 不要加 ///* */ 或 KDoc;如果某段代码非得靠注释才能看懂,优先重写它。 (代码里字符串内的内容,比如 URL,当然不受此限。)
  • 新 UI 一律构建在 Wta 设计系统之上——所有界面通过 com.webtoapp.ui.design 渲染。旧的 Premium* / Enhanced* / Settings* 组件作为 Wta 内部实现的 永久别名层保留——不要再新增,也无需强行替换。构建期有一个审计脚本 (.github/scripts/audit_ui_design_system.py,接进 build.gradle.kts)按 .github/scripts/ui_design_allowlist.txt 跟踪历史 UI 债务。
  • 复用 ui/design/WtaTokens.kt 里的设计 token(间距、圆角、透明度、高度), 别硬编码数字
  • 字符串必须覆盖全部 10 种已支持语言:文案在 core/i18n/Strings.kt facade object Strings + 同文件 StringsAStringsE,拆分只为常量池)。 已支持:中 / 英 / 阿 / 葡 / 西 / 法 / 德 / 俄 / 日 / 韩。 新增或修改面向用户的 when (Strings.lang) 必须为 10 个分支写真实翻译, 禁止把 pt/es/fr/de/ru/ja/ko 继续当英文占位。品牌名、纯格式符可与英文相同。 某语实在不会翻可暂填英文并在 PR 标明。 StringsKtTranslationParityTest 目前强制三核心 + 禁止硬编码 else -> "..." 项目约定仍要求 10 语全覆盖
  • 引入新的全局单例前请先讨论;di/AppModule.kt 是单一事实来源
  • 原生桥是按能力门禁的:任何通过 @JavascriptInterface 暴露给网页的方法, 都必须经过逐能力白名单(NativeBridgeCapabilities)。绝不要在没有门禁的 情况下把原生能力暴露给任意页面。绕过门禁的 PR 会被拒
  • 预览和打包运行时是两条路径:桥接类 / WebView hook 要在预览 WebViewManager / WebViewActivity)和生成 APKShellActivity)两侧都 注册(需要 hook 网页 API 的还要注入脚本)。共享运行时代码只改 app/ 改完跑 ./gradlew :shell:syncShellRuntimeSources --rerun-tasks;不要手改 shell/ 下的同步产物
  • 不要 catch 然后吞掉异常;用 AppLogger 记录后重新抛出或返回失败的 Result

安全

动到 WebView、文件 IO、APK 签名或原生桥的改动会影响每一个生成出来的 应用,因此审核更严。出现以下情况的 PR 会被拒:

  • 把凭据 / 密钥存储或暴露给网页内容
  • 在没有能力门禁的情况下扩大暴露给任意页面的原生面
  • 削弱 APK 签名、隔离或指纹伪装的默认强度
  • 在一个大 diff 里夹带不相关的改动

Commit 消息

不强制 Conventional Commits,但请把"为什么"写进正文。示例见英文段。

Pull Request

  • main 分出分支,每个 PR 只解决一件事
  • PR 描述写"用户看得到的效果",不只是代码 diff
  • 改动涉及构建系统、原生代码或 APK 打包时,附上 ./gradlew :app:assembleDebug 的结果
  • CI 必须绿色才会合并

Review 标准

  • 正确性——是否真的做了 PR 描述里写的事
  • 安全——见上面《安全》小节
  • 聚焦——顺手做的重构请单独发 PR
  • 风格——参考上面那条

行为准则

反馈须精准。"这代码是坨屎"仅在同时说明"哪段代码、为何如此、怎样才不至于" 时方予受理。维护者(shiaho)已就针对其本人、其判断力及其人生选择的批评 出具长期豁免一份并存档。未附可用补丁的赞美,予以记录,余不受理。