跳转到内容

支付(SuperSDK.pay namespace)

SDK 提供应用内支付桥接能力 · H5 通过 SuperSDK.pay.* 调用。

🔴 F038 破坏式变更(继 F036 后第二次):pay.purchase 返回从 F036 的 PurchaseResult 凭证对象改为 PayResult3State 三态对象。统一为「provider.createOrder → provider.pay → 三态回调」契约;凭证不再经 H5 业务 JS(由 SDK Native PayBridge 直投后端回执端点)。现网 H5 必须配套升级(无兼容期 · 无 alias)。详见下方 F038 迁移指南。

🔴 SDK 是哑管道(v0.3 设计原则):provider = 两个方法 { createOrder(payParams)→json, pay(json)→三态 }。createOrder 产出的 json 对 SDK 完全不透明 —— SDK 不解析其中任何字段(productId / accountId / profileId / orderToken 都不碰),只按 provider 名路由、把 json 原样透传给 pay。字段语义由 provider 实现方(createOrder 产出 ↔ pay 消费)自洽保障。

业务方前提(必读): 本能力假定业务方已具备服务端主导 IAP 架构:

  • 创单 / 凭证验签(verify) / acknowledge / consume / 查单:全部由业务后端实现(调 Google Play Developer API + App Store Server API)· SDK 不提供
  • SDK 仅负责 ① 按 provider 名路由 + 把 createOrder 产出的不透明 json 透传给 pay ② 内置 google_play / 宿主 Apple provider 的原生扣款 ③ 由 Native PayBridge 把凭证直投后端回执端点(凭证不出 Native)④ 回调白名单三态 ⑤ 探测能力 ⑥ 客户端 restore(可选)
  • 详细架构见下方 IAP 推荐架构章节(v0.3 已重写)

⚠️ Apple Guideline 3.1.1 合规提醒:订阅 / 非消耗型商品 App 必须提供 “Restore Purchases” 按钮。可走 SDK pay.restorePurchases(provider 不实现时返回 NOT_SUPPORTED · 业务方 fallback 到业务后端 /api/pay/my-purchases)。漏做审核会 reject。

查询 Google Play 当前账号此刻可购买的订阅 offers。数据只来自客户端 queryProductDetailsAsync(ProductType.SUBS) 返回的 SubscriptionOfferDetails;SDK 不查询 Play Console 完整目录、不读 Settings、不合并业务文案,也不负责 UI 排序。

const offers = await SuperSDK.pay.querySubscriptionOffers({
provider: 'google_play',
productIds: ['matrixvplan01']
});
// 普通 base plan 的 offerId 明确为 null
// offerToken 永远不会暴露给 H5
console.log(offers[0]);
// {
// productId: 'matrixvplan01',
// basePlanId: 'weekly01',
// offerId: null,
// offerTags: [],
// title: 'Go VPN',
// description: '...',
// pricingPhases: [{
// formattedPrice: 'US$2.69',
// currencyCode: 'USD',
// priceAmountMicros: 2690000,
// billingPeriod: 'P1W',
// billingCycleCount: 0,
// recurrenceMode: 1
// }]
// }
参数类型必填说明
options.providerstring否单 provider 可省;Google 内置名为 google_play
options.productIdsstring[]是非空订阅 product ID 列表

返回 Promise<SubscriptionOffer[]>。同一 base plan 可以返回多条当前 eligible offer;Play 未向当前账号返回的促销不会被 SDK 拼接出来。Android 支持;iOS 明确返回 NOT_SUPPORTED。

查询错误会 reject:PRODUCT_NOT_FOUND(请求商品均未返回)、BILLING_UNAVAILABLE(Billing 服务不可用)、QUERY_FAILED(其他查询失败)、SDK_TOO_OLD(Native 尚无该 JSB)或 NOT_IN_APP。

唯一支付入口。内部聚合 provider.createOrder → provider.pay 两段(公共面仍仅此一个入口 · 不新增 createAndPay)。

执行编排(v0.3 哑管道):

校验 payConfig(SDK 仅校验 payConfig/payParams 是对象 · 不碰业务字段)
→ json = provider.createOrder(payParams) [provider 实现 · 缺省=identity 透传 payParams]
→ provider.pay(json) [IAP=SDK 内置原生自读 json · 三方=业务 JS 自写]
→ 回调三态 PayResult3State { status: finished | cancelled | error }
// IAP(provider 注册 createOrder-only override · pay 走 SDK 内置原生 · 见 registerProvider)
const result = await SuperSDK.pay.purchase({
provider: 'google_play', // 🔴 内置 Google provider 名(非 'google')· 以 getProviders() 返回为准 · 单 Provider 可省
payParams: { // createOrder 入参 · 由你的 createOrder 消费 · SDK 不解析
productId: 'sku_premium',
userId: currentUser.id
}
});
// result 是三态对象 PayResult3State(不是凭证!)
switch (result.status) {
case 'finished': // 平台已受理 ≠ 支付成功 · 去业务查单定真相 · 不在客户端发货
pollBusinessOrder(result.orderToken);
break;
case 'cancelled': // 用户取消
break;
case 'error': // 失败 · result.phase('create'|'pay') + result.code
console.error(result.phase, result.code, result.message);
break;
}

三方支付 inline 模式(无需 registerProvider · 单次性 · 两方法都内联):

const result = await SuperSDK.pay.purchase({
payParams: { productId: pkg.id, userId: uid },
createOrder: async (payParams) => { // 可选 · 产出对 SDK 不透明的 json(你的 pay 自己消费)
const res = await myApi.createOrder(payParams);
return { prepayId: res.prepay_id, orderToken: res.order_token };
},
pay: async (json) => { // 必填(inline) · 自行 checkout + 轮询 · 返回三态
// json 是你 createOrder 产出的对象(orderToken 是你自己产的 · 当场就持有 · 无需 SDK 回传)
const { payUrl } = await myApi.checkout(json.prepayId);
window.open(payUrl, '_blank');
const status = await pollChannel(json.orderToken); // 业务自实现轮询
if (status === 'completed') return { status: 'finished', orderToken: json.orderToken };
if (status === 'cancelled') return { status: 'cancelled' };
return { status: 'error', phase: 'pay', code: status, orderToken: json.orderToken };
}
});

payConfig 参数:

参数类型必填说明
providerstring否支付方式名(单 Provider 自动选 · 多 Provider 必填)· 以 getProviders() 返回为准
payParamsobject是createOrder 入参 · 任意对象(SDK 仅校验是对象 · 字段由你的 createOrder 消费 · SDK 不解析)
createOrderfunction否inline 模式 · (payParams) => Promise<json> · 缺省时 json=payParams(identity 透传)
payfunction否inline 模式 · (json) => Promise<PayResult3State> · 有此则走 inline JS provider;无此则走内置原生 IAP

🔴 删除 v0.2 的 onOrderCreated / checkout / queryStatus / pollInterval / maxPolls / onProgress:v0.3 哑管道下,这些都是 provider 自己实现的事(三方在自己的 pay 里 checkout+轮询;orderToken 是业务 createOrder 自己产的 · 当场持有 · 无需 SDK 回调还给业务)。

输入契约(无法开始 → reject):

仅「无法开始」reject(INVALID_PARAMS / NOT_IN_APP / SDK_TOO_OLD / PURCHASE_IN_PROGRESS / PROVIDER_REQUIRED / NO_PROVIDER);已开始流程的终态(create/pay 失败、取消、结束)一律 resolve 三态。

输入行为
pay.purchase(undefined/null/'x')reject INVALID_PARAMS · err.detail: “payConfig must be object”
pay.purchase({}) 或 payParams 非对象reject INVALID_PARAMS · err.detail: “payParams must be object”
Native 路径但非端环境reject NOT_IN_APP
Native 路径但老 SDK 无 appbridge.nativePayreject SDK_TOO_OLD(明示升级 · 不静默 fallback 老 purchase)
多 Provider 不传 providerreject PROVIDER_REQUIRED
无任何 providerreject NO_PROVIDER
一笔 inline 进行中再调reject PURCHASE_IN_PROGRESS

🔴 v0.3 不再校验 productId:SDK 不碰业务字段。productId 缺失/类型错由 provider 自己处理(内置 google_play 的 pay 读不到 productId → 返回 phase:'pay' error)。

返回值:Promise<PayResult3State> — 统一三态对象(IAP 与三方路径返回结构一致 · 由 Native PayBridge 白名单构造):

字段类型必填说明
statusenum是finished / cancelled / error
phaseenumerror 时create(createOrder 阶段失败 · 在 JSSDK 内捕获 · 未调 pay) / pay(pay 阶段平台计费错误)
codestringerror 时平台错误码映射(如 BILLING_UNAVAILABLE / CREATE_FAILED)
messagestring否调试信息(非敏感)
orderTokenstring否provider 从其 pay 内部结果回带的关联键(唯一业务键 · 供 H5 查单)

🔴 闭合白名单(凭证不出 Native):发给 H5 的对象只含上表字段,由 Native PayBridge 显式构造 —— 不把 provider 内部结果原样透传。purchaseToken / signature / originalJson 等凭证绝不到达 H5(由 PayBridge 投回执端点)。

🔴 finished ≠ 支付成功:语义为「客户端流程正常结束 · 去查单」。Google PENDING(现金/家长 Ask-to-Buy/慢速支付)与 iOS 等价待定态映射为 finished;Google ITEM_ALREADY_OWNED 也映射为 finished(去查单 · 后端对账补发)而非 error。H5 一律以业务查单结果判定成功/待定/失败 · 不在客户端发货/解锁(见下方业务查单四态) 。

探测宿主支持的支付方式列表(合并 JS 注册的 + Native 注册的)。

const providers = await SuperSDK.pay.getProviders();
// 例如:['google_play', 'alipay'] ← 实际值以本方法返回为准

🔴 provider 名以 pay.getProviders() 返回为准 · 不要硬编码。内置 Google provider 注册名是 'google_play'(GooglePayProvider.getProviderName() 硬编码 · 不是 'google')。iOS 无内置支付 provider · Apple 的 provider 名由宿主 ApplePayProvider 实现时自定义。推荐先调 getProviders() 拿返回值再传给 purchase / registerProvider,避免硬编码错名导致 PROVIDER_NOT_FOUND。下文示例为说明清晰用 'google_play' 字面量,生产代码应用 getProviders() 的返回值。

注册支付 Provider。v0.3 起 provider = 两个方法 { createOrder?, pay? }(至少有一个)· 由 pay 是否存在决定路由:

形态 A · 三方支付(支付宝 / 微信 / Stripe 等非 IAP):有 pay(可附 createOrder)。pay 自行 checkout + 轮询 · 返回三态。

SuperSDK.pay.registerProvider('alipay', {
createOrder: async (payParams) => { // 可选 · 产出对 SDK 不透明的 json(你的 pay 消费)
const res = await myApi.createOrder(payParams);
return { prepayId: res.prepay_id, orderToken: res.order_token };
},
pay: async (json) => { // 必填(三方) · 自行拉起渠道 + 轮询 · 返回 PayResult3State
const { payUrl } = await myApi.checkout(json.prepayId);
window.open(payUrl, '_blank');
const status = await pollChannel(json.orderToken); // 业务自实现
if (status === 'completed') return { status: 'finished', orderToken: json.orderToken };
if (status === 'cancelled') return { status: 'cancelled' };
return { status: 'error', phase: 'pay', code: status, orderToken: json.orderToken };
}
});

形态 B · IAP createOrder override(内置 Google = 'google_play' / 宿主 Apple provider 名见 getProviders()):仅 createOrder(无 pay)· pay 走 SDK 内置原生扣款(appbridge.nativePay)。用于让 IAP 的 createOrder 产出你约定的 json(供内置原生 pay 自读)。

🔴 注册名必须与内置/宿主 provider 名完全一致(内置 Google 是 'google_play',不是 'google')· 否则 purchase 时 PROVIDER_NOT_FOUND。建议用 (await SuperSDK.pay.getProviders()) 的返回值作 name,不要硬编码。

const [googleName] = (await SuperSDK.pay.getProviders())
.filter(n => n === 'google_play'); // 取真实内置名 · 不硬编码
SuperSDK.pay.registerProvider(googleName /* 'google_play' */, {
createOrder: async (payParams) => {
// 业务自行 fetch 创单端点建单 · 返回内置 google_play provider 的 pay 输入 json(见下「google provider 输入键」)
const res = await myApi.createOrder(payParams); // 🔴 后端创单端点签发 UUID orderToken
return {
productId: payParams.productId, // 必填
productType: payParams.productType ?? 'inapp', // 'inapp'(默认)或'subs'
basePlanId: payParams.basePlanId, // productType='subs'时必填
offerId: payParams.offerId, // 订阅优惠可选;省略时购买 base plan
accountId: payParams.accountId, // 可选 → obfuscatedAccountId(用户标识)
profileId: res.order_token // 可选 → obfuscatedProfileId(订单标识)· 🔴 必须 UUID
};
}
// 无 pay → SDK 内置 google_play 原生 pay 消费上面的 json(SDK 不解析 · 由内置 provider.pay 自读)
});

🔴 orderToken 必须 UUID(profileId / iOS appAccountToken 同值):若纯前端生成,用 crypto.randomUUID();若后端签发,后端创单端点须返回 UUID 形态。非 UUID → 内置 google_play / iOS host provider 返回 { phase:'pay', code:'INVALID_ORDER_TOKEN' }。

// 前端生成 orderToken 示例(无后端创单时)
createOrder: async (payParams) => ({
productId: payParams.productId,
profileId: crypto.randomUUID() // 🔴 UUID · 双端(Android obfuscatedProfileId / iOS appAccountToken)通吃
})

provider 字段:

字段形态说明
createOrderA 可选 / B 必填(payParams) => Promise<json> · 产出对 SDK 不透明的 json · 缺省=identity(json=payParams)
payA 必填 / B 无(json) => Promise<PayResult3State> · 有它=三方 JS pay;无它=内置原生 IAP pay

🔴 provider 契约(v0.3 哑管道):pay.purchase 内部 json = createOrder(payParams) → pay(json)。SDK 不解析 json 任何字段(productId/accountId/profileId/orderToken 都不碰)· 由 provider 实现方(createOrder 产出 ↔ pay 消费)自洽保障。

google provider 输入键(文档化 · 非 SDK 传输层):内置 google_play 的 pay 自读 json:productId(必填)、productType(可选,'inapp' 默认值或 'subs')、basePlanId(subs 必填)、offerId(subs 可选)、accountId(可选 → obfuscatedAccountId)、profileId(可选 → obfuscatedProfileId)。订阅只从 Google 返回的用户可用 SubscriptionOfferDetails 中精确匹配 basePlanId + offerId;不传 offerId 时匹配该 base plan 自身的 offer,不会静默回退到其他优惠。无匹配返回 OFFER_UNAVAILABLE。这是 google provider 的输入契约(谁 override 其 createOrder 就照此产)· 不是 SDK 传输层契约。宿主 Apple provider 自定义其 pay 输入键。

未 override createOrder 的纯 IAP:provider 既未注册 createOrder、payConfig 也无 createOrder → SDK 用 identity(json=payParams)· 即 payParams 直接作内置 pay 的输入(payParams 须自带 google provider 输入键)。

客户端恢复购买 · 走 Native PayService.restorePurchases · provider 可选实现。

🔵 F038 不改本契约:restorePurchases 仍返回 F036 的 PurchaseResult[](客户端 StoreKit/BillingClient 凭证恢复)· 与 purchase 的「三态 + 凭证回执直投」属不同路径(restore 是客户端凭证恢复 · 不走回执直投)。统一化留后续 Feature(已知不一致)。

Google 订阅约束:内置 google_play provider 的 restore 仅查询 ProductType.SUBS,不返回一次性商品。

try {
// provider 名以 getProviders() 返回为准:内置 Google 是 'google_play';iOS Apple 名由宿主注册
const purchases = await SuperSDK.pay.restorePurchases({ provider: 'apple' /* 宿主注册名 · 以 getProviders() 为准 */ });
// purchases: [{ orderId, purchaseToken, productId, purchaseState }]
} catch (e) {
if (e.message === 'NOT_SUPPORTED') {
// provider 未实现 restore · fallback 业务后端
const res = await fetch('/api/pay/my-purchases?userId=' + userId);
const purchases = await res.json();
} else if (e.message === 'PROVIDER_NOT_FOUND') {
// 错误的 provider 名
}
}
参数类型必填说明
options.providerstring否单 Provider 时可省 · 多 Provider 必填

返回值:Promise<Object[]> — 购买记录数组,每个元素结构同 pay.purchase 的 Native IAP 返回对象(含 orderId / productId / purchaseToken / purchaseTime / purchaseState / isAcknowledged / signature / originalJson / provider / raw)。无可恢复购买时返回空数组 []。

F038 pay.purchase 的失败分两类:reject 的 code(无法开始 · e.message)与 error 三态的 code(已开始的支付阶段失败 · result.code + result.phase)。

reject code(无法开始 · pay.purchase 抛出):

code含义建议处理
INVALID_PARAMS入参错误(payConfig/payParams 非对象)· err.detail 含具体字段检查传入参数
NOT_IN_APPNative 路径但非端环境检查 isInApp()
SDK_TOO_OLD老 SDK 无 appbridge.nativePay(F038 统一支付需 SDK 升级)升级宿主 SDK
PROVIDER_REQUIRED多 Provider 时未指定传入 provider 参数
NO_PROVIDER无任何 provider 可用提示宿主未实现支付
PURCHASE_IN_PROGRESS有 inline 购买正在进行中等待当前购买完成

error 三态 code(result.status==='error' · 带 phase):

codephase含义建议处理
CREATE_FAILEDcreatecreateOrder reject/throw(在 JSSDK 内捕获 · 未调 pay)提示重试(未拉起 · 可安全重发)
INVALID_JSONcreatecreateOrder 产出的 json 无法 JSON 序列化(IAP 路径)检查 createOrder 产出对象
INVALID_PARAMSpay内置 google_play 缺少 productId / 订阅缺少 basePlanId / productType 非 inapp/subs修正 Google provider 输入键
INVALID_ORDER_TOKENpayprovider 校验输入契约:orderToken(profileId / appAccountToken)非 UUID 格式(内置 google_play 与 iOS host provider 均会返回此 code)createOrder 产 orderToken 时用 crypto.randomUUID()(后端创单端点亦同)
PRODUCT_NOT_FOUNDpay购买前重查后未找到所选订阅商品刷新 eligible offer 列表
OFFER_UNAVAILABLEpay内置 google_play 返回的用户可用订阅 offer 中没有匹配的 basePlanId + offerId刷新商品配置,确认用户资格及 Play Console base plan/offer
BILLING_UNAVAILABLEpay订阅查询或购买时 Google Billing 服务不可用稍后重试
QUERY_FAILEDpay订阅购买前查询失败(非 Billing unavailable)稍后重试并保留原选择
PURCHASE_FAILEDpay订阅 Billing UI 拉起或购买回调失败展示错误并允许重试
FAILED / EXPIRED / CANCELLED…pay三方 provider 的 pay 自定义返回的 code(业务自定)按业务语义处理
BILLING_UNAVAILABLE / SERVICE_UNAVAILABLE / DEVELOPER_ERROR / ITEM_UNAVAILABLE / NO_ACTIVITY / ERROR …pay内置 IAP provider.pay 平台计费错误(映射自 BillingResponseCode / StoreKit Error)展示错误信息

🔴 注意:cancelled 不在 error 列(单独是 status==='cancelled');PENDING / ITEM_ALREADY_OWNED 也不是 error(归 finished · 去查单 · 见下方架构章节)。phase:'pay' 的具体 code 由 provider.pay 返回(IAP=SDK 内置映射;三方=业务自定),SDK 不收敛枚举(哑管道)。

finished ≠ 支付成功。SDK 不提供查单 API(与支付通道解耦)。H5 用 orderToken 轮询业务自有查单接口判定真实结果。业务查单接口约定返回四态:

status含义H5 处理
success后端已验签 + 发货完成解锁 / 提示成功
processing受理中(SDK 回执未达 / RTDN 未达 / 重试中)继续轮询(自定间隔/上限)
failed后端判定失败(验签不过 / 退款 / 平台拒绝)提示失败
unknown暂不确定(超轮询上限仍未定)留后台兜底(RTDN/ASSN 终会落地)· 不在客户端发货
async function pollBusinessOrder(orderToken, maxPolls = 6, interval = 2000) {
for (let i = 0; i < maxPolls; i++) {
const { status } = await fetch('/api/pay/order-status?orderToken=' + orderToken).then(r => r.json());
if (status === 'success' || status === 'failed') return status;
await new Promise(r => setTimeout(r, interval));
}
return 'unknown'; // 超上限仍未定 · 依赖后端 RTDN/ASSN 兜底
}

凭证已由 SDK Native(PayBridge)直投后端回执端点 · 后端独立验签发货。即使前端被杀,RTDN/ASSN 兜底也能让订单最终落地 success(见凭证回执直投契约 PayBridge 守门)。

let PAY_PROVIDER; // 真实 provider 名 · 来自 getProviders() · 不硬编码
async function init() {
// 1. 探测能力(provider 名以此返回为准 · 内置 Google 为 'google_play')
const providers = await SuperSDK.pay.getProviders();
if (providers.length === 0) return;
PAY_PROVIDER = providers[0]; // 或按业务挑选 · 如 providers.find(n => n === 'google_play')
// 2. 给 IAP provider 注册 createOrder override(可选 · 让 createOrder 产出 google provider 输入键)
SuperSDK.pay.registerProvider(PAY_PROVIDER, {
createOrder: async (payParams) => {
const res = await fetch('/api/pay/create-order', { // 业务创单(后端签发 UUID orderToken · 你当场持有)
method: 'POST', body: JSON.stringify(payParams)
}).then(r => r.json());
// ⬇️ google provider 输入键;订阅还需 productType='subs' + basePlanId,offerId 可选
return {
productId: payParams.productId,
productType: payParams.productType ?? 'inapp',
basePlanId: payParams.basePlanId,
offerId: payParams.offerId,
accountId: res.accountId,
profileId: res.orderToken // 🔴 UUID
};
}
});
}
async function buyProduct(productId, userId) {
// 3. 发起购买(SDK 内部 createOrder→pay · 返回三态)
const result = await SuperSDK.pay.purchase({
provider: PAY_PROVIDER, // 🔴 用 getProviders() 返回值 · 勿硬编码 'google'(内置实为 'google_play')
payParams: { productId, userId } // 任意对象 · 由你的 createOrder 消费 · SDK 不解析
});
// 4. 按三态分支
switch (result.status) {
case 'finished': // ≠ 成功 · 去查单(orderToken 由 provider 内部回带)
const orderStatus = await pollBusinessOrder(result.orderToken);
if (orderStatus === 'success') unlockEntitlement();
else if (orderStatus === 'failed') showFailed();
else showPending(); // processing / unknown
break;
case 'cancelled': // 用户取消 · 静默
break;
case 'error': // 失败 · phase + code
if (result.phase === 'create') showRetry(); // createOrder 失败 · 未拉起 · 可安全重发
else console.error('支付失败:', result.code, result.message);
break;
}
// 🔴 凭证不经 H5:purchaseToken/signature 等由 SDK Native(PayBridge)直投后端回执端点 · H5 不再 POST /verify
}
async function restoreUserPurchases(userId) {
try {
// 5. 客户端 restore(Apple Guideline 3.1.1 必需 · F038 契约不变 · 返回 PurchaseResult[])
return await SuperSDK.pay.restorePurchases({ provider: PAY_PROVIDER });
} catch (e) {
if (e.message === 'NOT_SUPPORTED') {
const res = await fetch('/api/pay/my-purchases?userId=' + userId);
return await res.json();
}
throw e;
}
}

F038 迁移指南(从 F036 PurchaseResult 迁到三态)

Section titled “F038 迁移指南(从 F036 PurchaseResult 迁到三态)”

🔴 破坏式变更(继 F036 后第二次):pay.purchase 返回从 PurchaseResult 凭证对象改为 PayResult3State 三态对象;凭证不再经 H5;JSB 由位置参数改为通用 nativePay(provider, jsonString, callbackId)。现网 H5 必须配套升级(无 alias · 无兼容期)。restorePurchases 不变(仍 F036 PurchaseResult[])。

F036 写法F038 后行为迁移路径
const r = await pay.purchase(...)
r.purchaseToken / r.orderId / r.signature
r 不再含凭证(三态对象)删除「读凭证 + POST /verify」逻辑;改为读 r.status(finished/cancelled/error)
if (r.purchaseState===0) ...(凭证判成功)r.purchaseState 不存在改为 r.status==='finished' → 用 orderToken 查单定真相
try/catch 捕 CANCELLED取消不再 reject改为 r.status==='cancelled' 分支
try/catch 捕支付失败支付阶段失败不再 reject(归三态 error)改为 r.status==='error' + r.phase/r.code;reject 仅剩「无法开始」(INVALID_PARAMS/NOT_IN_APP/SDK_TOO_OLD/PURCHASE_IN_PROGRESS/PROVIDER_REQUIRED/NO_PROVIDER)
H5 POST /api/pay/verify(凭证)凭证不经 H5删除;凭证由 SDK Native(PayBridge)直投宿主配置的回执端点 · H5 改为轮询业务查单接口
(无)需要订单关联—注册 createOrder override · 产出 google provider 输入键(orderToken→profileId);orderToken 是你 createOrder 自己产的 · 当场持有 · 无需 SDK 回调

🔴 不留兼容包袱:F038 直接改三态返回 · 不提供 PurchaseResult 旧返回 alias · 不留兼容期。CHANGELOG 标 BREAKING CHANGE。