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

Cursor + 应用更新

为您的 Cursor 应用实现版本检查和强制更新

您的 Cursor Web 应用每次发布都会更新,但包裹它的原生外壳只有在用户安装新的商店版本后才会改变。当新功能依赖更新的外壳,或旧构建版本指向您即将停用的 URL 时,您需要知道哪些用户落在了后面。WebViewGold 会把已安装的版本告诉您的 Web 应用;几行代码就能把它变成一条温和的提示横幅或一个强制更新页面。

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

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

旧版应用真正造成问题的时候

Web 部署会在下一次页面加载时覆盖所有已安装的版本。只有原生外壳的改动会让用户掉队,真正要紧的是以下三种情况:

某个 Web 功能需要更新的外壳

您在 1.3 版中启用了应用内购买、生物识别登录或新的推送服务。1.2 版的用户能看到按钮,但它背后的 URL scheme 在他们的构建版本中毫无作用。请为旧版本隐藏或替换该功能。

旧构建版本加载您即将停用的 URL

起始 URL 是编译进应用里的。从构建工具的子域名迁移到您自己的域名,或换到新的托管服务后,旧安装仍会访问旧地址。请让旧地址继续重定向,并用版本检查引导用户更新到新构建版本。

后端或登录的破坏性变更

您更换了认证服务商、OAuth 重定向域名或链接处理方式,而只有新构建版本才带有匹配的原生设置(登录助手、Universal Links、URL 列表)。与其让登录悄无声息地失败,不如显示一个更新页面,对用户更友好。

给 Cursor 的提示词

把这段粘贴到 Cursor 中以实现 Web 应用端。检查结果,发布,然后在 WebViewGold 应用中测试。

给 Cursor 代理的提示词
这个 Web 应用运行在 WebViewGold 原生外壳中。它的 User-Agent 包含 "WebViewGold-iOS" 或 "WebViewGold-Android";外壳会设置全局变量 versionNumber(应用版本)和 bundleNumber(构建号)。
1. 在 lib/native.ts 中添加 getNativeVersion(),在 3 秒内解析 versionNumber,否则返回 null;添加按数值比较的 compareVersions(a, b);以及一个映射表 NATIVE_FEATURES = { iap: "1.3.0", biometric: "1.2.0" } 和 supportsNative(feature)。
2. 当 supportsNative() 为 false 时,隐藏调用该原生功能的界面,改为显示一条简短提示:“更新应用后即可使用此功能”。
3. 添加一个服务端端点,从数据库返回每个平台的 minimum、latest 和 storeUrl。
4. 添加一个 VersionGate:低于 minimum 时显示全屏更新页面,低于 latest 时显示可关闭的横幅,任何错误都放行。
5. 为 compareVersions、supportsNative 和出错放行的路径编写单元测试。
6. 在 .cursor/rules 中记录这些桥接变量。

我的iOS WebView应用终于通过审核了。谢谢!!

塔哈·法鲁基(Taha Farooqui) · CodeCanyon

WebViewGold 版本检查的工作原理

原生端只负责报告版本;规则放在您的后端。

  1. 向 Web 应用提供版本号

    在 Config.swift 中把 autoInjectVariable 设为 true,在 Config.java 中把 AUTO_INJECT_VARIABLES 设为 true。WebViewGold 随后会以 JavaScript 变量的形式提供 versionNumber(用户看到的版本号,例如 1.4.0)和 bundleNumber(构建号)。如果不使用自动注入,请导航到 getappversion:// 一次,然后读取相同的变量。

  2. 从后端发布版本规则

    在后端为每个平台存储最低支持版本和最新版本:一张小表、一个 JSON 文件或一条远程配置都可以。这样修改规则就无需发布商店版本,最好连部署都不需要。

  3. 按数值比较,而不是按文本比较

    按字符串比较时,“1.10.0”会排在“1.9.0”前面。请按点号拆分,把每一段当作数字来比较;如果您的构建号是单纯递增的整数,也可以直接比较构建号。

  4. 提示或阻止

    低于最新版本:显示一条可关闭的横幅。低于最低版本:显示全屏的“需要更新”页面,只有一个跳转到商店页面的按钮。在普通浏览器中,或者版本未知时,什么都不显示。

  5. 打开商店应用,而不是商店网页

    链接到 https://apps.apple.com/app/idYOUR_APPLE_ID 和 https://play.google.com/store/apps/details?id=your.package.name,并把 apps.apple.com 和 play.google.com 加入始终在应用外打开的主机列表(iOS 上是 safariwhitelist,Android 上是 BROWSER_WHITELIST),这样系统就会打开 App Store 或 Play 商店,而不是在 WebView 中显示网页。

JavaScript 中的版本关卡

在您的 Cursor 应用首次渲染后调用一次。它会短暂等待注入的变量,任何出错情况都会放行(fail open),只有后端明确要求时才会阻止。请为每个平台使用不同的 User-Agent 标记,例如在 useragent_iphone / useragent_ipad 中使用“WebViewGold-iOS”,在 USER_AGENT 中使用“WebViewGold-Android”:

javascript
const ua = navigator.userAgent;
const inApp = ua.includes("WebViewGold");
const platform = ua.includes("WebViewGold-Android") ? "android" : "ios";

function compareVersions(a, b) {
  const pa = String(a).split(".").map(Number);
  const pb = String(b).split(".").map(Number);
  for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
    const d = (pa[i] || 0) - (pb[i] || 0);
    if (d !== 0) return d < 0 ? -1 : 1;
  }
  return 0;
}

// autoInjectVariable / AUTO_INJECT_VARIABLES = true 时会提供 versionNumber;
// 否则请在轮询前先执行一次 window.location.href = "getappversion://"
function waitForVersion(ms = 3000) {
  return new Promise((resolve) => {
    const start = Date.now();
    (function poll() {
      if (typeof versionNumber !== "undefined") return resolve(String(versionNumber));
      if (Date.now() - start > ms) return resolve(null);
      setTimeout(poll, 100);
    })();
  });
}

async function checkAppVersion() {
  if (!inApp) return;                         // 浏览器中无需处理
  const installed = await waitForVersion();
  if (!installed) return;                     // 版本未知时放行
  const rule = await fetch("/api/app-version?platform=" + platform)
    .then((r) => (r.ok ? r.json() : null)).catch(() => null);
  if (!rule) return;                          // 后端不可达时放行
  if (compareVersions(installed, rule.minimum) < 0) showUpdateRequired(rule.storeUrl);
  else if (compareVersions(installed, rule.latest) < 0) showUpdateBanner(rule.storeUrl);
}

示例规则:最低 1.3.0,最新 1.4.0

已安装版本结果用户看到的内容
1.4.0 或更新已是最新什么都不显示
1.3.0 至 1.3.x低于最新版本一条可关闭的横幅:“有新版本可用”
1.2.x 或更早低于最低版本一个说明原因的全屏页面,带一个商店按钮和支持联系方式
浏览器、预览或版本未知无数据什么都不显示:失败放行

会把用户锁在门外的陷阱

  • 过早提高最低版本。请等新构建版本在两个商店都发布之后再提高。在 Google Play 分阶段发布期间,不在发布比例内的用户暂时还拿不到更新;Apple 的分阶段发布只会错开自动更新,iPhone 用户可以立即手动更新。
  • 阻止了正在审核的构建版本。App Review 安装的是您最新的构建版本,所以正确的比较逻辑永远不会阻止它。有缺陷的逻辑(字符串比较、平台识别错误)会让审核人员走进死胡同,并招来准则 2.1 拒审。
  • 出错时阻止(fail closed)。如果变量缺失、请求超时或手机离线,请让用户进入应用。误弹出的更新墙比旧版本更糟糕。
  • 把它用于 Web 改动。Web 部署本来就能覆盖所有人。只有原生改动才是需要更新的理由;参见哪些改动需要商店更新。
  • 没有任何说明。用一句话解释这次更新为什么重要,再附上支持联系方式,远胜于一个光秃秃的“立即更新”;而且这个页面不能藏在登录之后。

常见问题

WebViewGold 会自己强制更新吗?

不会。WebViewGold 会告诉您的 Web 应用当前安装的是哪个版本(通过 getappversion:// 或自动注入的 versionNumber 和 bundleNumber 变量)。决策逻辑和更新页面都在您的 Web 应用中,所以您可以随时修改规则,而无需发布商店版本。

如果我的 Web 应用即时更新,还需要强制更新吗?

通常不需要。大多数改动会在下一次页面加载时覆盖所有用户。版本检查只对原生改动重要:新的原生功能、新的起始 URL 或域名、链接处理或登录设置的变化。很多应用只需要那条温和的提示横幅。

Apple 和 Google 允许显示更新页面吗?

两个商店都不禁止请用户更新,许多大型应用也这样做。请确保正在审核的构建版本永远不会被阻止,如实说明为什么需要更新,并且只链接到您自己的商店页面。

我可以使用 Google Play 的应用内更新对话框吗?

Google 为 Android 应用提供了原生的应用内更新 API,但它不属于 WebViewGold 文档中的 JavaScript 桥接功能。版本检查加 Play 商店链接在两个平台上的工作方式相同,而且只需维护一套代码。

如何测试更新页面?

在后端临时把最低版本设得高于您的 TestFlight 或内部测试构建版本,打开应用,检查页面和商店按钮,然后再改回来。同时请在普通浏览器中打开网站:那里绝不能出现这个页面。

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

结果相同,只是您需要投入的工作量不同。三种方式都附带审核通过保证和 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日。

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

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

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

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