client_framework/docs/payment_flow.md
2026-03-24 19:34:04 +08:00

6.7 KiB
Raw Blame History

支付流程文档

1. 概述

本文档描述 Android 项目Flutter的完整支付流程包括商品获取、支付方式选择、订单创建、Google Play 内购以及补单机制。


2. 支付流程总览

用户点击 Buy
    │
    ├─ enableThirdPartyPayment === true 且已登录
    │       │
    │       ├─ getPaymentMethods(activityId) 获取支付方式
    │       ├─ 弹窗选择支付方式_PaymentMethodDialog
    │       ├─ createPayment 创建订单
    │       │
    │       ├─ 若选中的是 Google Payresource/ceremony == "GooglePay"
    │       │       ├─ 调起 Google Play 内购
    │       │       ├─ 拿到 serverVerificationData
    │       │       └─ POST /v1/payment/googlepay 回调验证
    │       │
    │       └─ 否则(其他支付方式)
    │               └─ 打开 payUrl 在外部浏览器完成支付
    │
    └─ enableThirdPartyPayment !== true 或未登录
            └─ 仅 Android直接调起 Google Play 内购

3. 支付分支依据

条件 说明
UserState.enableThirdPartyPayment 登录后由 AuthService 从 /v1/user/common_info 响应写入
UserState.userId 用户登录后存储的用户 ID
第三方支付 enableThirdPartyPayment == trueuserId 非空
直接谷歌支付 其他情况(未开第三方支付或未登录)

4. 商品展示与获取

4.1 接口

  • Android: GET /v1/payment/getGooglePayActivities
  • iOS: GET /v1/payment/getApplePayActivities

4.2 商品字段映射

字段API 字段(客户端映射) 说明
helm code / productId Google Play 商品 ID
warrior activityId 活动 ID用于创建订单
guardian actualAmount 实际金额
curriculum originAmount 原价(带划线)
forge bonus 赠送积分
glossary title 标题

4.3 代码入口

文件:lib/features/recharge/recharge_screen.dart

  • _fetchActivities(): 获取商品列表
  • _onBuy(): 用户点击购买入口

5. 第三方支付流程

5.1 步骤

  1. 获取支付方式: POST /v1/payment/get-payment-methods

    • 参数: warrior (activityId), vambrace (可选,国家)
  2. 弹窗选择: 展示支付方式列表(_PaymentMethodSheet),包含:

    • resource: 支付方式(如 GOOGLEPAY
    • ceremony: 子支付方式
    • name: 显示名称
    • icon: 图标 URL
    • recommend: 是否推荐
  3. 创建订单: POST /v1/payment/createPayment

    • 参数: sentinel, asset(userId), warrior(activityId), resource, ceremony
    • 返回: federation(订单ID), convert(支付URL)
  4. 支付方式分支:

    • Google Pay: 调用 GooglePlayPurchaseService.launchPurchaseAndReturnData() → 调起内购 → 调用 PaymentApi.googlepay() 回调验证
    • 其他方式: 使用 url_launcher 打开 convert 支付链接

5.2 代码位置

  • 入口: recharge_screen.dart_runThirdPartyPayment()
  • 创建订单: _createOrderAndOpenUrl()
  • Google Pay 判断: _isGooglePay()

6. 直接谷歌支付流程

仅 Android且不经过 getPaymentMethodscreatePayment(三方支付关闭时):

  1. 调用 createPaymentresource=GooglePay, ceremony=GooglePay
  2. 调起 Google Play 内购
  3. 回调验证

代码位置

  • recharge_screen.dart_runGooglePay()

7. Google Play 内购统一入口

7.1 核心方法

GooglePlayPurchaseService.launchPurchaseAndReturnData(productId)

  • 调起 Google Play 内购
  • 返回 GooglePayPurchaseResult 包含:
    • orderId: Google 订单号
    • payload.purchaseData: purchaseData用于 merchant
    • payload.signature: 签名(用于 sample
    • purchaseDetails: PurchaseDetails 对象

7.2 回调验证

PaymentApi.googlepay(sample, merchant, federation, asset)

  • sample: 签名
  • merchant: purchaseData
  • federation: 订单ID
  • asset: userId

7.3 核销

GooglePlayPurchaseService.completeAndConsumePurchase(purchaseDetails)

  • 执行 completePurchase
  • 执行 consumePurchaseAndroid

8. 补单机制

8.1 触发时机

  • 进入充值页时调用 GooglePlayPurchaseService.runOrderRecovery()

8.2 补单流程

  1. 获取未核销订单: getUnacknowledgedPurchases()

    • 合并 queryPastPurchasespurchaseStream 的待处理订单
  2. 对每笔订单:

    • 查询本地存储的 federation 映射
    • 若存在 federation: 调用 googlepay 回调 → 成功后 consume
    • 若无 federation: 仅执行 consume 解除「已拥有此内容」
  3. 补单成功后刷新账户

8.3 存储映射

使用 SharedPreferences 存储 googleOrderId → federation 映射:

  • saveFederationForGoogleOrderId()
  • getFederationForGoogleOrderId()
  • removeFederationForGoogleOrderId()

9. API 汇总

接口 方法 说明
/v1/payment/getGooglePayActivities GET 获取 Android 商品列表
/v1/payment/getApplePayActivities GET 获取 iOS 商品列表
/v1/payment/get-payment-methods POST 获取支付方式列表
/v1/payment/createPayment POST 创建支付订单
/v1/payment/getOrderDetail GET 查询订单状态(轮询)
/v1/payment/googlepay POST Google Pay 回调验证

10. 代码文件位置

功能 文件路径
充值页面 lib/features/recharge/recharge_screen.dart
支付 API lib/core/api/services/payment_api.dart
Google Play 内购服务 lib/features/recharge/google_play_purchase_service.dart
支付方式模型 lib/features/recharge/models/payment_method_item.dart
商品模型 lib/features/recharge/models/activity_item.dart
购买结果模型 lib/features/recharge/models/google_pay_purchase_result.dart
WebView 支付页 lib/features/recharge/payment_webview_screen.dart

11. 常见问题

11.1 商品未找到

  • 原因: 客户端 helm (productId) 与 Google Play 后台「产品 ID」不一致
  • 排查: 检查 docs/google_pay_product_not_found.md

11.2 补单

  • 未确认订单可能不会出现在 queryPastPurchases
  • 应用启动时订阅 purchaseStream 接收重新下发
  • 补单会合并两者的待处理订单

12. 注意事项

  • 所有 Google Play 内购统一使用 launchPurchaseAndReturnData() 方法
  • 回调验证成功后必须调用 completePurchase + consumePurchase
  • 支付 URL 打开方式取决于 createPayment 返回的 convert 字段
  • 订单状态轮询: 间隔 1/3/7/15/31/63 秒