@capgo/native-purchases 7.7.1 → 7.7.3
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.4.8-android"
|
|
53
|
-
def billing_version = "
|
|
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(
|
|
60
|
-
Log.d(TAG, "semaphoreWait() called with waitTime: " +
|
|
61
|
-
Log.i(NativePurchasesPlugin.TAG, "semaphoreWait " +
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
739
|
-
.getOneTimePurchaseOfferDetails()
|
|
740
|
-
|
|
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
|
-
|
|
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
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
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
|
-
|
|
1073
|
-
purchases != null
|
|
1012
|
+
BillingClient.BillingResponseCode.OK
|
|
1074
1013
|
) {
|
|
1075
1014
|
for (Purchase purchase : purchases) {
|
|
1076
1015
|
Log.d(
|