> ## Documentation Index
> Fetch the complete documentation index at: https://waffo.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 在我自己的 App 里加载收银台（WebView、App 唤起、返回）

> WebView 集成指南没有回答的 App 侧问题：Waffo 是否会检测 WebView 并提示客户、要放行哪些域名、客户不再返回时您的 App 如何得知支付结果、钱包 App 往返后收银台是否会自行刷新、支付跳转链接能否打开两次、钱包打不开时要采集什么、为什么 App 唤起无法在 sandbox 测试，以及能否只在 App 环境隐藏某种支付方式。

在 App WebView 中嵌入收银台的机制——您的 WebView
必须放行什么、如何在 Android 和 iOS 上拦截非 HTTP(S) scheme、以及如何
排查 `net::ERR_UNKNOWN_URL_SCHEME`——见
[收银台集成步骤](/docs/zh/developer-docs/integration/checkout/steps#app-webview-integration-considerations)，
各支付方式的例外见
[支付方式集成说明](/docs/zh/developer-docs/tools-and-references/references/payment-method-integration-notes)。
请先阅读那些内容。本页回答围绕它们产生的问题。

## 发布 WebView 集成之前有清单可以过一遍吗？

有——以下是支付流程可能依赖的能力。您的 App 每屏蔽
一项，就会直接去掉一些支付方式，而不是优雅降级。

| 能力 | 支付流程为什么需要它 | 详情在哪里 |
| - | - | - |
| 从非 HTTP(S) scheme 打开外部 App | 在自己 App 内授权的钱包方式 | [Steps → custom schemes](/docs/zh/developer-docs/integration/checkout/steps#handle-wallet-app-custom-schemes) |
| 打开外部浏览器 | 声明其流程无法在商户 App WebView 中运行的方式 | [支付方式集成说明](/docs/zh/developer-docs/tools-and-references/references/payment-method-integration-notes) |
| 下载、复制和长按保存 | 二维码、支付码、银行信息 | Steps → WebView considerations |
| 保留 URL 和每一个查询参数 | 有些方式会在跳转上附加必需的值 | Steps → WebView considerations |
| `allow="payment"` 和 `strict-origin-when-cross-origin` referrer（如果您也嵌入 iframe） | 浏览器支付 API 和对 referrer 敏感的方式 | [Steps → iframe](/docs/zh/developer-docs/integration/checkout/steps#iframe-embedding-considerations) |
| 如实发送 `userInfo.userTerminal` | 终端类型决定哪些方式根本有资格出现 | [跳转与 `actionType`](/docs/zh/support/cashier-redirect-and-action-type-faq) |

## 我能从收银台检测到自己在 WebView 里吗？Waffo 会提示客户吗？

收银台一般不会尝试检测 App WebView，也不会
为此显示"请在浏览器中打开"的提示。有一个例外：当
收银台在已知支付流程无法运行的**即时通讯 App 内置浏览器**中打开时，
它会显示一个阻断对话框，要求
客户在别处打开链接，显示完整链接，并提供复制
按钮。该对话框无法关闭，因为在那个页面上继续
终归会失败。

对于您自己的 App，检测应在您这边完成：您控制着 WebView，所以
您本来就知道。请在创建订单时利用这一点——见
下文关于在 App 环境隐藏支付方式的问题。

## 我的 WebView 必须放行哪些域名？

放行 Waffo 收银台域名，并且不要把域名白名单当作
您对支付流程的控制手段。

收银台 URL 是 Waffo 域名下的 HTTPS，但之后的支付步骤
会导航到支付方式自己的域名，钱包唤起时还会导航到
支付页面在运行时决定的非 HTTP(S) scheme。这一下游集合
是每种支付方式的属性，会在您这边没有任何改动的情况下变化，
所以没有可以固定的列表。只允许固定主机集合的 App
能通过集成测试，然后在您没测过的某种方式上失败。

受支持的做法是
[Steps → custom schemes](/docs/zh/developer-docs/integration/checkout/steps#handle-wallet-app-custom-schemes)
中的那种：把 HTTP(S) 导航留在 WebView 内，把经过校验的非 HTTP(S) 导航
交给操作系统。

## 客户离开我的 WebView 去钱包 App 付款了，我的 App 怎么得知结果？

通过您的服务端，而不是通过 WebView。可靠性顺序是固定的，
在 App 场景下也不会变：

| 信号 | 用途 |
| - | - |
| 发到您 `notifyUrl` 的支付通知 | 权威结果。由您的服务端告知您的 App |
| `POST /api/v1/order/inquiry` | 确认或补齐——例如 App 恢复到前台时 |
| `successRedirectUrl` / `failedRedirectUrl` / `cancelRedirectUrl` | 仅用于切换客户的屏幕 |

一个实用的 App 模式：当您的 App 回到前台时，向您自己的
后端询问订单状态（后端通过通知或查询得知），而不是从
WebView 中读取任何内容。这也是能应对客户手动切回您的 App、
而不是跟随跳转的模式。

关于为什么跳转不是结果的完整论述，见
[支付结果](/docs/zh/support/payment-results-faq)。

## 客户没经过跳转，直接切回了我的 App。这笔订单我该怎么处理？

不需要特殊处理——并且明确地说，不要把它当作失败。从
平台的角度看，订单正处于支付方式留下的那个状态，
跳转被跳过并不能说明该状态是什么。

* 查询订单，或等待通知。两者都给出真实状态。
* 不要因为客户没有回来就关闭、取消或重新创建订单。
  重复支付就是这样产生的。
* 如果支付仍在待处理，客户很可能之后会在订单有效期内、
  在钱包 App 里完成支付。

## 客户回到了 WebView，收银台页面会自己刷新结果吗？

会。当收银台处于任何待定状态——等待跳转、等待
二维码等指引、或处理中——它会以退避间隔轮询订单状态，
并在结果到达时自行推进页面。
某些客户通常付款很快的二维码方式，在二维码展示后会
以更高频率轮询。

跳转页还带有一个明确的重新检查操作。按下它会立即查询
订单；如果支付仍未完成，页面会如实
告知，而不是假装已完成。

所以客户不需要重新加载任何东西，您的 App 也不应
在恢复前台时强制重新加载 WebView——那可能会重启一个本来正常的流程。

## 同一个支付跳转链接能打开两次吗？客户再点一次付款会失效吗？

取决于支付方式，您无法控制。有些支付
方式签发的跳转 URL 是**一次性**的——消费一次后，再次打开
就不起作用。其他方式允许重新打开。

托管收银台知道适用哪种情况并相应体现：允许重新打开时，
页面会一直提供 **Pay** 按钮让客户可以再次跳
出到钱包；不允许时，页面只提供重新检查操作，
以免把客户送到一个会失败的 URL。

两个后果：

* 在托管收银台上您什么都不用做——页面已经
  处理了两种情况。
* 在商户自建收银台上，**请把跳转 URL 当作一次性的**。这一
  属性有意不放在面向商户的 `orderAction` 中，
  所以您没有任何可以据此分支的字段。展示跳转一次，然后
  回退到查询订单。

## 客户在 WebView 里点了付款，什么都没发生。联系支持团队前我要采集什么？

在失败当时采集以下五项。没有它们，该报告
无法与正常的"客户改变主意"区分开。

1. WebView 收到的**最后一个导航 URL**，完整且未修改——
   包括其 scheme 和每一个查询参数
2. 您的 WebView 导航回调是否对该 URL 触发过
3. 设备上是否有任何已安装的 App 能处理该 scheme
4. 订单 ID 和时间戳
5. 客户是在您 App 的 WebView、外部浏览器，还是
   另一个 App 的内置浏览器中

[Steps → troubleshooting](/docs/zh/developer-docs/integration/checkout/steps#troubleshoot-err_unknown_url_scheme-and-forbidden)
中的排查表把常见症状映射到原因。注意那里的规则：从
失败 URL 的 scheme 和您 WebView 对它的处理来诊断，而不是从设备型号
或操作系统版本。同一个 App 构建在不同操作系统版本上表现不同，
几乎总是导航回调被触达方式的差异，而不是
平台级别的拦截。

## 为什么我在 sandbox 里复现不了钱包 App 唤起？

因为 sandbox 不连接真实的支付方式。sandbox
收银台是一个模拟器：您按按钮声明结果，
没有真实的支付方式选择、没有卡输入，也没有钱包 App 交接。见
[Sandbox 模拟器](/docs/zh/developer-docs/tools-and-references/developer-tools/sandbox-simulator)。

所以您集成中的 App 唤起部分——scheme 拦截、把 URL 交给
操作系统、返回——必须在生产环境用一笔
小额真实支付验证。sandbox *擅长*的是它周边的一切：订单
创建、通知处理、App 恢复逻辑，以及您自己的
恢复时读取订单状态的流程。

请为每种涉及 App 交接的支付方式规划一次生产冒烟测试，
并预留它需要真实钱包账户这一事实的成本。

## 我能只在我的 App 环境里隐藏某种支付方式吗？

无法通过设置实现，收银台上也没有"环境"参数。
您能做的——也是平台围绕其设计的——是按订单决定：

* 您的 App 知道自己是您的 App。让您的服务端在 `/api/v1/order/create` 上传入 `payMethodType`，
  以及针对特定钱包传入 `payMethodName`，这样订单只
  提供在该环境下可用的方式。
* 如实发送 `userInfo.userTerminal`。不支持您所发送终端
  类型的方式根本不会被提供。

无论如何，按订单过滤比账户级开关更稳健，因为
同一个账户通常还服务于一个没有此类限制的网页流程。
参数规则见
[收银台定制](/docs/zh/developer-docs/integration/checkout/customization#payment-method-filtering)。

## 我是不是应该一开始就在外部浏览器打开收银台？

这是一种合理的设计，而且对某些支付方式来说是唯一
可行的——各方式说明列出了其自身流程无法在
商户 App WebView 内运行的情形。

需要权衡的取舍：

| | App 内 WebView | 一开始就用外部浏览器 |
| - | - | - |
| 客户留在您的 App 内 | 是 | 否——有可见的 App 切换 |
| 钱包 App 唤起 | 需要您的 App 做 scheme 拦截 | 由浏览器处理 |
| 下载 / 复制 / 长按保存 | 需要您的 WebView 明确支持 | 可用 |
| 支付后返回您的 App | 您的跳转处理 | 取决于客户，或使用 deeplink 跳转 URL |
| 拒绝商户 App WebView 的方式 | 必须隐藏或外部打开 | 无需特殊处理 |

许多集成最终采用的折中路线：对能在 WebView 中运行的流程保留
WebView，仅对支付方式要求的订单打开外部浏览器——
这在创建时您就知道，因为方式是您选的。

注意 `successRedirectUrl`、`failedRedirectUrl` 和 `cancelRedirectUrl`
既接受 HTTPS URL 也接受 deeplink，所以外部浏览器流程仍然可以
把客户带回您的 App。

## 有 SDK 帮我封装 App 侧的唤起吗？

Waffo 前端 SDK 覆盖的是网页层面——渲染卡字段，以及
在您的页面中嵌入收银台。App 侧的部分——在您的 WebView 中拦截
非 HTTP(S) 导航并交给操作系统——
是您自己 App 中的平台 API，没有 Waffo 库可以替代
它们。Android 和 iOS 的平台文档链接见
[Steps → custom schemes](/docs/zh/developer-docs/integration/checkout/steps#handle-wallet-app-custom-schemes)。

## 我能直接把收银台链接通过短信或邮件发给客户吗？

那正是支付链接的用途，它是一个独立的产品层面，有
自己的过期和复用规则——见[支付链接](/docs/zh/support/payment-link-faq)。
不要把 API 创建订单的收银台 URL 改作对外发送的链接：
它属于一笔订单，随该订单过期，一旦订单
到达最终状态，链接就会显示过期页面。

***

遇到无法归类的 WebView 故障？请携上文采集清单中的五项
[联系支持团队](mailto:support@waffo.com)。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.