From a83c76edabc31e96bca4db26225d47d14b728e7a Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 29 Mar 2026 15:31:51 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=9A=E6=94=AF=E4=BB=98?= =?UTF-8?q?=E8=B5=B0=E5=86=85=E8=B4=AD=E7=9A=84=E9=80=BB=E8=BE=91=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E5=BD=93pay=20URL=E4=B8=BA=E7=A9=BA=E7=9A=84=E6=97=B6?= =?UTF-8?q?=E5=80=99=E6=89=8D=E8=B5=B0=E5=86=85=E8=B4=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/petsHeroAI_client_guide.md | 645 +++++++++++---------- lib/features/recharge/recharge_screen.dart | 84 ++- 2 files changed, 386 insertions(+), 343 deletions(-) diff --git a/docs/petsHeroAI_client_guide.md b/docs/petsHeroAI_client_guide.md index 9693985..bb5d128 100644 --- a/docs/petsHeroAI_client_guide.md +++ b/docs/petsHeroAI_client_guide.md @@ -2,14 +2,14 @@ ## 通用信息 -| 项目 | 值 | -|------|----| -| 加密方式 | AES-128-ECB, PKCS5Padding, Base64 | -| AES Key | `liyP4LkMfP68XvCt` | -| 预发域名 | `pre-ai.petsheroai.xyz` | -| 生产域名 | `ai.petsheroai.xyz` | -| 代理入口 | `POST {baseUrl}/quester/defender/summoner` | -| 包名 | `com.petsheroai.app` | +| 项目 | 值 | +| ------- | ------------------------------------------ | +| 加密方式 | AES-128-ECB, PKCS5Padding, Base64 | +| AES Key | `liyP4LkMfP68XvCt` | +| 预发域名 | `pre-ai.petsheroai.xyz` | +| 生产域名 | `ai.petsheroai.xyz` | +| 代理入口 | `POST {baseUrl}/quester/defender/summoner` | +| 包名 | `com.petsheroai.app` | ## 加密流程 @@ -7087,322 +7087,323 @@ V2 完整响应体 (解密后): ## 错误码 -| code | 说明 | -|------|------| -| 0 | 成功 | -| -1 | 失败 | -| -2 | 系统错误 | -| -3 | 鉴权失败 | -| -5 | 参数错误 | -| 1001 | 积分不足 | -| 1002 | 免费次数已用完 | +| code | 说明 | +| ---- | ----------- | +| 0 | 成功 | +| -1 | 失败 | +| -2 | 系统错误 | +| -3 | 鉴权失败 | +| -5 | 参数错误 | +| 1001 | 积分不足 | +| 1002 | 免费次数已用完 | | 1003 | 免费次数和积分均已用完 | ## 字段映射全表 -| 原始字段 | V2字段 | -|----------|--------| -| User_token | knight | -| accountId | wizard | -| accountName | captain | -| activityId | warrior | -| activitys | summon | -| actualAmount | guardian | -| addCredits | awaken | -| adsTokenId | champion | -| age | transform | -| amount | hero | -| animate | ascend | -| app | sentinel | -| appFbConfig | evolve | -| appType | ranger | -| appraise | unleash | -| approveState | paladin | -| aspectRatio | quest | -| automaticRenewal | legend | -| avatar | realm | -| baseCredits | wield | -| baseUrl | destiny | -| begTime | emblem | -| bonus | forge | -| bonusCredits | conjure | -| bonusRatio | enchant | -| businessId | vanquish | -| businessType | defend | -| campaignInfo | relic | -| card | artifact | -| categoryId | insignia | -| categoryName | patrol | -| ch | crest | -| channel | lineage | -| channelType | armor | -| client | shield | -| clientId | gauntlet | -| code | helm | -| coder | mantle | -| config | charge | -| content | cloak | -| contentType | pauldron | -| count | visor | -| countId | command | -| country | vambrace | -| countryCode | navigate | -| creatTime | explore | -| createTime | discover | -| createTimeText | uncover | -| credit | reveal | -| creditPromotion | unlock | -| credits | greaves | -| creditsRecordUrl | conquer | -| cryptoInvoiceUrl | protect | -| currency | familiar | -| current | empower | -| cvcCode | companion | -| data | sidekick | -| days | species | -| department | inspire | -| desc | valor | -| description | pedigree | -| devId | ancestry | -| deviceId | origin | -| discountOff | lead | -| domain | totem | -| domains | avatar | -| dt | sigil | -| duration | cosmos | -| email | galaxy | -| enabled | nebula | -| endTime | citadel | -| event | fortress | -| expectedSize | stronghold | -| expireMonth | dominion | -| expireYear | sanctuary | -| expiresIn | soar | -| ext | nexus | -| extConfig | surge | -| extJson | vanguard | -| face | dash | -| faceIndex | leap | -| faceInfos | strike | -| face_index | parry | -| feature | dodge | -| features | scout | -| feedbackId | track | -| feedbackIds | registry | -| fileName | layer | -| fileName1 | gateway | -| fileName2 | action | -| filePath | hunt | -| filePath1 | recruit | -| filePath2 | train | -| fileUrls | inventory | -| filterCountry | blueprint | -| filterDomain | vendor | -| filterOwnerId | participant | -| filterStatus | specimen | -| filterTaskType | package | -| filterVip | quotation | -| firstName | appointment | -| firstRegister | equip | -| forcePayCenter | upgrade | -| fps | notification | -| frameIndex | unite | -| frame_index | pledge | -| freeBlurTimes | vow | -| freeTimes | decree | -| gender | venture | -| googleClientId | discourse | -| h5UrlConfig | pursue | -| hasNext | manifest | -| hash | mediation | -| hashIsZero | corpus | -| headFaceIndex | histogram | -| headImg | agent | -| headPos | bond | -| headType | arena | -| hint | traverse | -| host | initiative | -| icon | greylist | -| id | federation | -| imageCount | simplify | -| imageFaceIndex | committee | -| imageId | royalty | -| imageInfos | curate | -| img | revenue | -| imgCount | declaration | -| imgId | criterion | -| imgList | downsample | -| imgType | reconnect | -| imgUrl | reconfigure | -| index | prewarm | -| inviteBy | item | -| invitedCnt | deduce | -| isBlur | reify | -| isVip | generate | -| issuerUrl | merge | -| keepUserId | series | -| label | subscribe | -| lang | seminar | -| lastName | bazaar | -| lastUpdateTime | probe | -| link | festival | -| list | junction | -| maxLimit | architect | -| method | heap | -| methodActivitys | modify | -| methodChannels | restore | -| model | authorization | -| msg | rampart | -| name | brigade | -| needCredits | deserialize | -| needImage | assembly | -| needUndress | directive | -| needopt | allowance | -| negativePrompt | underwriter | -| note | extrapolate | -| openType | transplant | -| optimizeCountSql | harvest | -| optimizeJoinOfCountSql | seek | -| orderId | gazette | -| orders | identify | -| originAmount | curriculum | -| owner | genealogy | -| p12KeyPath | arraignment | -| packageName | folio | -| page | trophy | -| pages | coordinate | -| password | township | -| payCenterUrl | switch | -| payId | assert | -| payMethod | intercept | -| payMethods | wallet | -| payStatus | destroy | -| payTime | restart | -| payTypeList | handshake | -| payUrl | convert | -| paylink | unzip | -| paymentMethod | resource | -| paymentMethods | renew | -| permissions | sandbox | -| phone | block | -| pkg | portal | -| platform | trigger | -| previewImage | extract | -| previewVideo | preempt | -| productType | subtract | -| progress | dice | -| prompt | ledger | -| publicKey | template | -| purchaseData | merchant | -| queueCnt | revert | -| read | redact | -| receipt | attendee | -| recent | entrap | -| recentlyUsed | finalize | -| recommend | deny | -| records | intensify | -| redirectUrl | disambiguate | -| referer | digest | -| refererType | campaign | -| replyStatus | voxelize | -| requiredHeaders | remap | -| resolution | booking | -| resolution480p | reverify | -| resolution720p | preprocess | -| resulotion | theorize | -| rewardCredits | represent | -| rewardRatio | render | -| role | evaluate | -| searchCount | suspend | -| selected | deploy | -| serviceAccountEmail | alert | -| sharedSecret | comment | -| showName | mold | -| sign | resolution | -| signature | sample | -| size | heatmap | -| sort | invent | -| srcFaceImgBase64 | attachment | -| srcFaceIndex | stadium | -| srcImg | refuge | -| srcImg1 | endeavor | -| srcImg1Url | guild | -| srcImg2 | balance | -| srcImg2Url | commission | -| srcImgBase64 | profit | -| srcImgUrl | statute | -| srcVideo | compendium | -| state | listing | -| status | line | -| style | webinar | -| subBusinessType | tailor | -| subPaymentMethod | ceremony | -| subScribeValidTime | tokenize | -| subscriptionActivitys | cleanse | -| subscriptionPeriod | distribute | -| sumCredits | emit | -| sys | associate | -| t2IConfig | regulate | -| tag | constrain | -| tags | rally | -| targetId | node | -| targetInvitedCnt | authorize | -| taskId | tree | -| taskIds | privilege | -| taskType | cipher | -| taskTypes | platoon | -| templateFaceUrl | simulate | -| templateFifCredits | pause | -| templateFifDuration | decommission | -| templateFifUrl | acknowledge | -| templateName | congregation | -| templateTfCredits | pipe | -| templateTfDuration | unwrap | -| templateTfUrl | extend | -| templateType | recharge | -| templateTypes | endowment | -| templateUrl | inject | -| tgId | concession | -| tgName | defer | -| tgOrderId | insurer | -| theme | parallelize | -| title | glossary | -| token | thesis | -| total | weigh | -| totalUnreadCount | defragment | -| transactionId | chronicle | -| truePrompt | deposition | -| ts | quarto | -| type | accolade | -| types | municipality | -| unreadCountList | footprint | -| updateTime | fork | -| uploadUrl | shed | -| uploadUrl1 | bolster | -| uploadUrl2 | expound | -| url | digitize | -| user | rebalance | -| userApplePayList | gallery | -| userId | asset | -| userInfoType | frame | -| userName | terminal | -| userToken | reevaluate | -| userType | prefetch | -| username | pulse | -| usign | retrospect | -| val | journal | -| value | schema | -| verifyCode | supplier | -| videoDuration | demonstrate | -| videoFaceIndex | applicant | -| videoFrameIndex | fragment | -| videoSize | summary | -| videoUrl | promotion | -| waitTime | flowStep | -| x1 | invoke | -| x2 | sync | -| y1 | configure | -| y2 | manufacture | +| 原始字段 | V2字段 | +| ---------------------- | ------------- | +| User\_token | knight | +| accountId | wizard | +| accountName | captain | +| activityId | warrior | +| activitys | summon | +| actualAmount | guardian | +| addCredits | awaken | +| adsTokenId | champion | +| age | transform | +| amount | hero | +| animate | ascend | +| app | sentinel | +| appFbConfig | evolve | +| appType | ranger | +| appraise | unleash | +| approveState | paladin | +| aspectRatio | quest | +| automaticRenewal | legend | +| avatar | realm | +| baseCredits | wield | +| baseUrl | destiny | +| begTime | emblem | +| bonus | forge | +| bonusCredits | conjure | +| bonusRatio | enchant | +| businessId | vanquish | +| businessType | defend | +| campaignInfo | relic | +| card | artifact | +| categoryId | insignia | +| categoryName | patrol | +| ch | crest | +| channel | lineage | +| channelType | armor | +| client | shield | +| clientId | gauntlet | +| code | helm | +| coder | mantle | +| config | charge | +| content | cloak | +| contentType | pauldron | +| count | visor | +| countId | command | +| country | vambrace | +| countryCode | navigate | +| creatTime | explore | +| createTime | discover | +| createTimeText | uncover | +| credit | reveal | +| creditPromotion | unlock | +| credits | greaves | +| creditsRecordUrl | conquer | +| cryptoInvoiceUrl | protect | +| currency | familiar | +| current | empower | +| cvcCode | companion | +| data | sidekick | +| days | species | +| department | inspire | +| desc | valor | +| description | pedigree | +| devId | ancestry | +| deviceId | origin | +| discountOff | lead | +| domain | totem | +| domains | avatar | +| dt | sigil | +| duration | cosmos | +| email | galaxy | +| enabled | nebula | +| endTime | citadel | +| event | fortress | +| expectedSize | stronghold | +| expireMonth | dominion | +| expireYear | sanctuary | +| expiresIn | soar | +| ext | nexus | +| extConfig | surge | +| extJson | vanguard | +| face | dash | +| faceIndex | leap | +| faceInfos | strike | +| face\_index | parry | +| feature | dodge | +| features | scout | +| feedbackId | track | +| feedbackIds | registry | +| fileName | layer | +| fileName1 | gateway | +| fileName2 | action | +| filePath | hunt | +| filePath1 | recruit | +| filePath2 | train | +| fileUrls | inventory | +| filterCountry | blueprint | +| filterDomain | vendor | +| filterOwnerId | participant | +| filterStatus | specimen | +| filterTaskType | package | +| filterVip | quotation | +| firstName | appointment | +| firstRegister | equip | +| forcePayCenter | upgrade | +| fps | notification | +| frameIndex | unite | +| frame\_index | pledge | +| freeBlurTimes | vow | +| freeTimes | decree | +| gender | venture | +| googleClientId | discourse | +| h5UrlConfig | pursue | +| hasNext | manifest | +| hash | mediation | +| hashIsZero | corpus | +| headFaceIndex | histogram | +| headImg | agent | +| headPos | bond | +| headType | arena | +| hint | traverse | +| host | initiative | +| icon | greylist | +| id | federation | +| imageCount | simplify | +| imageFaceIndex | committee | +| imageId | royalty | +| imageInfos | curate | +| img | revenue | +| imgCount | declaration | +| imgId | criterion | +| imgList | downsample | +| imgType | reconnect | +| imgUrl | reconfigure | +| index | prewarm | +| inviteBy | item | +| invitedCnt | deduce | +| isBlur | reify | +| isVip | generate | +| issuerUrl | merge | +| keepUserId | series | +| label | subscribe | +| lang | seminar | +| lastName | bazaar | +| lastUpdateTime | probe | +| link | festival | +| list | junction | +| maxLimit | architect | +| method | heap | +| methodActivitys | modify | +| methodChannels | restore | +| model | authorization | +| msg | rampart | +| name | brigade | +| needCredits | deserialize | +| needImage | assembly | +| needUndress | directive | +| needopt | allowance | +| negativePrompt | underwriter | +| note | extrapolate | +| openType | transplant | +| optimizeCountSql | harvest | +| optimizeJoinOfCountSql | seek | +| orderId | gazette | +| orders | identify | +| originAmount | curriculum | +| owner | genealogy | +| p12KeyPath | arraignment | +| packageName | folio | +| page | trophy | +| pages | coordinate | +| password | township | +| payCenterUrl | switch | +| payId | assert | +| payMethod | intercept | +| payMethods | wallet | +| payStatus | destroy | +| payTime | restart | +| payTypeList | handshake | +| payUrl | convert | +| paylink | unzip | +| paymentMethod | resource | +| paymentMethods | renew | +| permissions | sandbox | +| phone | block | +| pkg | portal | +| platform | trigger | +| previewImage | extract | +| previewVideo | preempt | +| productType | subtract | +| progress | dice | +| prompt | ledger | +| publicKey | template | +| purchaseData | merchant | +| queueCnt | revert | +| read | redact | +| receipt | attendee | +| recent | entrap | +| recentlyUsed | finalize | +| recommend | deny | +| records | intensify | +| redirectUrl | disambiguate | +| referer | digest | +| refererType | campaign | +| replyStatus | voxelize | +| requiredHeaders | remap | +| resolution | booking | +| resolution480p | reverify | +| resolution720p | preprocess | +| resulotion | theorize | +| rewardCredits | represent | +| rewardRatio | render | +| role | evaluate | +| searchCount | suspend | +| selected | deploy | +| serviceAccountEmail | alert | +| sharedSecret | comment | +| showName | mold | +| sign | resolution | +| signature | sample | +| size | heatmap | +| sort | invent | +| srcFaceImgBase64 | attachment | +| srcFaceIndex | stadium | +| srcImg | refuge | +| srcImg1 | endeavor | +| srcImg1Url | guild | +| srcImg2 | balance | +| srcImg2Url | commission | +| srcImgBase64 | profit | +| srcImgUrl | statute | +| srcVideo | compendium | +| state | listing | +| status | line | +| style | webinar | +| subBusinessType | tailor | +| subPaymentMethod | ceremony | +| subScribeValidTime | tokenize | +| subscriptionActivitys | cleanse | +| subscriptionPeriod | distribute | +| sumCredits | emit | +| sys | associate | +| t2IConfig | regulate | +| tag | constrain | +| tags | rally | +| targetId | node | +| targetInvitedCnt | authorize | +| taskId | tree | +| taskIds | privilege | +| taskType | cipher | +| taskTypes | platoon | +| templateFaceUrl | simulate | +| templateFifCredits | pause | +| templateFifDuration | decommission | +| templateFifUrl | acknowledge | +| templateName | congregation | +| templateTfCredits | pipe | +| templateTfDuration | unwrap | +| templateTfUrl | extend | +| templateType | recharge | +| templateTypes | endowment | +| templateUrl | inject | +| tgId | concession | +| tgName | defer | +| tgOrderId | insurer | +| theme | parallelize | +| title | glossary | +| token | thesis | +| total | weigh | +| totalUnreadCount | defragment | +| transactionId | chronicle | +| truePrompt | deposition | +| ts | quarto | +| type | accolade | +| types | municipality | +| unreadCountList | footprint | +| updateTime | fork | +| uploadUrl | shed | +| uploadUrl1 | bolster | +| uploadUrl2 | expound | +| url | digitize | +| user | rebalance | +| userApplePayList | gallery | +| userId | asset | +| userInfoType | frame | +| userName | terminal | +| userToken | reevaluate | +| userType | prefetch | +| username | pulse | +| usign | retrospect | +| val | journal | +| value | schema | +| verifyCode | supplier | +| videoDuration | demonstrate | +| videoFaceIndex | applicant | +| videoFrameIndex | fragment | +| videoSize | summary | +| videoUrl | promotion | +| waitTime | flowStep | +| x1 | invoke | +| x2 | sync | +| y1 | configure | +| y2 | manufacture | ---- -*本文档由 ProtocolEncTool 自动生成,API 变更后请重新执行生成命令。* +*** + +*本文档由 ProtocolEncTool 自动生成,API 变更后请重新执行生成命令。transplant* diff --git a/lib/features/recharge/recharge_screen.dart b/lib/features/recharge/recharge_screen.dart index aead116..bad4dcf 100644 --- a/lib/features/recharge/recharge_screen.dart +++ b/lib/features/recharge/recharge_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_lucide/flutter_lucide.dart'; +import 'package:url_launcher/url_launcher.dart'; import '../../core/adjust/adjust_events.dart'; import '../../core/api/api_config.dart'; @@ -37,6 +38,11 @@ class _RechargeScreenState extends State /// 当前正在支付的商品 code,仅该 item 的 Buy 显示 loading String? _loadingProductId; + + /// 待处理的订单信息,用于系统浏览器返回后触发轮询 + String? _pendingOrderId; + String? _pendingUserId; + double? _pendingPurchaseAmount; @override void initState() { @@ -61,6 +67,23 @@ class _RechargeScreenState extends State mounted) { setState(() => _loadingProductId = null); } + + // 系统浏览器返回后,触发订单轮询 + if (state == AppLifecycleState.resumed && + _pendingOrderId != null && + _pendingUserId != null && + _pendingPurchaseAmount != null && + mounted) { + _startOrderPolling( + orderId: _pendingOrderId!, + userId: _pendingUserId!, + purchaseAmount: _pendingPurchaseAmount!, + ); + // 清空待处理订单信息 + _pendingOrderId = null; + _pendingUserId = null; + _pendingPurchaseAmount = null; + } } Future _fetchActivities() async { @@ -260,32 +283,48 @@ class _RechargeScreenState extends State : null; final orderId = data?['federation']?.toString(); - if (_isGooglePay(paymentMethod, subPaymentMethod)) { + final purchaseAmount = + (AdjustEvents.parsePrice(item.actualAmount) ?? 0).toDouble(); + final payUrl = data?['convert']?.toString(); + final openType = data?['transplant'] as int?; + + if (_shouldUseGooglePay(payUrl)) { await _launchGooglePlayPurchase(item, serverOrderId: orderId, userId: userId); return; } - final purchaseAmount = - (AdjustEvents.parsePrice(item.actualAmount) ?? 0).toDouble(); - final payUrl = data?['convert']?.toString(); if (payUrl != null && payUrl.isNotEmpty) { if (mounted) { setState(() => _loadingProductId = null); - await Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => PaymentWebViewScreen(paymentUrl: payUrl), - ), - ); - if (mounted && orderId != null && orderId.isNotEmpty) { - _startOrderPolling( - orderId: orderId, - userId: userId, - purchaseAmount: purchaseAmount, + + if (_shouldUseSystemBrowser(openType)) { + // 打开系统浏览器 + await launchUrl(Uri.parse(payUrl), mode: LaunchMode.externalApplication); + // 系统浏览器返回后,用户回到应用时会通过 didChangeAppLifecycleState 触发轮询 + _pendingOrderId = orderId; + _pendingUserId = userId; + _pendingPurchaseAmount = purchaseAmount; + _showSnackBar( + context, 'Order created. Complete payment in the browser.'); + } else { + // 打开内置浏览器 + await Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => PaymentWebViewScreen(paymentUrl: payUrl), + ), ); + // 内置浏览器关闭后开启订单轮询 + if (mounted && orderId != null && orderId.isNotEmpty) { + _startOrderPolling( + orderId: orderId, + userId: userId, + purchaseAmount: purchaseAmount, + ); + } + _showSnackBar( + context, 'Order created. Complete payment in the page.'); } - _showSnackBar( - context, 'Order created. Complete payment in the page.'); } } else { if (mounted) { @@ -354,11 +393,14 @@ class _RechargeScreenState extends State poll(0); } - /// ceremony==GooglePay 或 resource==GOOGLEPAY 时走谷歌内购并上报 - static bool _isGooglePay(String paymentMethod, String? subPaymentMethod) { - final r = paymentMethod.trim().toLowerCase(); - final c = (subPaymentMethod ?? '').trim().toLowerCase(); - return r == 'googlepay' || c == 'googlepay'; + /// payUrl 为空时走谷歌内购,有值时走第三方支付 + static bool _shouldUseGooglePay(String? payUrl) { + return payUrl == null || payUrl.isEmpty; + } + + /// 根据 openType 决定打开方式:0=内置浏览器,1=系统浏览器,其他=内置浏览器 + static bool _shouldUseSystemBrowser(int? openType) { + return openType == 1; } /// 三方为 false 时走谷歌应用内支付:先创建订单再调起内购(与第三方选 Google Pay 一致)