7.4 KiB
支付流程(当前实现)
本文档描述充值页「Buy」点击后的完整支付流程,与 recharge_screen.dart、PaymentApi、GooglePlayPurchaseService 实现一致。
1. 流程总览
用户点击 Buy
│
├─ lucky === true 且已登录
│ │
│ ├─ getPaymentMethods(activityId)
│ ├─ 弹窗选择支付方式(_PaymentMethodDialog)
│ ├─ createPayment(activityId, productId, paymentMethod, subPaymentMethod)
│ │
│ ├─ 若选中的是 Google Pay(resource/ceremony == "GooglePay")
│ │ ├─ 调起 Google Play 内购(productId = item.code)
│ │ ├─ 拿到 serverVerificationData
│ │ └─ POST /v1/payment/googlepay(merchant, federation, asset)
│ │
│ └─ 否则(其他支付方式)
│ └─ 打开 createPayment 返回的 payUrl(convert)在外部浏览器完成支付
│
└─ lucky !== true 或未登录
└─ 仅 Android:直接调起 Google Play 内购(productId = item.code),无 createPayment
2. 支付分支依据
- 数据来源:
/v1/user/common_info响应中的 surge(JSON 字符串),解析得到 lucky。 - 客户端状态:
UserState.enableThirdPartyPayment(登录后由 AuthService 从 common_info 写入)。 - 分支:
- 第三方支付:
lucky == true且UserState.userId非空 → 走「获取支付方式 → 弹窗选择 → 创建订单 → 按支付方式分支」。 - 直接谷歌支付:否则(未开三方或未登录)→ 仅 Android 下直接调起 Google Play 内购,不调 getPaymentMethods / createPayment。
- 第三方支付:
3. 支付界面与商品展示
- 界面:
recharge_screen.dart。 - 商品来源:
GET /v1/payment/getGooglePayActivities(Android)或 getApplePayActivities(iOS),列表为 data.summon(activitys)。 - 单条商品字段(V2 映射):
| 字段(映射后) | 说明 |
|---|---|
| helm | 产品代码,即 Google Pay 商品 ID(与 Play 后台「产品 ID」必须一致) |
| warrior | 活动 ID(activityId),getPaymentMethods / createPayment 必传 |
| guardian | 实际金额,界面带 $ 显示 |
| curriculum | 原价,界面中划线显示 |
| forge | 赠送积分,界面展示 |
| glossary | 标题;greaves=积分数,familiar=货币等 |
- 界面规则:价格 / 原价 / 赠送积分同一行展示;仅当前点击的 item 的 Buy 按钮显示 loading(_loadingProductId)。
4. 第三方支付流程(lucky === true)
4.1 步骤顺序
| 步骤 | 说明 |
|---|---|
| 1 | 用户点击某商品的 Buy,得到该商品的 activityId(warrior)、productId(helm/code)。 |
| 2 | POST /v1/payment/get-payment-methods,body:warrior=activityId,vambrace=国家(可选)。 |
| 3 | 弹窗 支付方式列表(renew),用户选择一项 → 得到 resource(paymentMethod)、ceremony(subPaymentMethod)。 |
| 4 | POST /v1/payment/createPayment,body:sentinel, asset(userId), warrior(activityId), resource, ceremony;得到 federation(订单 ID)、convert(payUrl)等。 |
| 5a | 若 resource 或 ceremony 为 "GooglePay"(不区分大小写):调起 Google Play 内购(productId=item.code),成功后用 serverVerificationData 作为 merchant 调用 POST /v1/payment/googlepay(merchant, federation, asset),不打开 payUrl。 |
| 5b | 否则:若有 convert(payUrl)则用 url_launcher 在外部浏览器打开;无则仅提示订单已创建。 |
4.2 支付方式弹窗
- 在 get-payment-methods 成功后,展示 Select payment method 弹窗(_PaymentMethodDialog),列表项来自 renew(PaymentMethodItem:resource, ceremony, name, icon, recommend 等)。
- 用户选择一项后关闭弹窗,用选中的 resource、ceremony 调用 createPayment;取消弹窗则不创建订单并清除 loading。
4.3 选中 Google Pay 时的子流程
- 条件:
_isGooglePay(paymentMethod, subPaymentMethod)为 true(即 paymentMethod 或 subPaymentMethod 转为小写后等于"googlepay")。 - 仅 Android 执行;非 Android 提示 "Google Pay is only available on Android" 并结束。
- 调用 GooglePlayPurchaseService.launchPurchaseAndReturnData(productId)(所有内购统一使用):
- productId 为当前商品的 code(helm)。
- 成功返回 serverVerificationData(merchant),失败/取消返回 null。
- 若有 merchant 且订单 ID(federation)存在,调用 PaymentApi.googlepay(merchant, federation, asset);根据返回提示成功或失败并打点(AdjustEvents)。
5. 直接谷歌支付(lucky !== true)
- 仅 Android:调用 GooglePlayPurchaseService.launchPurchaseAndReturnData(item.code),不请求 getPaymentMethods / createPayment;凭据可用于后续服务端回调。
- 成功/失败通过 SnackBar 与 AdjustEvents 打点;商品 ID 仍为 item.code(须与 Play 后台产品 ID 一致)。
- 非 Android:提示 "Google Pay is only available on Android"。
6. 接口与字段速查
-
GET /v1/payment/getGooglePayActivities
Query:sentinel, portal;响应 data.summon / data.cleanse,单项含 helm, warrior, guardian, curriculum, forge 等。 -
POST /v1/payment/get-payment-methods
Body:warrior(activityId), vambrace(可选)。响应 data.renew:每项 resource, ceremony, brigade, greylist, deny 等。 -
POST /v1/payment/createPayment
Query:sentinel, asset(userId)。Body:sentinel, asset, warrior, resource, ceremony(可选)。
响应 data:federation(订单ID), convert(payUrl), destroy(状态), handshake, transplant 等。 -
POST /v1/payment/googlepay
Query:sentinel, asset(userId)。Body:merchant(购买凭据 serverVerificationData), federation(订单ID), asset, sample(签名可选)。
响应 data:federation, line(状态), awaken(是否加积分) 等。 -
请求/响应 V2 加解密与字段映射以 petsHeroAI_client_guide.md 为准。
7. 代码与文档对应
| 功能 | 位置 |
|---|---|
| 支付分支与 Buy 入口 | recharge_screen.dart:_onBuy → enableThirdPartyPayment ? _runThirdPartyPayment : _runGooglePay |
| 第三方:获取支付方式 + 弹窗 | _runThirdPartyPayment:PaymentApi.getPaymentMethods → _PaymentMethodDialog |
| 第三方:创建订单 + Google Pay / 打开链接 | _createOrderAndOpenUrl:createPayment → _isGooglePay ? launchPurchaseAndReturnData + googlepay : launchUrl(convert) |
| 直接谷歌支付 | _runGooglePay → _launchGooglePlayPurchase → GooglePlayPurchaseService.launchPurchaseAndReturnData |
| 谷歌内购 + 凭据上报 | google_play_purchase_service.dart:launchPurchaseAndReturnData;PaymentApi.googlepay |
| 商品未找到排查 | docs/google_pay_product_not_found.md |
8. 小结
- 三方开:getPaymentMethods → 弹窗选支付方式 → createPayment → 选 Google Pay 则内购 + googlepay 回调,否则打开 payUrl。
- 三方关:仅 Android 直接内购(item.code),无 createPayment。
- 商品 ID:始终使用接口返回的 helm(item.code),须与 Google Play 后台「产品 ID」完全一致,否则会出现「系统无法找到您要购买的商品」。