PAYATHON 2026

集成 HyperPay 后未获得有效支付结果

支付小周

结论

shopperResultUrl 被拒绝的原因是:

com.share.flutter_app://result

这个地址的 URI scheme com.share.flutter_app 含有下划线 _。标准 URI 语法规定,scheme 只能使用字母、数字、加号 +、连字符 - 和点号 .,不能使用下划线。

可以改成:

com.share.flutterapp://result

或者:

com.share.flutter-app://result

Android 和 iOS 也要注册完全相同的 Deep Link scheme。

notificationUrl 应填写支付服务器可以访问的公网 HTTPS 地址,不能使用 App Deep Link。HyperPay 会通过这个地址发送服务端异步支付通知,例如:

https://api.example.com/webhooks/hyperpay

为什么会出现这个错误

响应中的两个参数错误彼此相关:

shopperResultUrl: invalid uri
notificationUrl: Notification url must be present if shopperResultUrl is not a valid url

第一个错误说明 HyperPay 无法将下面的值解析为有效 URI:

com.share.flutter_app://result

URI 的基本格式是:

scheme://host/path

按照通用 URI 语法,scheme 必须符合:

[A-Za-z][A-Za-z0-9+.-]*

因此:

com.share.flutter_app   // 无效,包含 _
com.share.flutterapp    // 有效
com.share.flutter-app   // 有效
com.share.flutter.app   // 有效

由于 shopperResultUrl 无效,同时 HyperPay 没有收到可用的 notificationUrl,最终返回:

200.300.404

这个结果表示请求参数缺失或格式错误,不是最终的支付成功或失败状态。

正确配置 shopperResultUrl

创建 checkout 时,可以使用不带下划线的自定义 scheme:

shopperResultUrl=com.share.flutterapp://result

请求参数示例:

entityId=YOUR_ENTITY_ID
amount=10.00
currency=SAR
paymentType=DB
shopperResultUrl=com.share.flutterapp://result

使用表单编码时,需要对参数进行 URL 编码。例如:

curl -X POST "https://eu-test.oppwa.com/v1/checkouts" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "entityId=YOUR_ENTITY_ID" \
  --data-urlencode "amount=10.00" \
  --data-urlencode "currency=SAR" \
  --data-urlencode "paymentType=DB" \
  --data-urlencode "shopperResultUrl=com.share.flutterapp://result"

HyperPay 的接口地址、认证方式和必填字段可能因接入模式及运行环境而异,请以当前账户对应的官方集成文档为准。

只修改接口参数还不够,App 也必须能处理相同的 URI。

Android

在目标 Activity 的 AndroidManifest.xml 中添加:

<intent-filter>
    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />

    <data
        android:scheme="com.share.flutterapp"
        android:host="result" />
</intent-filter>

这段配置对应以下地址:

com.share.flutterapp://result

android:scheme 和 android:host 必须与传给 HyperPay 的地址一致。

iOS

在 Info.plist 中注册 URL scheme:

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>com.share.flutterapp</string>
        </array>
    </dict>
</array>

如果使用 Flutter Deep Link 插件,还需要按插件要求配置事件监听。插件只能将回调 URI 交给应用,不能替代服务端的支付状态查询。

正确配置 notificationUrl

notificationUrl 是服务端 webhook 地址,需要满足以下条件:

  • 使用公网可以访问的 URL;
  • 优先使用 HTTPS;
  • 不能填写 localhost、局域网地址或 App 自定义 scheme;
  • 接口能够接收 HyperPay 发出的通知请求;
  • 收到通知后,再次向 HyperPay 查询并核验支付状态。

例如:

https://api.example.com/webhooks/hyperpay

参数可以这样填写:

shopperResultUrl=com.share.flutterapp://result
notificationUrl=https://api.example.com/webhooks/hyperpay

在本机开发时,通常需要部署测试 webhook,或者通过安全的 HTTPS 隧道临时开放本地接口。HyperPay 测试环境是否接受某类隧道域名,应以其实际校验规则为准。

如何可靠获得支付结果

shopperResultUrl 的作用只是将用户带回 App,不能直接证明支付成功。用户可能关闭页面、遇到网络中断,回调 URI 也可能被手动触发。

建议按以下流程处理:

  1. 服务端创建 checkout,并将 checkout ID 返回给 App。
  2. App 打开 HyperPay 支付组件。
  3. 支付流程结束后,App 收到 shopperResultUrl 回调。
  4. App 将 checkout ID 或 SDK 返回的 resourcePath 发给自己的服务端。
  5. 服务端调用 HyperPay 的支付状态查询接口。
  6. 服务端根据查询结果更新订单。
  7. 配置了 notificationUrl 时,服务端还要处理异步通知,并通过幂等机制应对重复通知。

查询逻辑的伪代码如下:

async function verifyPayment(resourcePath) {
  // resourcePath 应来自可信的支付流程,
  // 并在服务端验证它是否属于当前订单。
  const response = await hyperPayRequest(resourcePath, {
    entityId: process.env.HYPERPAY_ENTITY_ID
  });

  return response.result;
}

App 收到下面的地址后,不要直接将订单标记为已支付:

com.share.flutterapp://result

最终支付状态应以服务端查询到的 HyperPay 结果为准。

注意事项

  • 不要在 shopperResultUrl 的 scheme 中使用 _。
  • 自定义 scheme、Android Manifest 和 iOS Info.plist 中的配置必须一致。
  • notificationUrl 应指向服务端 HTTPS 接口,不能填写移动端 Deep Link。
  • 测试环境和生产环境应分别配置接口地址、凭据和 entity ID。
  • 不要在 App 中保存访问令牌等服务端密钥。
  • webhook 可能重复发送,订单更新必须具备幂等性。
  • 判断支付结果时,应遵循当前 HyperPay 文档中的结果码规则,不能只看 HTTP 状态码或页面是否成功跳转。

备注:内容仅供参考。