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

Claude Code + 可靠性

用 Claude Code 构建离线页面和错误状态:App Review 测什么,以及如何通过

审核人员打开飞行模式,四处点一点,再把它关掉。如果您的应用显示白屏、原始错误信息,或者一个转个不停的加载图标,就会因准则 2.1 或功能损坏而被拒。WebViewGold 用原生离线页面处理页面加载失败的情况;而在您正在运行的 Web 应用内部发生的一切,都要靠您的代码。下面介绍 Claude Code 如何构建这一部分,以及如何像审核人员那样测试它。

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

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

两个层面:原生外壳和正在运行的应用

外壳。当 WebView 无法加载页面时,WebViewGold 会显示其原生离线页面,而不是错误页面。在 iOS 上,您可以通过 offlinetitle、offlinemsg、screen1、screen2 和 offlinebuttontext 设置其文字,offlinescreenautoretry 会每秒自动重试,无需点按。在 Android 上,您可以用 OFFLINE_SCREEN_BACKGROUND_COLOR 设置背景色;应用的文字字符串位于 strings.xml 中。想要更进一步,两个平台都可以在离线时显示一个内置的本地 HTML 页面(iOS 为 offlinelocalhtmlswitch,Android 为 FALLBACK_USE_LOCAL_HTML_FOLDER_IF_OFFLINE),并提供一个调用 reconnect:// 的“重试”按钮,重新加载最后一个在线 URL(Reconnect API)。

您的应用。一个已经在运行的单页应用,在网络断开时不会触发页面加载。它的 fetch 请求在页面内部失败,只有您的代码才能显示合理的内容:离线横幅、带“重试”的错误状态、超时提示而不是无休止的加载图标。大多数离线相关的拒审都源于此,这也是下面由 Claude Code 构建的部分。离线模式专题页比较了离线支持的三个层级。

审核人员依据准则 2.1(应用完整性:崩溃、损坏的页面、占位内容),Google 则依据其功能损坏规则。两者都不要求您的应用完全离线可用,但都期望它说明发生了什么,并且能够恢复。

Claude Code 做什么,您做什么

Claude Code

编写在线状态 hook、fetch 封装函数、每一个加载状态、空状态和错误状态、错误边界、备用页面,以及模拟离线和服务器错误的 Playwright 测试,然后运行这些测试。

您

设置原生离线页面的文字和颜色,把备用页面复制到两个 WebViewGold 项目中,如有需要就开启备用页面,然后构建一次。

审核人员式测试

在启动时和使用过程中开启飞行模式、慢速网络、出故障的 API,全部在真实设备上进行。这是唯一与 App Review 实际做法相符的测试。

故障场景及其负责方

情况由谁处理用户应该看到什么
应用启动时没有网络WebViewGold 离线页面或本地备用页面带有您品牌风格的提示和“重试”
使用过程中网络断开您的 Web 应用一条细长的离线横幅;需要网络的操作被禁用或排队
网络非常慢您的 Web 应用先显示骨架屏,约 10 到 15 秒后显示超时提示和“重试”
API 返回 500您的 Web 应用一句通俗的说明和“重试”;没有堆栈跟踪,也没有 JSON
会话已过期您的 Web 应用返回登录页并附上简短说明,登录后再回到原来的页面
未知路由您的 Web 应用一个像应用一样的“未找到”页面,带“首页”按钮
计划内维护您的 Web 应用一个无需部署就能开启的维护页面

把 Web 应用转换成原生应用的绝佳方式!周转速度快,无需开发完整的原生应用就能把应用上架到应用商店!

Kevin Joling · FlightConnections & TrainConnections · Trustpilot

Claude Code 提示词

第 7 项中的 Playwright 测试让这一切可以重复:Claude Code 编写测试,通过它的 Bash 工具运行,并修复失败的部分。

粘贴到 Claude Code
审核人员会在飞行模式和糟糕的网络下测试我们的应用。应用运行在用 WebViewGold 构建的原生 iOS 和 Android 应用中。页面加载失败时,封装层会显示原生离线页面;但一旦我们的单页应用运行起来,失败的 fetch 和路由切换就只能由我们的代码处理。让每一种故障都可见、可恢复。

1. src/lib/use-online.ts:一个基于窗口 online 和 offline 事件的 hook。离线时,在安全区域下方显示一条细长横幅:您已离线。网络恢复后,我们会重新加载您的数据。恢复在线后隐藏横幅,并重新获取可见的查询。
2. src/lib/fetch-json.ts:一个 fetch 封装函数,超时时间 12 秒(AbortController),针对离线、超时和请求失败抛出 NetworkError,遇到 401 时重定向到 /login?reason=expired,登录后返回原来的路径。用它替换所有直接的 fetch 调用。
3. 每个加载数据的页面都要有加载骨架屏、带一个有用操作的空状态,以及带一句通俗说明和“重试”按钮的错误状态。界面中不得出现原始错误信息、状态码或堆栈跟踪。
4. 需要网络的操作在离线时禁用,并显示“等待网络连接”,或者排队,在恢复在线后发送。绝不能丢失用户输入的内容。
5. 一个带友好备用界面和“重新加载”按钮的根错误边界,一个像应用一样、带“首页”按钮的“未找到”页面,以及一个可以通过环境变量开启的 /maintenance 页面。
6. 任何加载图标都不能永远转下去:每个加载状态最终都要变成内容、空状态或错误状态。
7. 使用 context.setOffline(true) 的 Playwright 测试,检查横幅、带“重试”的错误状态以及恢复在线后的恢复情况,再加一个模拟 API 返回 500 的测试。运行这些测试并修复失败项。
8. public/offline-fallback/index.html:一个完全自包含的页面(内联 CSS,不使用外部字体、脚本或图片),采用我们的品牌色,包含一段简短的提示和一个导航到 reconnect:// 的“重试”按钮。我会把它复制到 WebViewGold 项目中。

列出改动过的每个页面,以及所有无法测试的内容。

在线状态 hook 和 fetch 封装函数

小到一次就能审阅完。请注意,navigator.onLine 为 true 并不能证明互联网可用(想想酒店的 Wi-Fi),所以失败的请求也会被当作网络错误处理。

typescript
// src/lib/use-online.ts
import { useEffect, useState } from "react";

export function useOnline() {
  const [online, setOnline] = useState(typeof navigator === "undefined" ? true : navigator.onLine);
  useEffect(() => {
    const up = () => setOnline(true);
    const down = () => setOnline(false);
    window.addEventListener("online", up);
    window.addEventListener("offline", down);
    return () => {
      window.removeEventListener("online", up);
      window.removeEventListener("offline", down);
    };
  }, []);
  return online;
}

// src/lib/fetch-json.ts
export class NetworkError extends Error {}

export async function fetchJson<T>(url: string, init: RequestInit = {}, timeoutMs = 12000): Promise<T> {
  if (typeof navigator !== "undefined" && !navigator.onLine) throw new NetworkError("offline");
  const ctrl = new AbortController();
  const timer = setTimeout(() => ctrl.abort(), timeoutMs);
  try {
    const res = await fetch(url, { ...init, signal: ctrl.signal });
    if (res.status === 401) {
      window.location.href = "/login?reason=expired&next=" + encodeURIComponent(location.pathname);
      throw new Error("unauthorized");
    }
    if (!res.ok) throw new Error("HTTP " + res.status);
    return (await res.json()) as T;
  } catch (e) {
    if (e instanceof DOMException && e.name === "AbortError") throw new NetworkError("timeout");
    if (e instanceof TypeError) throw new NetworkError("network"); // 请求根本没有到达服务器
    throw e;
  } finally {
    clearTimeout(timer);
  }
}

带 reconnect:// 的内置备用页面

所有内容都内联,因为这个页面恰恰是在什么都下载不了的时候显示的。按照iOS 设置指南和Android 设置指南(选项 C)中的说明,把它复制到每个 WebViewGold 项目的本地 HTML 文件夹中。请把页面文字改成您应用所用的语言。

html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
  <title>Offline</title>
  <style>
    body { margin: 0; min-height: 100vh; display: grid; place-items: center; padding: 24px;
           box-sizing: border-box; text-align: center; background: #0f172a; color: #e2e8f0;
           font-family: -apple-system, system-ui, sans-serif; }
    h1 { font-size: 22px; margin: 0 0 8px; }
    p { margin: 0; line-height: 1.5; color: #94a3b8; }
    button { margin-top: 24px; min-height: 48px; padding: 0 28px; border: 0; border-radius: 12px;
             background: #38bdf8; color: #0f172a; font-size: 17px; font-weight: 600; }
  </style>
</head>
<body>
  <main>
    <h1>You are offline</h1>
    <p>We will take you back to where you were as soon as the connection returns.</p>
    <button type="button" onclick="window.location.href='reconnect://'">Try again</button>
  </main>
</body>
</html>

设置原生部分

每个项目十分钟,外加一次构建。

  1. 为离线页面打上品牌

    iOS:用您应用的语气撰写 offlinetitle、offlinemsg、screen1、screen2 和 offlinebuttontext,并把 offlinescreenautoretry 设为 true。Android:设置 OFFLINE_SCREEN_BACKGROUND_COLOR,并在 strings.xml 的应用文字字符串中检查离线相关的措辞。

  2. 可选:内置备用页面

    把上面的页面复制到本地 HTML 文件夹,并开启 offlinelocalhtmlswitch(iOS)或 FALLBACK_USE_LOCAL_HTML_FOLDER_IF_OFFLINE(Android),同时让 uselocalhtmlfolder / USE_LOCAL_HTML_FOLDER 保持为 false,这样远程 URL 仍是主要来源。

  3. 加载反馈

    选择原生加载标志或进度条(iOS 上为 useLoadingSign、useLoadingProgressBar、loadingIndicatorColor;Android 上为 ACTIVATE_PROGRESS_BAR)。对于耗时较长的服务器操作,您的应用可以用 spinneron:// 显示原生加载指示器,再用 spinneroff:// 隐藏它。

  4. 运行提示词并部署

    审阅 diff,亲自运行一次 Playwright 测试,然后部署。Web 部分会立即推送到已安装的应用中。

  5. 构建一次

    离线文字和备用页面是原生构建的一部分。如果您希望由我们的团队来设置并构建两个应用,Full Service 可以全部包办。

像审核人员一样测试

  • 在飞行模式下冷启动:出现带有您文字的原生离线页面(或您的备用页面)。关闭飞行模式,点“重试”:应用加载成功。
  • 使用应用时开启飞行模式:横幅出现,需要网络的按钮显示“等待网络连接”,没有任何地方变白。关闭飞行模式:横幅消失,数据随之刷新。
  • 模拟糟糕的网络:在 iPhone 上,使用“设置 → 开发者”下的 Network Link Conditioner(设备连接过 Xcode 后才会显示);在 Android 上,使用模拟器的网络速度设置。先出现骨架屏,然后是内容,或者带“重试”的超时提示。
  • 让一个预览部署指向错误的 API URL:每个页面都显示带“重试”的错误状态,没有一个显示原始 JSON。
  • 在另一个标签页中退出登录,或者让会话过期:应用返回登录页并附上简短说明,然后再回到原来的页面。
  • 打开一个不存在的路由:出现一个像应用一样、带“首页”按钮的“未找到”页面。
  • 把应用放到后台半小时再回来:它仍然可用,或者干净地重新加载(如果您的数据会过时,可以考虑 autoRefreshEnabled / AUTO_REFRESH_ENABLED,并测试它不会丢掉填了一半的表单)。

常见陷阱

  • 无休止的加载图标。每个请求都需要超时。一个永不停止的加载图标,在审核人员看来就是卡死了。
  • 会加载外部资源的备用页面。Web 字体、CDN 上的 CSS 或来自您服务器的图片,在离线时都不存在。请把所有内容内联。
  • 把离线支持建立在 Service Worker 上。不要在 iOS 应用中依赖它,WKWebView 只在特定配置下才启用 Service Worker。原生离线页面和内置备用页面才是可靠的层面。
  • 把审核人员挡在门外。地理封锁、针对数据中心 IP 的防火墙规则或过于激进的机器人验证,会让您的 API 只对 Apple 和 Google 失败。请针对审核人员测试时所在的地区检查您的规则。
  • 占位页面。“即将推出”页面和点了没反应的按钮同样属于准则 2.1 的问题。既然代理反正要改动每个页面,就让它顺便把这些列出来。

常见问题

我的应用必须完全离线可用吗?

不必。审核人员期望的是清晰的提示和可用的恢复方式,而不是离线功能。要完全离线使用,需要一个内置的本地版本,或者一个专为离线数据设计的应用。

为什么我在使用过程中断网时,原生离线页面没有出现?

因为那一刻并没有在加载任何页面。一个正在运行的单页应用只会让它自己的 fetch 请求失败,所以横幅和错误状态必须由您的代码来显示。

reconnect:// 具体做什么?

它会重新加载应用切换到离线页面之前最后一个成功加载的 URL。如果网络仍然断开,备用页面会再次出现。

Claude Code 能自己测试飞行模式吗?

它可以用 Playwright 在浏览器中模拟离线(context.setOffline)并模拟服务器错误,这覆盖了您的 Web 代码。原生离线页面和真实的网络行为,仍然需要在手机上测试。

离线横幅应该出现在哪里?

在状态栏和安全区域下方,覆盖在内容之上,但绝不能挡住主要按钮。顶部一条细长的横条,是用户熟悉的惯例。

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

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