-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Google billing interface uses promises #17996
Conversation
✅ Package size is not changedInterface Check Report! WARNING this pull request has changed these public interfaces:
@@ -72731,9 +72731,9 @@
/**
* @en Code returned in In-app Billing API calls.
* @zh 应用内结算 API 调用中返回的响应代码。
*/
- readonly responseCode: string;
+ readonly responseCode: number;
readonly toStr: string;
}
export interface __types_jsb_jsb__BillingConfig {
/**
@@ -73053,9 +73053,9 @@
/**
* @en Code returned in In-app Billing API calls.
* @zh 应用内结算 API 调用中返回的响应代码。
*/
- readonly responseCode: string;
+ readonly responseCode: number;
readonly toStr: string;
}
/**
* @en Represents the offer details to buy an one-time purchase product.
@@ -73495,32 +73495,15 @@
export let onExternalOfferInformationDialogResponse: (result: __types_jsb_jsb__BillingResult) => void | undefined;
export let onInAppMessageResponse: (result: __types_jsb_jsb__InAppMessageResult) => void | undefined;
}
/// <reference types="./@types/jsb" />
- export interface _vendor_google_billing_billing__BillingEventMap {
- [google.BillingEventType.BILLING_SETUP_FINISHED]: (result: google.BillingResult) => void;
- [google.BillingEventType.BILLING_SERVICE_DISCONNECTED]: () => void;
- [google.BillingEventType.PRODUCT_DETAILS_RESPONSE]: (result: google.BillingResult, productDetailsList: google.ProductDetails[]) => void;
- [google.BillingEventType.PURCHASES_UPDATED]: (result: google.BillingResult, purchases: google.Purchase[]) => void;
- [google.BillingEventType.CONSUME_RESPONSE]: (result: google.BillingResult, purchaseToken: string) => void;
- [google.BillingEventType.ACKNOWLEDGE_PURCHASES_RESPONSE]: (result: google.BillingResult) => void;
- [google.BillingEventType.QUERY_PURCHASES_RESPONSE]: (result: google.BillingResult, purchases: google.Purchase[]) => void;
- [google.BillingEventType.BILLING_CONFIG_RESPONSE]: (result: google.BillingResult, config: google.BillingConfig) => void;
- [google.BillingEventType.ALTERNATIVE_BILLING_ONLY_TOKEN_RESPONSE]: (result: google.BillingResult, alternativeBillingOnlyReportingDetails: google.AlternativeBillingOnlyReportingDetails) => void;
- [google.BillingEventType.EXTERNAL_OFFER_REPORTING_DETAILS_RESPONSE]: (result: google.BillingResult, externalOfferReportingDetails: google.ExternalOfferReportingDetails) => void;
- [google.BillingEventType.ALTERNATIVE_BILLING_ONLY_AVAILABILITY_RESPONSE]: (result: google.BillingResult) => void;
- [google.BillingEventType.EXTERNAL_OFFER_AVAILABILITY_RESPONSE]: (result: google.BillingResult) => void;
- [google.BillingEventType.ALTERNATIVE_BILLING_ONLY_INFORMATION_DIALOG_RESPONSE]: (result: google.BillingResult) => void;
- [google.BillingEventType.EXTERNAL_OFFER_INFORMATION_DIALOG_RESPONSE]: (result: google.BillingResult) => void;
- [google.BillingEventType.IN_APP_MESSAGE_RESPONSE]: (result: google.InAppMessageResult) => void;
- }
export class _vendor_google_billing_billing__Billing {
constructor();
/**
* @en Starts up BillingClient setup process asynchronously.
* @zh 异步启动 BillingClient 设置过程。
*/
- startConnection(): void;
+ startConnection(): Promise<google.BillingResult>;
/**
* @en Closes the connection and releases all held resources such as service connections.
* @zh 关闭连接并释放所有持有的资源,例如服务连接。
*/
@@ -73543,60 +73526,60 @@
* @param productId @zh 产品ID。 @en product id.
* @param productType @zh 产品类型。 @en product type.
*
*/
- queryProductDetailsParams(productId: string[], productType: google.ProductType): void;
+ queryProductDetailsParams(productId: string[], productType: google.ProductType): Promise<google.ProductDetails[]>;
/**
* @en Initiates the billing flow for an in-app purchase or subscription.
* @zh 启动应用内购买或订阅的计费流程。
* @param productDetails @zh 产品详情。 @en product details.
* @param selectedOfferToken @zh 选择提供的token。 @en selected offer token.
*/
- launchBillingFlow(productDetails: google.ProductDetails[], selectedOfferToken: string | null): void;
+ launchBillingFlow(productDetails: google.ProductDetails[], selectedOfferToken: string | null): Promise<google.Purchase[]>;
/**
* @en Consumes a given in-app product.
* @zh 消费指定的应用内产品。
* @param purchase @zh 已经购买的产品。 @en Purchased Products.
*/
- consumePurchases(purchase: google.Purchase[]): void;
+ consumePurchases(purchase: google.Purchase[]): Promise<string>;
/**
* @en Acknowledges in-app purchases.
* @zh 确认应用内购买。
* @param purchase @zh 已经购买的产品。 @en Purchased Products.
*/
- acknowledgePurchase(purchase: google.Purchase[]): void;
+ acknowledgePurchase(purchase: google.Purchase[]): Promise<void>;
/**
* @en Returns purchases details for currently owned items bought within your app.
* @zh 返回您应用内当前拥有的购买商品的购买详情。
* @param productType @zh 产品类型 @en Product type.
*/
- queryPurchasesAsync(productType: google.ProductType): void;
+ queryPurchasesAsync(productType: google.ProductType): Promise<google.Purchase[]>;
/**
* @en Gets the billing config, which stores configuration used to perform billing operations.
* @zh 获取计费配置,其中存储用于执行计费操作的配置。
*/
- getBillingConfigAsync(): void;
+ getBillingConfigAsync(): Promise<google.BillingConfig>;
/**
* @en Creates alternative billing only purchase details that can be used to report a transaction made
* via alternative billing without user choice to use Google Play billing.
* @zh 创建仅限替代结算的购买详情,可用于报告通过替代结算进行的交易,而无需用户选择使用 Google Play 结算。
*/
- createAlternativeBillingOnlyReportingDetailsAsync(): void;
+ createAlternativeBillingOnlyReportingDetailsAsync(): Promise<void>;
/**
* @en Checks the availability of offering alternative billing without user choice to use Google Play billing.
* @zh 检查是否可以提供替代结算方式,而无需用户选择使用 Google Play 结算方式。
*/
- isAlternativeBillingOnlyAvailableAsync(): void;
+ isAlternativeBillingOnlyAvailableAsync(): Promise<void>;
/**
* @en Creates purchase details that can be used to report a transaction made via external offer.
* @zh 创建可用于报告通过外部报价进行的交易的购买详情。
*/
- createExternalOfferReportingDetailsAsync(): void;
+ createExternalOfferReportingDetailsAsync(): Promise<void>;
/**
* @en Checks the availability of providing external offer.
* @zh 检查提供外部报价的可用性。
*/
- isExternalOfferAvailableAsync(): void;
+ isExternalOfferAvailableAsync(): Promise<void>;
/**
* @en Checks if the specified feature or capability is supported by the Play Store.
* @zh 检查 Play Store 是否支持指定的功能。
* @param feature @zh 功能特性 @en feature.
@@ -73616,11 +73599,8 @@
* @en Overlays billing related messages on top of the calling app.
* @zh 在调用应用程序上叠加与计费相关的消息。
*/
showInAppMessages(): google.BillingResult | null;
- on<K extends keyof _vendor_google_billing_billing__BillingEventMap>(type: K, callback: _vendor_google_billing_billing__BillingEventMap[K], target?: unknown): _vendor_google_billing_billing__BillingEventMap[K];
- once<K extends keyof _vendor_google_billing_billing__BillingEventMap>(type: K, callback: _vendor_google_billing_billing__BillingEventMap[K], target?: unknown): _vendor_google_billing_billing__BillingEventMap[K];
- off<K extends keyof _vendor_google_billing_billing__BillingEventMap>(eventType: K, callback?: _vendor_google_billing_billing__BillingEventMap[K], target?: any): void;
}
export enum _cocos_video_video_player_enums__VideoPlayerEventType {
/**
* @en None.
|
@@ -131,8 +131,16 @@ class Billing { | |||
* @en Starts up BillingClient setup process asynchronously. | |||
* @zh 异步启动 BillingClient 设置过程。 | |||
*/ | |||
public startConnection (): void { | |||
jsb.googleBilling?.startConnection(); | |||
public startConnection (): Promise<google.BillingResult> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we don’t use an id for callbacks, could it lead to timing issues and result in incorrect outcomes?
var a = billing.startConnection();
var b = billing.startConnection();
//or use promise.all
Promise.all([billing.startConnection(), billing.startConnection(), billing.startConnection()])
@@ -186,76 +206,184 @@ class Billing { | |||
* @param productDetails @zh 产品详情。 @en product details. | |||
* @param selectedOfferToken @zh 选择提供的token。 @en selected offer token. | |||
*/ | |||
public launchBillingFlow (productDetails: google.ProductDetails[], selectedOfferToken: string | null): void { | |||
jsb.googleBilling?.launchBillingFlow(productDetails, selectedOfferToken); | |||
public launchBillingFlow (productDetails: google.ProductDetails[], selectedOfferToken: string | null): Promise<google.Purchase[]> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里不应该是一个异步方法,更不应该是异步返回一个交易列表,正确的应该是一个同步方法,并且结果是返回此操作的状态码,详见
https://developer.android.com/google/play/billing/integrate?hl=zh-cn#launch
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PurchaseUpdate 的回调,不一定是主动触发 launchBilingFlow 后回调的
它是 Google 那边在连接成功后,任何时间 都可能会触发的一个回调。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
现在过度封装后的 launchBillingFlow
甚至没法对齐 Google 官方文档的做法
https://developer.android.com/google/play/billing/integrate?hl=zh-cn#launch
launchBillingFlow 是拉起支付界面,但并不是一定能拉起成功,拉起成功也并不是一定会创建交易(比如用户拉起之后,就取消支付)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个地方没有必要保持一致,连接成功之后,基本上不会出错,内部也有连接是否成功的判断。因为cocos和UI不是在同一个线程,很难做到保持一致。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PurchaseUpdate
这个倒是没有注意到的问题。我看看
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个地方没有必要保持一致,连接成功之后,基本上不会出错,内部也有连接是否成功的判断。因为cocos和UI不是在同一个线程,很难做到保持一致。
要的!并非所有响应代码都是错误
https://developer.android.com/google/play/billing/errors?hl=zh-cn#item_already_owned
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -176,8 +184,20 @@ class Billing { | |||
* @param productType @zh 产品类型。 @en product type. | |||
* | |||
*/ | |||
public queryProductDetailsParams (productId: string[], productType: google.ProductType): void { | |||
jsb.googleBilling?.queryProductDetailsParams(productId, productType); | |||
public queryProductDetailsParams (productId: string[], productType: google.ProductType): Promise<google.ProductDetails[]> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个 Promise 返回的对象是错误的,没有和 Google Billing 的API保持一致
当前的返回列表信息 google.ProductDetails[]
,没有了 BillingResult
的结果
预期正确的返回 BillingResult billingResult,<ProductDetails> productDetailsList
(这个是Android代码)
https://developer.android.com/google/play/billing/integrate?hl=zh-cn#show-products
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我们现在是希望封装得对 ts 开发者友好点。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
同理,其他很多公开API也是一样的问题,请尽量保持和GoogleBillingAPI一致的返回结果,很多时候,BillingResult 是一个很重要的返回参数,实际项目开发中也会用到此参数做业务判断,不能忽略返回此参数
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我们现在是希望封装得对 ts 开发者友好点。
这个支付 sdk 很重要,项目的命脉,个人建议最好是和官方的 API 保持一致,而不是过度封装
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
接口都一样,只是说回调的方式对 ts 更友好点。担心 ts 的开发者不习惯 java 风格的 api。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
感觉你们过于忽视对 BilingResult 相应状态码的处理,Google 甚至专门有一个文档链接详细介绍处理的
https://developer.android.com/google/play/billing/errors?hl=zh-cn
特别是这句:并非所有响应代码都是错误
。
所以,Google Billing 的API ,很多地方才返回这个 BillingResult 状态对象,因为是真的很多状态,并不是非对即错,一般业务都需要根据不同状态做对应的处理
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
此 PR 前的 ts API 本身也跟 Java 的 API 风格不一致。
// ts
public queryProductDetailsParams (productId: string[], productType: google.ProductType): void {
...
}
// java
billingClient.queryProductDetailsAsync(
queryProductDetailsParams,
new ProductDetailsResponseListener() {
public void onProductDetailsResponse(BillingResult billingResult,
List<ProductDetails> productDetailsList) {
// check billingResult
// process returned productDetailsList
}
}
)
如果是跟 java 风格一致,那么这个接口的 ts 声明应该是:
class QueryProductDetailsParams {
public static newBuilder(): QueryProductDetailsParamsBuilder;
}
class QueryProductDetailsParamsBuilder {
public setProductList( ... );
public build(): QueryProductDetailsParams;
}
interface ProductDetailsResponseListener {
onProductDetailsResponse (billingResult: BillingResult, productDetailsList: ProductDetails[]) ) => void;
}
queryProductDetailsAsync(params: QueryProductDetailsParams, listener: ProductDetailsResponseListener): void;
// 用法:
queryProductDetailsAsync(
QueryProductDetailsParams.newBuilder().setProductList(...).build(), {
onProductDetailsResponse (billingResult: BillingResult, productDetailsList: ProductDetails[]) {
// check billingResult
// process returned productDetailsList
}
}
);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
另外,为什么 ts 封装的接口 productType: google.ProductType 这个参数只支持传递一个?java 的接口是 id 与 type 的结构体的数组。这是不是也导致了不一致的行为?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
大佬们有点跑题了
请注意:我这里原本的问题是,保持一致的 返回参数
,而不是保持java风格一致
请注意:我这里原本的问题是,保持一致的 返回参数
,而不是保持java风格一致
请注意:我这里原本的问题是,保持一致的 返回参数
,而不是保持java风格一致
感觉大佬们现在误解我的意思了
现在这里的代码的问题是过度封装,返回参接只是返回了商品列表google.ProductDetails[]
,不返回 BillingResult 的参数(而这个参数一般业务都会用到的)
在返回参数没保持一致的前提下,我再看了这个代码的 请求参数
,也是错误的,或者不能说是错误的,只能说又是过度封装,导致本来可以做的事情,现在直接不能做
原来的 API 是可以这样子的
一次性请求不同类型的商品(消耗型、订阅型)不同id
但是现在的 API 不能做到
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个后面会调整
public queryProductDetailsParams (productId: string[], productType: google.ProductType): Promise<google.ProductDetails[]> { | ||
return new Promise((resolve, reject) => { | ||
this.once( | ||
google.BillingEventType.PRODUCT_DETAILS_RESPONSE, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里的 id 是唯一的,存在非常严重的问题。
当我连续 queryProductDetailsParams
n次,此接口并不是按照调用顺序返回的,举个例子
queryProductDetailsParams1
queryProductDetailsParams2
queryProductDetailsParams3
实际的返回结果可能是
queryProductDetailsParams2
queryProductDetailsParams1
queryProductDetailsParams3
正确的做法应该是在调用此接口的时候,实时生成一个回调事件(uuid之类),同时ts注册这个事件的回调监听,然后在 Android 端获取到结果的时候,回调对应的事件
注意:其他API需要检查,很大概率存在类似问题
this.once(google.BillingEventType.BILLING_SERVICE_DISCONNECTED, (): void => { | ||
reject(); | ||
}); | ||
jsb.googleBilling?.startConnection(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to reject if jsb.googleBilling
is undefined or null?
会议结论是 完全仿造google里java的风格,1比1的还原,不做封装。 关闭PR |
Re: #
Changelog
Continuous Integration
This pull request:
Compatibility Check
This pull request: