@capgo/native-purchases 8.0.6 → 8.0.7

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.
@@ -42,18 +42,42 @@ import org.json.JSONArray;
42
42
  @CapacitorPlugin(name = "NativePurchases")
43
43
  public class NativePurchasesPlugin extends Plugin {
44
44
 
45
- private final String pluginVersion = "8.0.6";
45
+ private final String pluginVersion = "8.0.7";
46
46
  public static final String TAG = "NativePurchases";
47
47
  private static final Phaser semaphoreReady = new Phaser(1);
48
48
  private BillingClient billingClient;
49
+ private PluginCall pendingCall = null;
50
+ private BillingResult lastBillingError = null;
49
51
 
50
52
  @PluginMethod
51
53
  public void isBillingSupported(PluginCall call) {
52
54
  Log.d(TAG, "isBillingSupported() called");
53
- JSObject ret = new JSObject();
54
- ret.put("isBillingSupported", true);
55
- Log.d(TAG, "isBillingSupported() returning true");
56
- call.resolve(ret);
55
+ try {
56
+ // Try to initialize billing client to check if billing is actually available
57
+ // Pass null so initBillingClient doesn't reject the call - we'll handle the result ourselves
58
+ this.initBillingClient(null);
59
+ // If initialization succeeded, billing is supported
60
+ JSObject ret = new JSObject();
61
+ ret.put("isBillingSupported", true);
62
+ Log.d(TAG, "isBillingSupported() returning true - billing client initialized successfully");
63
+ closeBillingClient();
64
+ call.resolve(ret);
65
+ } catch (RuntimeException e) {
66
+ Log.e(TAG, "isBillingSupported() - billing client initialization failed: " + e.getMessage());
67
+ closeBillingClient();
68
+ // Return false instead of rejecting - this is a check method
69
+ JSObject ret = new JSObject();
70
+ ret.put("isBillingSupported", false);
71
+ Log.d(TAG, "isBillingSupported() returning false - billing not available");
72
+ call.resolve(ret);
73
+ } catch (Exception e) {
74
+ Log.e(TAG, "isBillingSupported() - unexpected error: " + e.getMessage());
75
+ closeBillingClient();
76
+ JSObject ret = new JSObject();
77
+ ret.put("isBillingSupported", false);
78
+ Log.d(TAG, "isBillingSupported() returning false - unexpected error");
79
+ call.resolve(ret);
80
+ }
57
81
  }
58
82
 
59
83
  @Override
@@ -110,6 +134,13 @@ public class NativePurchasesPlugin extends Plugin {
110
134
  } else {
111
135
  Log.d(TAG, "Billing client was already null");
112
136
  }
137
+
138
+ // Clear pending call and error state
139
+ if (pendingCall != null) {
140
+ Log.w(TAG, "Warning: Clearing pending call that was never resolved/rejected");
141
+ pendingCall = null;
142
+ }
143
+ lastBillingError = null;
113
144
  }
114
145
 
115
146
  private void handlePurchase(Purchase purchase, PluginCall purchaseCall) {
@@ -233,6 +264,12 @@ public class NativePurchasesPlugin extends Plugin {
233
264
 
234
265
  private void initBillingClient(PluginCall purchaseCall) {
235
266
  Log.d(TAG, "initBillingClient() called");
267
+ Log.d(TAG, "purchaseCall is null: " + (purchaseCall == null));
268
+
269
+ // Store the pending call so we can reject it if billing setup fails
270
+ this.pendingCall = purchaseCall;
271
+ this.lastBillingError = null;
272
+
236
273
  semaphoreWait();
237
274
  closeBillingClient();
238
275
  semaphoreUp();
@@ -278,9 +315,43 @@ public class NativePurchasesPlugin extends Plugin {
278
315
  if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
279
316
  Log.d(TAG, "Billing setup successful, client is ready");
280
317
  // The BillingClient is ready. You can query purchases here.
318
+ lastBillingError = null;
281
319
  semaphoreReady.countDown();
282
320
  } else {
283
- Log.d(TAG, "Billing setup failed");
321
+ Log.e(TAG, "Billing setup failed with code: " + billingResult.getResponseCode());
322
+ Log.e(TAG, "Error message: " + billingResult.getDebugMessage());
323
+
324
+ // Store the error for later use
325
+ lastBillingError = billingResult;
326
+
327
+ // Release the latch so the waiting thread can continue
328
+ semaphoreReady.countDown();
329
+
330
+ // Reject the pending call if there is one
331
+ if (pendingCall != null) {
332
+ Log.d(TAG, "Rejecting pending call due to billing setup failure");
333
+ String errorMessage = "Billing service unavailable";
334
+ switch (billingResult.getResponseCode()) {
335
+ case BillingClient.BillingResponseCode.SERVICE_UNAVAILABLE:
336
+ errorMessage =
337
+ "Billing service unavailable. Please check your internet connection and Google Play Services.";
338
+ break;
339
+ case BillingClient.BillingResponseCode.BILLING_UNAVAILABLE:
340
+ errorMessage = "Billing is not available on this device.";
341
+ break;
342
+ case BillingClient.BillingResponseCode.FEATURE_NOT_SUPPORTED:
343
+ errorMessage = "This billing feature is not supported.";
344
+ break;
345
+ case BillingClient.BillingResponseCode.SERVICE_DISCONNECTED:
346
+ errorMessage = "Billing service disconnected. Please try again.";
347
+ break;
348
+ default:
349
+ errorMessage = "Billing setup failed: " + billingResult.getDebugMessage();
350
+ break;
351
+ }
352
+ pendingCall.reject("BILLING_SETUP_FAILED", errorMessage);
353
+ pendingCall = null;
354
+ }
284
355
  }
285
356
  }
286
357
 
@@ -295,10 +366,26 @@ public class NativePurchasesPlugin extends Plugin {
295
366
  try {
296
367
  Log.d(TAG, "Waiting for billing client setup to finish");
297
368
  semaphoreReady.await();
298
- Log.d(TAG, "Billing client setup completed");
369
+ Log.d(TAG, "Billing client setup wait completed");
370
+
371
+ // Check if billing setup failed
372
+ if (lastBillingError != null) {
373
+ Log.e(TAG, "Billing setup failed, throwing exception");
374
+ throw new RuntimeException("Billing setup failed: " + lastBillingError.getDebugMessage());
375
+ }
376
+
377
+ Log.d(TAG, "Billing client setup completed successfully");
299
378
  } catch (InterruptedException e) {
300
- Log.d(TAG, "InterruptedException while waiting for billing setup: " + e.getMessage());
379
+ Log.e(TAG, "InterruptedException while waiting for billing setup: " + e.getMessage());
301
380
  e.printStackTrace();
381
+ if (pendingCall != null) {
382
+ pendingCall.reject("BILLING_INTERRUPTED", "Billing setup was interrupted");
383
+ pendingCall = null;
384
+ }
385
+ } catch (RuntimeException e) {
386
+ Log.e(TAG, "RuntimeException during billing setup: " + e.getMessage());
387
+ // Don't reject here - already rejected in onBillingSetupFinished
388
+ throw e;
302
389
  }
303
390
  }
304
391
 
@@ -383,7 +470,14 @@ public class NativePurchasesPlugin extends Plugin {
383
470
  );
384
471
  QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder().setProductList(productList).build();
385
472
  Log.d(TAG, "Initializing billing client for purchase");
386
- this.initBillingClient(call);
473
+ try {
474
+ this.initBillingClient(call);
475
+ } catch (RuntimeException e) {
476
+ Log.e(TAG, "Failed to initialize billing client: " + e.getMessage());
477
+ closeBillingClient();
478
+ // Call already rejected in initBillingClient
479
+ return;
480
+ }
387
481
  try {
388
482
  Log.d(TAG, "Querying product details for purchase");
389
483
  billingClient.queryProductDetailsAsync(
@@ -520,7 +614,14 @@ public class NativePurchasesPlugin extends Plugin {
520
614
  public void restorePurchases(PluginCall call) {
521
615
  Log.d(TAG, "restorePurchases() called");
522
616
  Log.d(NativePurchasesPlugin.TAG, "restorePurchases");
523
- this.initBillingClient(null);
617
+ try {
618
+ this.initBillingClient(call);
619
+ } catch (RuntimeException e) {
620
+ Log.e(TAG, "Failed to initialize billing client: " + e.getMessage());
621
+ closeBillingClient();
622
+ // Call already rejected in initBillingClient
623
+ return;
624
+ }
524
625
  this.processUnfinishedPurchases();
525
626
  call.resolve();
526
627
  Log.d(TAG, "restorePurchases() completed");
@@ -541,7 +642,14 @@ public class NativePurchasesPlugin extends Plugin {
541
642
 
542
643
  QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder().setProductList(productList).build();
543
644
  Log.d(TAG, "Initializing billing client for single product query");
544
- this.initBillingClient(call);
645
+ try {
646
+ this.initBillingClient(call);
647
+ } catch (RuntimeException e) {
648
+ Log.e(TAG, "Failed to initialize billing client: " + e.getMessage());
649
+ closeBillingClient();
650
+ // Call already rejected in initBillingClient
651
+ return;
652
+ }
545
653
  try {
546
654
  Log.d(TAG, "Querying product details");
547
655
  billingClient.queryProductDetailsAsync(
@@ -655,7 +763,14 @@ public class NativePurchasesPlugin extends Plugin {
655
763
  Log.d(TAG, "Total products in query list: " + productList.size());
656
764
  QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder().setProductList(productList).build();
657
765
  Log.d(TAG, "Initializing billing client for product query");
658
- this.initBillingClient(call);
766
+ try {
767
+ this.initBillingClient(call);
768
+ } catch (RuntimeException e) {
769
+ Log.e(TAG, "Failed to initialize billing client: " + e.getMessage());
770
+ closeBillingClient();
771
+ // Call already rejected in initBillingClient
772
+ return;
773
+ }
659
774
  try {
660
775
  Log.d(TAG, "Querying product details");
661
776
  billingClient.queryProductDetailsAsync(
@@ -817,7 +932,14 @@ public class NativePurchasesPlugin extends Plugin {
817
932
  return;
818
933
  }
819
934
 
820
- this.initBillingClient(null);
935
+ try {
936
+ this.initBillingClient(call);
937
+ } catch (RuntimeException e) {
938
+ Log.e(TAG, "Failed to initialize billing client: " + e.getMessage());
939
+ closeBillingClient();
940
+ // Call already rejected in initBillingClient
941
+ return;
942
+ }
821
943
 
822
944
  JSONArray allPurchases = new JSONArray();
823
945
  AtomicInteger pendingQueries = new AtomicInteger((queryInApp ? 1 : 0) + (querySubs ? 1 : 0));
@@ -982,7 +1104,14 @@ public class NativePurchasesPlugin extends Plugin {
982
1104
  }
983
1105
 
984
1106
  Log.d(TAG, "Manually acknowledging purchase with token: " + purchaseToken);
985
- this.initBillingClient(null);
1107
+ try {
1108
+ this.initBillingClient(call);
1109
+ } catch (RuntimeException e) {
1110
+ Log.e(TAG, "Failed to initialize billing client: " + e.getMessage());
1111
+ closeBillingClient();
1112
+ // Call already rejected in initBillingClient
1113
+ return;
1114
+ }
986
1115
 
987
1116
  try {
988
1117
  AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
@@ -20,7 +20,7 @@ public class NativePurchasesPlugin: CAPPlugin, CAPBridgedPlugin {
20
20
  CAPPluginMethod(name: "isEntitledToOldBusinessModel", returnType: CAPPluginReturnPromise)
21
21
  ]
22
22
 
23
- private let pluginVersion: String = "8.0.6"
23
+ private let pluginVersion: String = "8.0.7"
24
24
  private var transactionUpdatesTask: Task<Void, Never>?
25
25
 
26
26
  @objc func getPluginVersion(_ call: CAPPluginCall) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/native-purchases",
3
- "version": "8.0.6",
3
+ "version": "8.0.7",
4
4
  "description": "In-app Subscriptions Made Easy",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",