跳至内容
WebViewGold 从 Vibe Coding 到 App Store
中文
获取 WebViewGold

Claude Code

一个教会 Claude Code 使用 WebViewGold JavaScript 桥接的 Agent Skill

Agent Skill 是一个包含 SKILL.md 文件的文件夹,Claude Code 只在任务需要时才加载它。这正适合存放 WebViewGold 桥接:精确的 URL scheme、注入的变量和平台差异,代理一碰到原生功能就至关重要,其余时候则完全用不上。下面是一个完整的技能,已对照 WebViewGold 文档核实,可以直接放进 .claude/skills/。

每个平台一次性 $109 起,或由我们的团队全程代劳,$698 起。

  • 审核通过保证 – 否则 14 天内退款
  • 无需编程
  • 一次性付费,免费更新
  • 7×24 小时人工支持
  • 2014 年起德国出品 · ISO 27001

为什么用技能,而不是更长的 CLAUDE.md

CLAUDE.md 在每次会话开始时都会被读取,所以其中的每一行在每个任务中都要占用上下文,包括大量与原生功能毫无关系的任务。技能的工作方式正好相反。Claude Code 只把每个技能的简短描述放在视野里;当您输入 /webviewgold-bridge,或者 Claude 发现某个请求与描述相符时,完整的 SKILL.md 才会加载。技能文件夹中的支持文件,只有在指令指向它们时才会加载。

对 JavaScript 桥接来说,这再理想不过。scheme 表、回调签名和 iOS 上的变通做法,都是代理必须原样照抄的精确参考资料,而在它修复 CSS bug 时又毫不相关。您的 CLAUDE.md 只保留一行(“原生功能:参见 webviewgold-bridge 技能”),细节则集中在一个有人维护的地方。

技能也不是 MCP 服务器。MCP 把 Claude 连接到一个在线系统,例如 GitHub、数据库或浏览器。桥接不需要在线连接,它需要的是正确的知识和一个辅助文件,而这正是技能所打包的内容。

文件夹结构

三个文件。只有 SKILL.md 是必需的;另外两个让它保持简短。

text
.claude/skills/webviewgold-bridge/
├── SKILL.md            rules, scheme table, patterns (loads with the skill)
├── platform-notes.md   iOS vs Android differences and native switches (loads on demand)
└── templates/
    └── native.ts       helper module Claude copies into src/lib/

SKILL.md

description 是最重要的一行:它决定 Claude 何时加载这个技能,所以它列出了各项功能,以及人们实际会输入的词语。表中的每个 scheme 都出现在 WebViewGold 文档中,例如推送、生物识别和分享面板页面。

markdown
---
name: webviewgold-bridge
description: Adds or debugs native iOS and Android features in this web app through the WebViewGold JavaScript bridge (URL schemes such as registerpush://, bioauth://, qrcode://, shareapp://, getonesignalplayerid://, rateapp://). Use when a task involves push notifications, Face ID, Touch ID or fingerprint login, QR or barcode scanning, the share sheet, haptics or vibration, saving images, app rating, the app version, opening app settings, or any behavior that must differ inside the native app.
---

# WebViewGold JavaScript bridge

This web app also ships as native iOS and Android apps built with WebViewGold. The apps load
the production URL in a WKWebView (iOS) or an Android WebView. Native features are triggered
by navigating to a URL scheme. Results come back as injected global variables or as calls to
global functions. There is no SDK to install and nothing to bundle.

## Rules
1. Detect the app with isNativeApp() from src/lib/native.ts. If that file does not exist,
   copy templates/native.ts from this skill. Never write a second user agent check.
2. Trigger schemes only through callNative(), callNativeQuietly() or callAndRead(). Every
   call needs a browser fallback: the web equivalent, or hide the control. No dead buttons.
3. Use only the schemes in the table below. For anything else, read the feature page under
   https://www.webviewgold.com/docs/iOS/ or https://www.webviewgold.com/docs/android/
   (full text: https://www.webviewgold.com/llms-full.txt). If it is not documented, tell
   the user it is not supported. Never invent a scheme, parameter or variable name.
4. iOS processes only one location change per script run. For several data calls at once
   use multiapicall://getonesignalplayerid,getappversion (comma-separated, no spaces; it
   works on Android too). Fire haptics on iOS through callNativeQuietly().
5. Injected variables arrive asynchronously. Read them with readInjected() or callAndRead(),
   never synchronously right after the call.
6. A scheme for a feature that is switched off in the native project does nothing. When you
   add a feature, list the native settings the user must enable (see platform-notes.md).
   Never edit signing, certificates, provisioning profiles or keystore settings.
7. Biometric success is a UI gate only. Sensitive actions still need a server-side check.

## Scheme reference
| Feature | Call | Result |
|---|---|---|
| Push permission prompt | registerpush:// | System permission dialog |
| Push permission status | checkNativePushPermissions:// | window.nativePushEnabled (true or false) |
| App settings | settingsapp:// | Opens the system settings of the app |
| OneSignal subscription ID | getonesignalplayerid:// | window.onesignalplayerid |
| Firebase push ID | getfirebaseplayerid:// | window.firebaseplayerid |
| Local notification | sendlocalpushmsg://push.send?s=SECONDS=msg!MESSAGE&!#TITLE&!#URL | Shown after SECONDS |
| Cancel local notifications | sendlocalpushmsg://push.send.cancel | Removes all scheduled ones |
| Biometrics | bioauth:// | iOS calls onBioAuthSuccess(), onBioAuthFailure(errorCode, errorMessage) or onBioAuthUnavailable() |
| QR code | qrcode:// | The scanned URL opens in the app |
| Barcode | barcodescanner:// | window.barcodescanresult |
| Share sheet | shareapp://message?=TEXT&url=URL | Native share dialog |
| Haptics | lighthaptic:// heavyhaptic:// successhaptic:// warninghaptic:// errorhaptic:// | Vibration; mediumhaptic:// is iOS only |
| Save image | savethisimage://?url=IMAGE_URL | Saved to the photo library |
| Rating | rateapp:// | System review dialog; the system decides whether it appears |
| App version | getappversion:// | window.versionNumber and window.bundleNumber |

## Patterns
- Push: ask after onboarding or a first success, never on the first screen. Explain in one
  sentence what we will send, then call registerpush://. In settings, use pushEnabled() and
  offer settingsapp:// when push is off. Save onesignalplayerid on the user profile via our API.
- Share: always encodeURIComponent TEXT and URL; share() in native.ts does it.
- QR codes: encode URLs on our own domain, because the scanned URL loads inside the app.
- Rating: only after a positive moment (order completed, task finished). Never at launch and
  never in exchange for a reward.
- Version: hide UI that older app builds cannot support by checking appVersion().

## Before you finish
- Every native call sits behind isNativeApp() and has a browser fallback.
- Your summary lists each scheme you used, the native switches to enable (platform-notes.md)
  and any platform-specific limits.
- Remind the user to test inside the real app on a device: push and biometrics cannot be
  tested in a desktop browser.

在过去5年我们尝试过的所有应用平台中,WebViewGold为我们带来了有史以来最短、最高效的上市时间。我不知道为什么没有更早发现你们,但我真的非常满意。目前我们的应用在iOS App Store和Google Play商店的下载量已超过6000次,没有任何问题!

安东尼奥·达维拉 · CodeCanyon

platform-notes.md

每项功能需要在原生项目中开启什么,以及 iOS 和 Android 有哪些差异。当 Claude 告诉您需要启用哪些设置时,它会读取这个文件。生物识别部分反映的是文档目前的状态:iOS 页面记录了三个回调,Android 页面只记录了验证提示。

markdown
# Platform notes for the WebViewGold bridge

## User agent token
- iOS: Config.swift, useragent_iphone and useragent_ipad
- Android: Config.java, USER_AGENT
- Value: a normal mobile user agent string, a space, then WebViewGoldApp

## Push (OneSignal)
- iOS: kPushEnabled and oneSignalID in Config.swift. Set askforpushpermissionatfirstrun to
  false when the web app asks later with registerpush://. The App ID needs the Push
  Notifications and App Groups capabilities.
- Android: PUSH_ENABLED in Config.java, ONE_SIGNAL_APP_ID in app/build.gradle.
- Firebase instead of OneSignal: getfirebaseplayerid:// and window.firebaseplayerid.

## Variables without a call
- iOS autoInjectVariable, Android AUTO_INJECT_VARIABLES: values such as the push ID and the
  app version are injected automatically. readInjected() works either way.

## Biometrics
- iOS: add "Privacy - Face ID Usage Description" to Info.plist. Callbacks:
  onBioAuthSuccess(), onBioAuthFailure(errorCode, errorMessage), onBioAuthUnavailable().
- Android: the system BiometricPrompt, which may fall back to PIN or pattern. The Android
  docs describe the prompt but not the three callbacks: test on a device before relying on
  them, and keep a fallback.
- enableBioMetricAuth (both platforms) is a separate app lock on every launch and is
  independent of bioauth://.

## Camera features (qrcode://, barcodescanner://)
- iOS: camera usage description in Info.plist; qrcodelinks in Config.swift decides where
  scanned URLs open.
- Android: requireCamera and QR_CODE_URL_OPTIONS in Config.java.

## Haptics
- mediumhaptic:// exists on iOS only. Use lighthaptic:// or heavyhaptic:// on Android.

## Downloads
- savethisimage://?url=... saves an image. Other files download natively by extension:
  extentionARY (Config.swift) and downloadableExtension (Config.java).

## Rating
- rateapp:// shows the system review dialog, which the system rate-limits.
  iOS alternative: showcustomrateappdialog and ratemyappurl in Config.swift.

## Documentation
- iOS: https://www.webviewgold.com/docs/iOS/
- Android: https://www.webviewgold.com/docs/android/
- Full text for agents: https://www.webviewgold.com/llms-full.txt

templates/native.ts

技能要求 Claude 复制的辅助文件。它是唯一知道 User-Agent 标记的地方,并处理了代理通常会忽略的三个细节:来自iOS 触觉反馈文档的静默 iframe 调用方式、iOS 上每次脚本运行只处理一次地址变更(参见 MultiAPICall),以及在读取新值之前先清除过期的变量。

typescript
// templates/native.ts
// Copied into src/lib/native.ts by the webviewgold-bridge skill.
// The only file that knows how the web app detects the WebViewGold apps.

// Set in Config.swift (useragent_iphone, useragent_ipad) and Config.java (USER_AGENT)
const TOKEN = "WebViewGoldApp";

export function isNativeApp(): boolean {
  return typeof navigator !== "undefined" && navigator.userAgent.includes(TOKEN);
}

export function isAndroidApp(): boolean {
  return isNativeApp() && /Android/i.test(navigator.userAgent);
}

export function isIOSApp(): boolean {
  return isNativeApp() && !isAndroidApp();
}

// Navigate to a scheme. Returns false in normal browsers so callers can fall back.
export function callNative(scheme: string): boolean {
  if (!isNativeApp()) return false;
  window.location.href = scheme;
  return true;
}

// Fire-and-forget call through a temporary iframe, so it does not cancel a
// navigation in progress (the technique from the WebViewGold iOS haptics docs).
export function callNativeQuietly(scheme: string): boolean {
  if (!isNativeApp()) return false;
  const frame = document.createElement("iframe");
  frame.style.display = "none";
  frame.src = scheme;
  document.body.appendChild(frame);
  frame.remove();
  return true;
}

// Poll for a global variable the app injects (onesignalplayerid, nativePushEnabled ...)
export function readInjected<T = unknown>(name: string, timeoutMs = 3000): Promise<T> {
  return new Promise((resolve, reject) => {
    const started = Date.now();
    const tick = () => {
      const value = (window as any)[name];
      if (value !== undefined) return resolve(value as T);
      if (Date.now() - started > timeoutMs) return reject(new Error(name + " was not injected"));
      setTimeout(tick, 100);
    };
    tick();
  });
}

// Call a scheme and read a fresh result; clears a stale value first.
export async function callAndRead<T = unknown>(scheme: string, name: string, timeoutMs = 3000): Promise<T | null> {
  if (!isNativeApp()) return null;
  try { delete (window as any)[name]; } catch { /* variable not deletable, keep polling */ }
  window.location.href = scheme;
  return readInjected<T>(name, timeoutMs).catch(() => null);
}

export type Haptic = "light" | "heavy" | "success" | "warning" | "error";

export function haptic(kind: Haptic): void {
  const scheme = kind + "haptic://";
  if (isIOSApp()) callNativeQuietly(scheme);
  else callNative(scheme);
}

export function share(text: string, url: string): boolean {
  return callNative("shareapp://message?=" + encodeURIComponent(text) + "&url=" + encodeURIComponent(url));
}

export function pushEnabled(): Promise<boolean | null> {
  return callAndRead<boolean>("checkNativePushPermissions://", "nativePushEnabled", 2000);
}

export function appVersion(): Promise<string | null> {
  return callAndRead<string>("getappversion://", "versionNumber", 2000);
}

安装并测试技能

在终端、IDE 扩展和云端会话中的用法完全相同。

  1. 创建文件夹

    在仓库根目录创建 .claude/skills/webviewgold-bridge/,放入上面的三个文件并 commit。如果希望在您所有的项目中都能使用这个技能,请改用 ~/.claude/skills/webviewgold-bridge/。

  2. 按您的应用精简

    删除那些您没有在原生项目中开启的功能所对应的表格行。已禁用功能的 scheme 在运行时什么也不做,而在表中看到它的代理会兴高采烈地把它接进去。

  3. 确认 Claude 能看到它

    在 Claude Code 中输入 /,查找 webviewgold-bridge,或者问一句“这个项目里可以用哪些技能?”。如果找不到,请确认 frontmatter 从 SKILL.md 的第一行开始。

  4. 让它自行触发

    不点名技能,直接请求一项功能:“在食谱页面上添加一个分享按钮。”Claude 应该加载这个技能,通过 share() 使用 shareapp://,并保留“复制链接”按钮作为浏览器中的备用方案。

  5. 需要时显式运行

    /webviewgold-bridge 结账后添加成功触觉反馈 会加载技能,并把这一行的其余部分作为任务传入。

  6. 审阅、部署、真机测试

    检查每个调用是否都有 isNativeApp() 守卫,并阅读 Claude 报告的原生开关列表。然后部署,在真实应用中测试;推送和 Face ID 在桌面浏览器中无法使用。

让 Claude Code 按您的应用定制技能

如果您希望技能只包含您实际启用的功能,就用这段提示词,而不是手动复制文件。

在项目根目录中粘贴到 Claude Code
为这个仓库在 .claude/skills/webviewgold-bridge/ 创建一个 Agent Skill。我们的 Web 应用也运行在用 WebViewGold 构建的原生 iOS 和 Android 应用中;原生功能通过 URL scheme 触发,并通过注入的 JavaScript 变量或全局回调函数返回结果。

1. 读取 Config.swift 和 Config.java(位于 native/ios 和 native/android,如有不同请调整),列出实际开启了哪些原生功能。
2. 针对每项已启用的功能,打开 https://www.webviewgold.com/docs/iOS/ 和 https://www.webviewgold.com/docs/android/ 下对应的文档页面,原样复制 scheme、参数和返回变量。文档里找不到的内容一律不写,并单独列出来给我。
3. 编写 SKILL.md,包括 frontmatter(name: webviewgold-bridge,以及一个列出各项功能和用户会输入的词语的 description)、简短的规则(isNativeApp 守卫、浏览器备用方案、iOS 上多个数据调用使用 multiapicall、注入变量是异步的、不编造 scheme)、一张 scheme 表,以及完成任务时的检查清单。
4. 把 iOS 与 Android 的差异,以及所需的 Config.swift、Config.java、Info.plist 和 AndroidManifest.xml 设置写进 platform-notes.md。
5. 把辅助模块放进 templates/native.ts,包含 isNativeApp、callNative、callNativeQuietly(iframe)、readInjected 和 callAndRead。

SKILL.md 控制在 150 行以内,保存前把每个文件都给我看。

技能、CLAUDE.md、子代理、命令、hook 还是 MCP?

机制何时加载在 WebViewGold 项目中的用途
CLAUDE.md每次会话简短的常驻规则:应用运行在 WebView 中、商店规则、受保护的路由
技能(SKILL.md)任务匹配时,或通过 /name参考知识和模板,比如这个桥接技能
子代理Claude 委派任务时需要独立上下文和严格角色的工作,比如商店审查检查器
命令您输入它时您有意启动的流程,比如 /release-check
Hook每次到达对应的生命周期事件时即使模型不同意也必须成立的规则,比如 Config 文件中不得出现 localhost URL
MCP 服务器调用其工具时在线系统:GitHub、您的数据库、用于截图的浏览器

常见陷阱

  • 描述含糊。“WebViewGold helper”永远不会被触发。写出人们常用的功能名称和动词:推送、Face ID、扫描、分享、振动、给应用评分。
  • 两个事实来源。如果 scheme 表在 CLAUDE.md 中也有一份,其中一份迟早会过时。把表格放在技能里,让 CLAUDE.md 指向它。
  • 技能膨胀成手册。让 SKILL.md 保持简短,把细节移到支持文件中。Claude 会在需要时阅读指令所指向的内容。
  • 跳过真机测试。技能能让代码正确;只有真实应用才能证明这项功能已经开启、已获授权并且能正常工作。
  • WebViewGold 更新后内容过时。升级到新的 WebViewGold 版本时,让 Claude 对照文档和新的 Config 文件重新核对这张表。
  • 安装没读过的技能。技能可以附带 Claude 可能会运行的脚本。添加第三方技能之前先读一遍,就像对待依赖项一样。

常见问题

技能在 Claude Code 网页版和 GitHub Actions 中能用吗?

能。.claude/skills/ 中的项目技能是仓库的一部分,所以云端会话会加载它们;只要工作流先检出仓库,并把 /skill-name 作为提示词传入,Claude Code GitHub Action 也能运行技能。

Claude 会自动加载这个技能吗?

请求与描述相符时,会。您也可以用 /webviewgold-bridge 自己运行它。如果只想手动使用,就在 frontmatter 中加上 disable-model-invocation: true。

这和 JavaScript 桥接指南有什么不同?

指南是向您讲解桥接,并提供一段一次性集成的提示词。技能则是给代理的永久版本:几个月后,当您早已忘记细节时,只要后续任务碰到原生功能,它就会自动加载。

Cursor 或 Codex 能使用同一个 SKILL.md 吗?

SKILL.md 遵循开放的 Agent Skills 格式,其他几个代理也能读取它,但每个工具都在自己的文件夹中查找。请查阅该工具的文档,或者使用本栏目中的 Cursor 规则模板或 AGENTS.md 模板。

为什么某个 scheme 在 Android 上可用,在 iOS 上却不行?

通常是因为同一段脚本中执行了多次 window.location.href 赋值。iOS 只处理其中一次;请像辅助文件那样,用 multiapicall:// 合并数据调用,并通过临时 iframe 触发触觉反馈。

让您的应用上架商店的三种方式

结果相同,只是您需要投入的工作量不同。三种方式都附带审核通过保证和 7×24 小时人工支持。

自己动手

$109 每个平台,一次性付费

WebViewGold 许可证:一个现成的 Xcode 或 Android Studio 项目。粘贴您的 URL,设置名称和图标,开启所需功能,构建并提交。永久免费更新。

在主页查看方案

Cloud Builder

$349 每个许可证,一次性附加购买

无需 Mac、Xcode 或 Android Studio:在浏览器中完成配置,我们在云端构建两个应用,并将其交付到 App Store Connect 和 Play Console。

Cloud Builder 如何运作 试用免费演示

Full Service

$698 每个平台 $798

把您的 URL 和图标发给我们。我们的团队在 72 小时内完成配置、构建并交付您的应用,白标,附源码项目。两个平台共 $1,158。

Full Service 详情 服务提供方: WeSetupYourWebViewApp

冬季特惠价格有效期至 2026年12月31日。

准备好发布您的应用了吗?

App Store & Google Play 审核通过保证 – 否则 14 天内退款

想直接交给我们?Full Service:我们在 72 小时内完成配置、构建并交付,每个平台 $698 起。有疑问?通过 7×24 小时在线聊天联系我们。

退款依据我们 FAQ 中列出的条件:应用因非内容原因被 Apple 和/或 Google 拒审,并在购买后 14 天内提出申请。