omg-ios-webview-return-fix.md 7.6 KB

OMG 支付 iOS WebView 返回 App 交接设计

最终决策(2026-08-17)

本方案只约定后端结果页与用户端 App 支付页之间的交接方式。支付状态查询、轮询、提示文案和最终业务页面跳转由前端继续实现,不属于本次后端修改范围。

  • 用户端实际支付页是 pages/OrderList/buy/omgCheckout。
  • 该页面通过 renderjs 创建并提交 HTML Form,OMG 收银台会加载到当前页面 WebView,而不是 <web-view> 子组件。
  • iOS 主返回流程由 omgCheckout 获取当前页面 WebviewObject,监听原生 loaded 事件并读取当前 URL。
  • 当前 URL 精确进入 https://foodieapi.waimai-paotui.com/pay/omg/result 时,视为收到 OMG_RETURNED 交接信号。
  • /pay/omg/result 继续返回 HTML 页面。现有提示内容、“返回 App”按钮和 App Scheme 可以保留,作为外部浏览器、Android 或监听失效时的兼容兜底。
  • iOS 主流程不依赖返回页中的 uni.webView.redirectTo、uni.postMessage、plus.webview.currentWebview、parent.evalJS 或 App Scheme。
  • 返回页到达只表示浏览器流程已经返回,不表示支付成功。前端不得仅凭该信号展示支付成功。
  • omgCheckout 是 OMG 专用页面,不需要额外增加 payChannel=omg。

后续如与 2026-08-14 的旧示例或旧描述存在差异,以本节和本文当前内容为准。

1. 问题与根因

OMG 信用卡付款完成后,iOS 会停留在后端返回的“正在返回 App”页面,自动返回和手动按钮都可能没有效果。

真机日志已经确认:

[OMG-RETURN] ios_parent_redirect_exception
ReferenceError: Can't find variable: sync

[OMG-RETURN] bridge_redirect_exception
ReferenceError: Can't find variable: sync

同一个 App Scheme 可以从 iOS 外部浏览器打开 App,说明 Scheme 注册和目标路由有效。失败边界位于 App 内 OMG WKWebView 的 Bridge 或同 App Scheme 交接。

因此,iOS 主流程不能继续依赖远程结果页主动控制 App 路由。可靠的交接点是 App 原生 WebView 自身的 loaded 事件。

2. 实际页面结构

pages/OrderList/buy/omgCheckout 不是承载 <web-view> 子组件的普通宿主页。它在 renderjs 中执行:

接收 omgCheckoutPayload
        ↓
创建 HTML Form
        ↓
POST 到 payload.gatewayUrl
        ↓
当前页面 WebView 被 OMG 收银台内容替换

所以前端需要监听:

this.$scope.$getAppWebview()

而不是:

this.$scope.$getAppWebview().children()[0]

renderjs 只负责提交 OMG Form。URL 监听和 App 路由接管必须放在普通 <script> 的 App 逻辑层中。

3. 返回交接流程

用户在 OMG 收银台完成或结束支付流程
        |
        v
OMG POST /pay/omg/result
        |
        v
后端校验返回资料并返回现有 HTML 结果页
        |
        v
omgCheckout 当前 WebView 触发 loaded
        |
        v
omgCheckout 通过 getURL() 读取当前地址
        |
        +-- 不是 /pay/omg/result --> 忽略
        |
        +-- 精确匹配结果页 -------> 触发一次 OMG_RETURNED
                                      |
                                      v
                              前端接管后续业务

这里所说的“结果页通知外层”是指:结果页加载使原生 WebView 自动触发 loaded,外层 App 逻辑再读取 URL。结果页不需要主动调用 postMessage。

4. 后端结果页边界

POST /pay/omg/result 继续存在,并继续返回 text/html 页面,不能删除接口或改为 204 No Content。

后端继续负责:

  • 接收 OMG 的 application/x-www-form-urlencoded Client POST。
  • 按现有规则校验返回资料。
  • 返回禁止缓存的安全 HTML 页面。
  • 保留现有页面提示内容。
  • 可以保留“返回 App”按钮及 App Scheme 作为兼容兜底。

后端结果页不负责保证 iOS App 内路由成功。即使保留现有 Bridge、父 WebView 或 Scheme 尝试,它们也只能作为非关键兜底,失败不得影响页面正常返回。

结果页不得直接宣称支付成功,也不得在 HTML、URL 或日志中暴露 token、完整 formFields、CheckMacValue 或其他支付凭证。

5. 前端交接契约

前端应在 renderjs 提交 Form 后、支付完成前,保证当前页面 WebView 已经绑定 loaded 监听。监听绑定后应立即读取一次当前 URL,防止目标页面在绑定前已经加载完成。

结果页匹配规则:

https://foodieapi.waimai-paotui.com/pay/omg/result
https://foodieapi.waimai-paotui.com/pay/omg/result?...query...
https://foodieapi.waimai-paotui.com/pay/omg/result#...hash...

必须同时精确匹配协议、域名和路径,不能只判断 URL 包含 omg 或 result。

匹配后只触发一次 OMG_RETURNED,防止 loaded 重复触发造成重复查询或重复跳转。omgCheckout 已经保存 orderId,结果页不需要重新传递订单号。

页面销毁时,前端需要移除 loaded 监听器并清理本页面创建的定时器。具体支付查询、状态处理和路由由前端实现。

6. 安全约束

  • /pay/omg/result 到达不等于支付成功。
  • 只有后端支付状态查询确认成功后,前端才能展示支付成功页面。
  • token 只能由 App 请求层发送给后端,不能传给 OMG 页面或拼入结果页 URL。
  • 日志不得包含 token、完整 formFields、CheckMacValue 或完整回调 URL。
  • 必须防止重复 loaded 事件造成重复业务处理。

7. 兼容策略

通道 定位 说明
当前 WebView loaded + 精确 URL iOS 主流程 不依赖远程页面 Bridge,由 omgCheckout 接管
现有“返回 App”按钮 兼容兜底 页面外观可以保留,不作为 iOS 成功判据
App Scheme 外部浏览器/Android 兜底 同 App iOS WKWebView 中不保证有效
远程 Bridge、parent.evalJS 非关键旧兜底 已有真机失败证据,不能承担主流程

保留旧页面和按钮不等于继续依赖旧方案。iOS 是否能够自动返回,必须以 omgCheckout 的原生 WebView 监听为准。

8. 预期日志

前端至少应能观察到以下交接日志;字段名称可按 App 现有规范调整:

[OMG-APP] webview_loaded {"isOmgResultPage":true}
[OMG-APP] result_page_detected {"orderRef":"***7389"}

结果页旧兜底失败日志可以继续存在,但不得影响上述交接:

[OMG-RETURN] ios_parent_redirect_exception ...
[OMG-RETURN] bridge_redirect_exception ...

9. 验收清单

  1. 使用 iPhone 打开 App 并进入 pages/OrderList/buy/omgCheckout。
  2. 确认当前页面 WebView 的 loaded 监听在支付完成前已绑定。
  3. 完成一笔 OMG 支付,确认后端仍返回现有 HTML 结果页。
  4. 确认结果页仍可显示原有提示和“返回 App”按钮。
  5. 确认 omgCheckout 能读取到精确的 /pay/omg/result URL。
  6. 确认同一次返回只触发一次 OMG_RETURNED。
  7. 确认 OMG 收银台中间页面、取消页面及其他地址不会触发返回交接。
  8. 确认后续支付状态处理由前端接管,并且不会仅凭结果页到达显示支付成功。
  9. 使用 Android 和外部浏览器复核现有按钮及 Scheme 兜底未被破坏。

10. 本次范围

本次只确认和记录交接设计,不修改用户端 App 代码,也不修改支付查询、轮询、提示文案或最终路由实现。

参考资料: