7
7
import com .android .billingclient .api .AcknowledgePurchaseResponseListener ;
8
8
import com .android .billingclient .api .BillingClient ;
9
9
import com .android .billingclient .api .BillingClient .BillingResponseCode ;
10
- import com .android .billingclient .api .BillingClient .SkuType ;
11
10
import com .android .billingclient .api .BillingClientStateListener ;
12
11
import com .android .billingclient .api .BillingFlowParams ;
13
12
import com .android .billingclient .api .BillingResult ;
14
13
import com .android .billingclient .api .ConsumeParams ;
15
14
import com .android .billingclient .api .ConsumeResponseListener ;
15
+ import com .android .billingclient .api .PendingPurchasesParams ;
16
+ import com .android .billingclient .api .ProductDetails ;
17
+ import com .android .billingclient .api .ProductDetailsResponseListener ;
16
18
import com .android .billingclient .api .Purchase ;
17
19
import com .android .billingclient .api .PurchasesResponseListener ;
18
20
import com .android .billingclient .api .PurchasesUpdatedListener ;
21
+ import com .android .billingclient .api .QueryProductDetailsParams ;
22
+ import com .android .billingclient .api .QueryProductDetailsResult ;
19
23
import com .android .billingclient .api .QueryPurchasesParams ;
20
- import com .android .billingclient .api .SkuDetails ;
21
- import com .android .billingclient .api .SkuDetailsParams ;
22
- import com .android .billingclient .api .SkuDetailsResponseListener ;
24
+ import java .lang .ref .WeakReference ;
23
25
import java .util .ArrayList ;
24
26
import java .util .Arrays ;
25
27
import java .util .List ;
26
- import java .lang .ref .WeakReference ;
27
28
import org .apache .cordova .CallbackContext ;
28
29
import org .apache .cordova .CordovaInterface ;
29
30
import org .apache .cordova .CordovaPlugin ;
@@ -103,9 +104,10 @@ public void run() {
103
104
}
104
105
105
106
private BillingClient getBillingClient () {
106
- return BillingClient
107
- .newBuilder (this .contextRef .get ())
108
- .enablePendingPurchases ()
107
+ return BillingClient .newBuilder (this .contextRef .get ())
108
+ .enablePendingPurchases (
109
+ PendingPurchasesParams .newBuilder ().enableOneTimeProducts ().build ()
110
+ )
109
111
.setListener (
110
112
new PurchasesUpdatedListener () {
111
113
public void onPurchasesUpdated (
@@ -143,8 +145,7 @@ private void setPurchaseUpdatedListener(CallbackContext callbackContext) {
143
145
}
144
146
145
147
private void consume (String token , CallbackContext callbackContext ) {
146
- ConsumeParams consumeParams = ConsumeParams
147
- .newBuilder ()
148
+ ConsumeParams consumeParams = ConsumeParams .newBuilder ()
148
149
.setPurchaseToken (token )
149
150
.build ();
150
151
billingClient .consumeAsync (
@@ -200,37 +201,49 @@ private void getProducts(
200
201
callbackContext .error ("Billing client is not connected" );
201
202
return ;
202
203
}
203
- SkuDetailsParams .Builder params = SkuDetailsParams .newBuilder ();
204
- params .setSkusList (idList ).setType (SkuType .INAPP );
204
+ List <QueryProductDetailsParams .Product > productList = new ArrayList <>();
205
+ for (String productId : idList ) {
206
+ productList .add (
207
+ QueryProductDetailsParams .Product .newBuilder ()
208
+ .setProductId (productId )
209
+ .setProductType (BillingClient .ProductType .INAPP )
210
+ .build ()
211
+ );
212
+ }
213
+ QueryProductDetailsParams params = QueryProductDetailsParams .newBuilder ()
214
+ .setProductList (productList )
215
+ .build ();
205
216
206
- billingClient .querySkuDetailsAsync (
207
- params . build () ,
208
- new SkuDetailsResponseListener () {
209
- public void onSkuDetailsResponse (
217
+ billingClient .queryProductDetailsAsync (
218
+ params ,
219
+ new ProductDetailsResponseListener () {
220
+ public void onProductDetailsResponse (
210
221
BillingResult billingResult ,
211
- List < SkuDetails > skuDetailsList
222
+ QueryProductDetailsResult queryProductDetailsResult
212
223
) {
213
224
try {
214
225
int responseCode = billingResult .getResponseCode ();
215
226
if (responseCode == BillingResponseCode .OK ) {
227
+ List <ProductDetails > productDetailsList = queryProductDetailsResult .getProductDetailsList ();
216
228
JSONArray products = new JSONArray ();
217
- Log .d ("IAP" , "Got " + skuDetailsList .size () + " products" );
218
- for (SkuDetails skuDetails : skuDetailsList ) {
229
+ for (ProductDetails productDetails : productDetailsList ) {
219
230
JSONObject product = new JSONObject ();
220
- product .put ("json" , skuDetails .getOriginalJson ());
221
- product .put ("productId" , skuDetails .getSku ());
222
- product .put ("title" , skuDetails .getTitle ());
223
- product .put ("description" , skuDetails .getDescription ());
224
- product .put ("price" , skuDetails .getPrice ());
225
- product .put (
226
- "priceAmountMicros" ,
227
- skuDetails .getPriceAmountMicros ()
228
- );
229
- product .put (
230
- "priceCurrencyCode" ,
231
- skuDetails .getPriceCurrencyCode ()
232
- );
233
- product .put ("type" , skuDetails .getType ());
231
+ ProductDetails .OneTimePurchaseOfferDetails offerDetails = productDetails .getOneTimePurchaseOfferDetails ();
232
+ if (offerDetails != null ) {
233
+ product .put ("productId" , productDetails .getProductId ());
234
+ product .put ("title" , productDetails .getTitle ());
235
+ product .put ("description" , productDetails .getDescription ());
236
+ product .put ("price" , offerDetails .getFormattedPrice ());
237
+ product .put (
238
+ "priceAmountMicros" ,
239
+ offerDetails .getPriceAmountMicros ()
240
+ );
241
+ product .put (
242
+ "priceCurrencyCode" ,
243
+ offerDetails .getPriceCurrencyCode ()
244
+ );
245
+ product .put ("type" , productDetails .getProductType ());
246
+ }
234
247
products .put (product );
235
248
}
236
249
callbackContext .success (products );
@@ -245,21 +258,64 @@ public void onSkuDetailsResponse(
245
258
);
246
259
}
247
260
248
- private void purchase (String json , CallbackContext callbackContext ) {
261
+ private void purchase (String productIdOrJson , CallbackContext callbackContext ) {
249
262
try {
250
- SkuDetails skuDetails = new SkuDetails (json );
251
- BillingResult result = billingClient .launchBillingFlow (
252
- activityRef .get (),
253
- BillingFlowParams .newBuilder ().setSkuDetails (skuDetails ).build ()
254
- );
255
- int responseCode = result .getResponseCode ();
256
- if (responseCode == BillingResponseCode .OK ) {
257
- callbackContext .success ();
258
- } else {
259
- callbackContext .error (responseCode );
263
+ if (productIdOrJson == null || productIdOrJson .trim ().isEmpty ()) {
264
+ callbackContext .error ("Product ID cannot be null or empty" );
265
+ return ;
260
266
}
261
- } catch (JSONException e ) {
262
- callbackContext .error (e .getMessage ());
267
+
268
+ final String productId = productIdOrJson ;
269
+
270
+ List <QueryProductDetailsParams .Product > productList = new ArrayList <>();
271
+ productList .add (
272
+ QueryProductDetailsParams .Product .newBuilder ()
273
+ .setProductId (productId )
274
+ .setProductType (BillingClient .ProductType .INAPP )
275
+ .build ()
276
+ );
277
+ QueryProductDetailsParams params = QueryProductDetailsParams .newBuilder ()
278
+ .setProductList (productList )
279
+ .build ();
280
+
281
+ billingClient .queryProductDetailsAsync (
282
+ params ,
283
+ new ProductDetailsResponseListener () {
284
+ public void onProductDetailsResponse (
285
+ BillingResult billingResult ,
286
+ QueryProductDetailsResult queryProductDetailsResult
287
+ ) {
288
+ if (billingResult .getResponseCode () == BillingResponseCode .OK ) {
289
+ List <ProductDetails > productDetailsList = queryProductDetailsResult .getProductDetailsList ();
290
+ if (!productDetailsList .isEmpty ()) {
291
+ ProductDetails productDetails = productDetailsList .get (0 );
292
+ BillingResult result = billingClient .launchBillingFlow (
293
+ activityRef .get (),
294
+ BillingFlowParams .newBuilder ().setProductDetailsParamsList (
295
+ Arrays .asList (
296
+ BillingFlowParams .ProductDetailsParams .newBuilder ()
297
+ .setProductDetails (productDetails )
298
+ .build ()
299
+ )
300
+ ).build ()
301
+ );
302
+ int responseCode = result .getResponseCode ();
303
+ if (responseCode == BillingResponseCode .OK ) {
304
+ callbackContext .success ();
305
+ } else {
306
+ callbackContext .error (responseCode );
307
+ }
308
+ } else {
309
+ callbackContext .error ("No product details found for: " + productId );
310
+ }
311
+ } else {
312
+ callbackContext .error (billingResult .getResponseCode ());
313
+ }
314
+ }
315
+ }
316
+ );
317
+ } catch (Exception e ) {
318
+ callbackContext .error ("Purchase error: " + e .getMessage ());
263
319
}
264
320
}
265
321
@@ -270,8 +326,7 @@ private void getPurchases(CallbackContext callbackContext) {
270
326
return ;
271
327
}
272
328
273
- QueryPurchasesParams params = QueryPurchasesParams
274
- .newBuilder ()
329
+ QueryPurchasesParams params = QueryPurchasesParams .newBuilder ()
275
330
.setProductType (BillingClient .ProductType .INAPP )
276
331
.build ();
277
332
billingClient .queryPurchasesAsync (
@@ -310,8 +365,7 @@ private void acknowledgePurchase(
310
365
return ;
311
366
}
312
367
313
- AcknowledgePurchaseParams params = AcknowledgePurchaseParams
314
- .newBuilder ()
368
+ AcknowledgePurchaseParams params = AcknowledgePurchaseParams .newBuilder ()
315
369
.setPurchaseToken (purchaseToken )
316
370
.build ();
317
371
@@ -339,10 +393,8 @@ private JSONObject purchaseToJson(Purchase purchase) throws JSONException {
339
393
}
340
394
item .put ("productIds" , skuArray );
341
395
item .put ("orderId" , purchase .getOrderId ());
342
- item .put ("sate" , purchase .getPurchaseState ());
343
396
item .put ("signature" , purchase .getSignature ());
344
397
item .put ("purchaseTime" , purchase .getPurchaseTime ());
345
- item .put ("isAcknowledged" , purchase .isAcknowledged ());
346
398
item .put ("purchaseToken" , purchase .getPurchaseToken ());
347
399
item .put ("purchaseState" , purchase .getPurchaseState ());
348
400
item .put ("isAcknowledged" , purchase .isAcknowledged ());
@@ -365,22 +417,6 @@ private String getString(JSONArray args, int index) {
365
417
}
366
418
}
367
419
368
- private int getInt (JSONArray args , int index ) {
369
- try {
370
- return args .getInt (index );
371
- } catch (JSONException e ) {
372
- return 0 ;
373
- }
374
- }
375
-
376
- private boolean getBoolean (JSONArray args , int index ) {
377
- try {
378
- return args .getBoolean (index );
379
- } catch (JSONException e ) {
380
- return false ;
381
- }
382
- }
383
-
384
420
private List <String > getStringList (JSONArray args , int index ) {
385
421
try {
386
422
JSONArray array = args .getJSONArray (index );
0 commit comments