@capgo/native-purchases 7.7.0 → 7.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -50,7 +50,7 @@ repositories {
50
50
 
51
51
  dependencies {
52
52
  implementation "com.google.guava:guava:33.4.8-android"
53
- def billing_version = "7.1.1"
53
+ def billing_version = "8.0.0"
54
54
  implementation "com.android.billingclient:billing:$billing_version"
55
55
  implementation fileTree(dir: 'libs', include: ['*.jar'])
56
56
  implementation project(':capacitor-android')
@@ -1,6 +1,7 @@
1
1
  package ee.forgr.nativepurchases;
2
2
 
3
3
  import android.util.Log;
4
+ import androidx.annotation.NonNull;
4
5
  import com.android.billingclient.api.AcknowledgePurchaseParams;
5
6
  import com.android.billingclient.api.AcknowledgePurchaseResponseListener;
6
7
  import com.android.billingclient.api.BillingClient;
@@ -8,11 +9,13 @@ import com.android.billingclient.api.BillingClientStateListener;
8
9
  import com.android.billingclient.api.BillingFlowParams;
9
10
  import com.android.billingclient.api.BillingResult;
10
11
  import com.android.billingclient.api.ConsumeParams;
12
+ import com.android.billingclient.api.PendingPurchasesParams;
11
13
  import com.android.billingclient.api.ProductDetails;
12
14
  import com.android.billingclient.api.ProductDetailsResponseListener;
13
15
  import com.android.billingclient.api.Purchase;
14
16
  import com.android.billingclient.api.PurchasesUpdatedListener;
15
17
  import com.android.billingclient.api.QueryProductDetailsParams;
18
+ import com.android.billingclient.api.QueryProductDetailsResult;
16
19
  import com.android.billingclient.api.QueryPurchasesParams;
17
20
  import com.getcapacitor.JSObject;
18
21
  import com.getcapacitor.Plugin;
@@ -23,12 +26,12 @@ import com.google.common.collect.ImmutableList;
23
26
  import java.util.ArrayList;
24
27
  import java.util.Collections;
25
28
  import java.util.List;
29
+ import java.util.Objects;
26
30
  import java.util.concurrent.CountDownLatch;
27
31
  import java.util.concurrent.Phaser;
28
32
  import java.util.concurrent.TimeUnit;
29
33
  import java.util.concurrent.TimeoutException;
30
34
  import org.json.JSONArray;
31
- import org.json.JSONException;
32
35
 
33
36
  @CapacitorPlugin(name = "NativePurchases")
34
37
  public class NativePurchasesPlugin extends Plugin {
@@ -56,21 +59,20 @@ public class NativePurchasesPlugin extends Plugin {
56
59
  Log.d(TAG, "Plugin load() completed");
57
60
  }
58
61
 
59
- private void semaphoreWait(Number waitTime) {
60
- Log.d(TAG, "semaphoreWait() called with waitTime: " + waitTime);
61
- Log.i(NativePurchasesPlugin.TAG, "semaphoreWait " + waitTime);
62
+ private void semaphoreWait() {
63
+ Log.d(TAG, "semaphoreWait() called with waitTime: " + (Number) 10);
64
+ Log.i(NativePurchasesPlugin.TAG, "semaphoreWait " + (Number) 10);
62
65
  try {
63
66
  // Log.i(CapacitorUpdater.TAG, "semaphoreReady count " + CapacitorUpdaterPlugin.this.semaphoreReady.getCount());
64
- NativePurchasesPlugin.this.semaphoreReady.awaitAdvanceInterruptibly(
65
- NativePurchasesPlugin.this.semaphoreReady.getPhase(),
66
- waitTime.longValue(),
67
- TimeUnit.SECONDS
68
- );
67
+ semaphoreReady.awaitAdvanceInterruptibly(
68
+ semaphoreReady.getPhase(),
69
+ ((Number) 10).longValue(),
70
+ TimeUnit.SECONDS
71
+ );
69
72
  // Log.i(CapacitorUpdater.TAG, "semaphoreReady await " + res);
70
73
  Log.i(
71
74
  NativePurchasesPlugin.TAG,
72
- "semaphoreReady count " +
73
- NativePurchasesPlugin.this.semaphoreReady.getPhase()
75
+ "semaphoreReady count " + semaphoreReady.getPhase()
74
76
  );
75
77
  Log.d(TAG, "semaphoreWait() completed successfully");
76
78
  } catch (InterruptedException e) {
@@ -86,7 +88,7 @@ public class NativePurchasesPlugin extends Plugin {
86
88
  private void semaphoreUp() {
87
89
  Log.d(TAG, "semaphoreUp() called");
88
90
  Log.i(NativePurchasesPlugin.TAG, "semaphoreUp");
89
- NativePurchasesPlugin.this.semaphoreReady.register();
91
+ semaphoreReady.register();
90
92
  Log.d(TAG, "semaphoreUp() completed");
91
93
  }
92
94
 
@@ -95,10 +97,9 @@ public class NativePurchasesPlugin extends Plugin {
95
97
  Log.i(NativePurchasesPlugin.TAG, "semaphoreDown");
96
98
  Log.i(
97
99
  NativePurchasesPlugin.TAG,
98
- "semaphoreDown count " +
99
- NativePurchasesPlugin.this.semaphoreReady.getPhase()
100
+ "semaphoreDown count " + semaphoreReady.getPhase()
100
101
  );
101
- NativePurchasesPlugin.this.semaphoreReady.arriveAndDeregister();
102
+ semaphoreReady.arriveAndDeregister();
102
103
  Log.d(TAG, "semaphoreDown() completed");
103
104
  }
104
105
 
@@ -224,7 +225,9 @@ public class NativePurchasesPlugin extends Plugin {
224
225
  acknowledgePurchaseParams,
225
226
  new AcknowledgePurchaseResponseListener() {
226
227
  @Override
227
- public void onAcknowledgePurchaseResponse(BillingResult billingResult) {
228
+ public void onAcknowledgePurchaseResponse(
229
+ @NonNull BillingResult billingResult
230
+ ) {
228
231
  // Handle the result of the acknowledge purchase
229
232
  Log.d(TAG, "onAcknowledgePurchaseResponse() called");
230
233
  Log.d(
@@ -245,7 +248,7 @@ public class NativePurchasesPlugin extends Plugin {
245
248
 
246
249
  private void initBillingClient(PluginCall purchaseCall) {
247
250
  Log.d(TAG, "initBillingClient() called");
248
- semaphoreWait(10);
251
+ semaphoreWait();
249
252
  closeBillingClient();
250
253
  semaphoreUp();
251
254
  CountDownLatch semaphoreReady = new CountDownLatch(1);
@@ -255,7 +258,7 @@ public class NativePurchasesPlugin extends Plugin {
255
258
  new PurchasesUpdatedListener() {
256
259
  @Override
257
260
  public void onPurchasesUpdated(
258
- BillingResult billingResult,
261
+ @NonNull BillingResult billingResult,
259
262
  List<Purchase> purchases
260
263
  ) {
261
264
  Log.d(TAG, "onPurchasesUpdated() called");
@@ -303,13 +306,17 @@ public class NativePurchasesPlugin extends Plugin {
303
306
  }
304
307
  }
305
308
  )
306
- .enablePendingPurchases()
309
+ .enablePendingPurchases(
310
+ PendingPurchasesParams.newBuilder().enableOneTimeProducts().build()
311
+ )
307
312
  .build();
308
313
  Log.d(TAG, "Starting billing client connection");
309
314
  billingClient.startConnection(
310
315
  new BillingClientStateListener() {
311
316
  @Override
312
- public void onBillingSetupFinished(BillingResult billingResult) {
317
+ public void onBillingSetupFinished(
318
+ @NonNull BillingResult billingResult
319
+ ) {
313
320
  Log.d(TAG, "onBillingSetupFinished() called");
314
321
  Log.d(
315
322
  TAG,
@@ -405,6 +412,7 @@ public class NativePurchasesPlugin extends Plugin {
405
412
  call.reject("planIdentifier cannot be empty if productType is subs");
406
413
  return;
407
414
  }
415
+ assert quantity != null;
408
416
  if (quantity.intValue() < 1) {
409
417
  // Handle error: quantity is less than 1
410
418
  Log.d(TAG, "Error: quantity is less than 1");
@@ -437,10 +445,13 @@ public class NativePurchasesPlugin extends Plugin {
437
445
  billingClient.queryProductDetailsAsync(
438
446
  params,
439
447
  new ProductDetailsResponseListener() {
448
+ @Override
440
449
  public void onProductDetailsResponse(
441
- BillingResult billingResult,
442
- List<ProductDetails> productDetailsList
450
+ @NonNull BillingResult billingResult,
451
+ @NonNull QueryProductDetailsResult queryProductDetailsResult
443
452
  ) {
453
+ List<ProductDetails> productDetailsList =
454
+ queryProductDetailsResult.getProductDetailsList();
444
455
  Log.d(TAG, "onProductDetailsResponse() called for purchase");
445
456
  Log.d(
446
457
  TAG,
@@ -451,7 +462,7 @@ public class NativePurchasesPlugin extends Plugin {
451
462
  );
452
463
  Log.d(TAG, "Product details count: " + productDetailsList.size());
453
464
 
454
- if (productDetailsList.size() == 0) {
465
+ if (productDetailsList.isEmpty()) {
455
466
  Log.d(TAG, "No products found");
456
467
  closeBillingClient();
457
468
  call.reject("Product not found");
@@ -474,6 +485,7 @@ public class NativePurchasesPlugin extends Plugin {
474
485
  // list the SubscriptionOfferDetails and find the one who match the planIdentifier if not found get the first one
475
486
  ProductDetails.SubscriptionOfferDetails selectedOfferDetails =
476
487
  null;
488
+ assert productDetailsItem.getSubscriptionOfferDetails() != null;
477
489
  Log.d(
478
490
  TAG,
479
491
  "Available offer details count: " +
@@ -580,6 +592,7 @@ public class NativePurchasesPlugin extends Plugin {
580
592
  if (
581
593
  billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK
582
594
  ) {
595
+ assert purchases != null;
583
596
  for (Purchase purchase : purchases) {
584
597
  Log.d(TAG, "Processing purchase: " + purchase.getOrderId());
585
598
  Log.d(TAG, "Purchase state: " + purchase.getPurchaseState());
@@ -688,10 +701,13 @@ public class NativePurchasesPlugin extends Plugin {
688
701
  billingClient.queryProductDetailsAsync(
689
702
  params,
690
703
  new ProductDetailsResponseListener() {
704
+ @Override
691
705
  public void onProductDetailsResponse(
692
- BillingResult billingResult,
693
- List<ProductDetails> productDetailsList
706
+ @NonNull BillingResult billingResult,
707
+ @NonNull QueryProductDetailsResult queryProductDetailsResult
694
708
  ) {
709
+ List<ProductDetails> productDetailsList =
710
+ queryProductDetailsResult.getProductDetailsList();
695
711
  Log.d(TAG, "onProductDetailsResponse() called for query");
696
712
  Log.d(
697
713
  TAG,
@@ -702,7 +718,7 @@ public class NativePurchasesPlugin extends Plugin {
702
718
  );
703
719
  Log.d(TAG, "Product details count: " + productDetailsList.size());
704
720
 
705
- if (productDetailsList.size() == 0) {
721
+ if (productDetailsList.isEmpty()) {
706
722
  Log.d(TAG, "No products found in query");
707
723
  Log.d(TAG, "This usually means:");
708
724
  Log.d(TAG, "1. Product doesn't exist in Google Play Console");
@@ -735,9 +751,9 @@ public class NativePurchasesPlugin extends Plugin {
735
751
  Log.d(TAG, "Processing as in-app product");
736
752
  product.put("identifier", productDetails.getProductId());
737
753
  double price =
738
- productDetails
739
- .getOneTimePurchaseOfferDetails()
740
- .getPriceAmountMicros() /
754
+ Objects.requireNonNull(
755
+ productDetails.getOneTimePurchaseOfferDetails()
756
+ ).getPriceAmountMicros() /
741
757
  1000000.0;
742
758
  product.put("price", price);
743
759
  product.put(
@@ -885,6 +901,7 @@ public class NativePurchasesPlugin extends Plugin {
885
901
  Log.d(TAG, "Product identifier: " + productIdentifier);
886
902
  Log.d(TAG, "Product type: " + productType);
887
903
 
904
+ assert productIdentifier != null;
888
905
  if (productIdentifier.isEmpty()) {
889
906
  Log.d(TAG, "Error: productIdentifier is empty");
890
907
  call.reject("productIdentifier is empty");
@@ -926,8 +943,7 @@ public class NativePurchasesPlugin extends Plugin {
926
943
  );
927
944
  if (
928
945
  billingResult.getResponseCode() ==
929
- BillingClient.BillingResponseCode.OK &&
930
- purchases != null
946
+ BillingClient.BillingResponseCode.OK
931
947
  ) {
932
948
  for (Purchase purchase : purchases) {
933
949
  Log.d(
@@ -964,92 +980,16 @@ public class NativePurchasesPlugin extends Plugin {
964
980
  }
965
981
 
966
982
  // Query subscriptions if no filter or if filter is "subs"
967
- if (productType == null || productType.equals("subs")) {
968
- Log.d(TAG, "Querying subscription purchases");
969
- QueryPurchasesParams querySubsParams =
970
- QueryPurchasesParams.newBuilder()
971
- .setProductType(BillingClient.ProductType.SUBS)
972
- .build();
973
-
974
- billingClient.queryPurchasesAsync(
975
- querySubsParams,
976
- (subsResult, subsPurchases) -> {
977
- Log.d(
978
- TAG,
979
- "Subscription purchases query result: " +
980
- subsResult.getResponseCode()
981
- );
982
- if (
983
- subsResult.getResponseCode() ==
984
- BillingClient.BillingResponseCode.OK &&
985
- subsPurchases != null
986
- ) {
987
- for (Purchase purchase : subsPurchases) {
988
- Log.d(
989
- TAG,
990
- "Processing subscription purchase: " +
991
- purchase.getOrderId()
992
- );
993
- JSObject purchaseData = new JSObject();
994
- purchaseData.put(
995
- "transactionId",
996
- purchase.getPurchaseToken()
997
- );
998
- purchaseData.put(
999
- "productIdentifier",
1000
- purchase.getProducts().get(0)
1001
- );
1002
- purchaseData.put(
1003
- "purchaseDate",
1004
- new java.text.SimpleDateFormat(
1005
- "yyyy-MM-dd'T'HH:mm:ss'Z'",
1006
- java.util.Locale.US
1007
- ).format(new java.util.Date(purchase.getPurchaseTime()))
1008
- );
1009
- purchaseData.put("quantity", purchase.getQuantity());
1010
- purchaseData.put("productType", "subs");
1011
- purchaseData.put("orderId", purchase.getOrderId());
1012
- purchaseData.put(
1013
- "purchaseToken",
1014
- purchase.getPurchaseToken()
1015
- );
1016
- purchaseData.put(
1017
- "isAcknowledged",
1018
- purchase.isAcknowledged()
1019
- );
1020
- purchaseData.put(
1021
- "purchaseState",
1022
- String.valueOf(purchase.getPurchaseState())
1023
- );
1024
- // Add cancellation information
1025
- // Note: Android doesn't provide direct cancellation information in the Purchase object
1026
- purchaseData.put("willCancel", null); // Default to null, would need API call to determine actual cancellation date
1027
- allPurchases.put(purchaseData);
1028
- }
1029
- }
1030
-
1031
- // Return final result
1032
- JSObject result = new JSObject();
1033
- result.put("purchases", allPurchases);
1034
- Log.d(
1035
- TAG,
1036
- "Returning " + allPurchases.length() + " purchases"
1037
- );
1038
- closeBillingClient();
1039
- call.resolve(result);
1040
- }
1041
- );
1042
- } else {
1043
- // Only querying in-app, return result now
1044
- JSObject result = new JSObject();
1045
- result.put("purchases", allPurchases);
1046
- Log.d(
1047
- TAG,
1048
- "Returning " + allPurchases.length() + " in-app purchases"
1049
- );
1050
- closeBillingClient();
1051
- call.resolve(result);
1052
- }
983
+ assert productType != null;
984
+ // Only querying in-app, return result now
985
+ JSObject result = new JSObject();
986
+ result.put("purchases", allPurchases);
987
+ Log.d(
988
+ TAG,
989
+ "Returning " + allPurchases.length() + " in-app purchases"
990
+ );
991
+ closeBillingClient();
992
+ call.resolve(result);
1053
993
  }
1054
994
  );
1055
995
  } else if (productType.equals("subs")) {
@@ -1069,8 +1009,7 @@ public class NativePurchasesPlugin extends Plugin {
1069
1009
  );
1070
1010
  if (
1071
1011
  billingResult.getResponseCode() ==
1072
- BillingClient.BillingResponseCode.OK &&
1073
- purchases != null
1012
+ BillingClient.BillingResponseCode.OK
1074
1013
  ) {
1075
1014
  for (Purchase purchase : purchases) {
1076
1015
  Log.d(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/native-purchases",
3
- "version": "7.7.0",
3
+ "version": "7.7.2",
4
4
  "description": "In-app Subscriptions Made Easy",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",