@capgo/native-purchases 8.0.5 → 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.
package/android/build.gradle
CHANGED
|
@@ -50,7 +50,7 @@ repositories {
|
|
|
50
50
|
|
|
51
51
|
dependencies {
|
|
52
52
|
implementation "com.google.guava:guava:33.5.0-android"
|
|
53
|
-
def billing_version = "8.2.
|
|
53
|
+
def billing_version = "8.2.1"
|
|
54
54
|
implementation "com.android.billingclient:billing:$billing_version"
|
|
55
55
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
56
56
|
implementation project(':capacitor-android')
|
|
@@ -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.
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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) {
|