@capgo/native-purchases 0.0.8 → 0.0.9
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/README.md
CHANGED
|
@@ -1,29 +1,31 @@
|
|
|
1
1
|
package ee.forgr.nativepurchases;
|
|
2
2
|
|
|
3
3
|
import android.util.Log;
|
|
4
|
-
import androidx.annotation.NonNull;
|
|
5
4
|
|
|
6
5
|
import com.android.billingclient.api.AcknowledgePurchaseParams;
|
|
6
|
+
import com.android.billingclient.api.BillingClientStateListener;
|
|
7
|
+
import com.android.billingclient.api.ProductDetails;
|
|
8
|
+
import com.android.billingclient.api.ProductDetailsResponseListener;
|
|
7
9
|
import com.android.billingclient.api.AcknowledgePurchaseResponseListener;
|
|
8
10
|
import com.android.billingclient.api.BillingClient;
|
|
9
11
|
import com.android.billingclient.api.BillingFlowParams;
|
|
10
12
|
import com.android.billingclient.api.BillingResult;
|
|
11
13
|
import com.android.billingclient.api.Purchase;
|
|
12
14
|
import com.android.billingclient.api.PurchasesUpdatedListener;
|
|
13
|
-
import com.android.billingclient.api.
|
|
14
|
-
import com.android.billingclient.api.SkuDetailsParams;
|
|
15
|
-
import com.android.billingclient.api.SkuDetailsResponseListener;
|
|
15
|
+
import com.android.billingclient.api.QueryProductDetailsParams;
|
|
16
16
|
import com.getcapacitor.JSObject;
|
|
17
17
|
import com.getcapacitor.Plugin;
|
|
18
18
|
import com.getcapacitor.PluginCall;
|
|
19
19
|
import com.getcapacitor.PluginMethod;
|
|
20
20
|
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
21
21
|
import com.google.common.base.CaseFormat;
|
|
22
|
+
import com.google.common.collect.ImmutableList;
|
|
23
|
+
|
|
22
24
|
import java.util.ArrayList;
|
|
23
|
-
import java.util.HashMap;
|
|
24
|
-
import java.util.Iterator;
|
|
25
25
|
import java.util.List;
|
|
26
26
|
import java.util.Map;
|
|
27
|
+
import java.util.concurrent.CountDownLatch;
|
|
28
|
+
|
|
27
29
|
import org.json.JSONArray;
|
|
28
30
|
import org.json.JSONException;
|
|
29
31
|
import org.json.JSONObject;
|
|
@@ -32,31 +34,9 @@ import org.json.JSONObject;
|
|
|
32
34
|
public class NativePurchasesPlugin extends Plugin {
|
|
33
35
|
|
|
34
36
|
public final String PLUGIN_VERSION = "2.0.13";
|
|
35
|
-
|
|
36
37
|
private BillingClient billingClient;
|
|
37
|
-
private PluginCall purchaseCall;
|
|
38
|
-
|
|
39
|
-
@Override
|
|
40
|
-
public void load() {
|
|
41
|
-
super.load();
|
|
42
|
-
billingClient = BillingClient.newBuilder(getContext())
|
|
43
|
-
.setListener(new PurchasesUpdatedListener() {
|
|
44
|
-
@Override
|
|
45
|
-
public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
|
|
46
|
-
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null) {
|
|
47
|
-
for (Purchase purchase : purchases) {
|
|
48
|
-
handlePurchase(purchase);
|
|
49
|
-
}
|
|
50
|
-
} else {
|
|
51
|
-
// Handle any other error codes.
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
})
|
|
55
|
-
.enablePendingPurchases()
|
|
56
|
-
.build();
|
|
57
|
-
}
|
|
58
38
|
|
|
59
|
-
private void handlePurchase(Purchase purchase) {
|
|
39
|
+
private void handlePurchase(Purchase purchase, PluginCall purchaseCall) {
|
|
60
40
|
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {
|
|
61
41
|
// Grant entitlement to the user, then acknowledge the purchase
|
|
62
42
|
acknowledgePurchase(purchase.getPurchaseToken());
|
|
@@ -69,6 +49,10 @@ public class NativePurchasesPlugin extends Plugin {
|
|
|
69
49
|
// purchase, and to complete it, they should follow instructions that are
|
|
70
50
|
// given to them. You can also choose to remind the user to complete the
|
|
71
51
|
// purchase if you detect that it is still pending.
|
|
52
|
+
purchaseCall.reject("Purchase is pending");
|
|
53
|
+
} else {
|
|
54
|
+
// Handle any other error codes.
|
|
55
|
+
purchaseCall.reject("Purchase is not purchased");
|
|
72
56
|
}
|
|
73
57
|
}
|
|
74
58
|
|
|
@@ -81,39 +65,98 @@ public class NativePurchasesPlugin extends Plugin {
|
|
|
81
65
|
@Override
|
|
82
66
|
public void onAcknowledgePurchaseResponse(BillingResult billingResult) {
|
|
83
67
|
// Handle the result of the acknowledge purchase
|
|
68
|
+
Log.i("NativePurchases", "onAcknowledgePurchaseResponse" + billingResult);
|
|
84
69
|
}
|
|
85
70
|
});
|
|
86
71
|
}
|
|
87
72
|
|
|
73
|
+
private void initBillingClient(PluginCall purchaseCall) {
|
|
74
|
+
CountDownLatch semaphoreReady = new CountDownLatch(1);
|
|
75
|
+
billingClient = BillingClient.newBuilder(getContext())
|
|
76
|
+
.setListener(new PurchasesUpdatedListener() {
|
|
77
|
+
@Override
|
|
78
|
+
public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
|
|
79
|
+
Log.i("NativePurchases", "onPurchasesUpdated" + billingResult);
|
|
80
|
+
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null) {
|
|
81
|
+
for (Purchase purchase : purchases) {
|
|
82
|
+
handlePurchase(purchase, purchaseCall);
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
// Handle any other error codes.
|
|
86
|
+
Log.i("NativePurchases", "onPurchasesUpdated" + billingResult);
|
|
87
|
+
purchaseCall.reject("Purchase is not purchased");
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}})
|
|
91
|
+
.enablePendingPurchases()
|
|
92
|
+
.build();
|
|
93
|
+
billingClient.startConnection(new BillingClientStateListener() {
|
|
94
|
+
@Override
|
|
95
|
+
public void onBillingSetupFinished(BillingResult billingResult) {
|
|
96
|
+
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
|
|
97
|
+
// The BillingClient is ready. You can query purchases here.
|
|
98
|
+
semaphoreReady.countDown();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
@Override
|
|
102
|
+
public void onBillingServiceDisconnected() {
|
|
103
|
+
// Try to restart the connection on the next request to
|
|
104
|
+
// Google Play by calling the startConnection() method.
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
try {
|
|
108
|
+
semaphoreReady.await();
|
|
109
|
+
} catch (InterruptedException e) {
|
|
110
|
+
e.printStackTrace();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
88
113
|
@PluginMethod
|
|
89
114
|
public void purchaseProduct(PluginCall call) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
115
|
+
String productIdentifier = call.getString("productIdentifier");
|
|
116
|
+
// cannot use quantity, because it's done in native modal
|
|
117
|
+
Log.d("CapacitorPurchases", "purchaseProduct: " + productIdentifier);
|
|
118
|
+
if (productIdentifier.isEmpty()) {
|
|
119
|
+
// Handle error: productIdentifier is empty
|
|
120
|
+
call.reject("productIdentifier is empty");
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
ImmutableList<QueryProductDetailsParams.Product> productList = ImmutableList.of(QueryProductDetailsParams.Product.newBuilder()
|
|
124
|
+
.setProductId(productIdentifier)
|
|
125
|
+
.setProductType(BillingClient.ProductType.INAPP)
|
|
126
|
+
.build());
|
|
127
|
+
QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder()
|
|
128
|
+
.setProductList(productList)
|
|
129
|
+
.build();
|
|
130
|
+
this.initBillingClient(call);
|
|
131
|
+
billingClient.queryProductDetailsAsync(
|
|
132
|
+
params,
|
|
133
|
+
new ProductDetailsResponseListener() {
|
|
134
|
+
public void onProductDetailsResponse(BillingResult billingResult, List<ProductDetails> productDetailsList) {
|
|
135
|
+
Log.i("NativePurchases", "onProductDetailsResponse" + billingResult + productDetailsList);
|
|
136
|
+
// Process the result
|
|
137
|
+
ProductDetails productDetails = productDetailsList.get(0);
|
|
138
|
+
ImmutableList<BillingFlowParams.ProductDetailsParams> productDetailsParamsList =
|
|
139
|
+
ImmutableList.of(
|
|
140
|
+
BillingFlowParams.ProductDetailsParams.newBuilder()
|
|
141
|
+
.setProductDetails(productDetails)
|
|
142
|
+
.build()
|
|
143
|
+
);
|
|
93
144
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
|
|
98
|
-
params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP);
|
|
145
|
+
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
|
|
146
|
+
.setProductDetailsParamsList(productDetailsParamsList)
|
|
147
|
+
.build();
|
|
99
148
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
.build();
|
|
108
|
-
billingClient.launchBillingFlow(getActivity(), flowParams);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
}
|
|
149
|
+
// Launch the billing flow
|
|
150
|
+
BillingResult billingResult2 = billingClient.launchBillingFlow(getActivity(), billingFlowParams);
|
|
151
|
+
Log.i("NativePurchases", "onProductDetailsResponse2" + billingResult2);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
);
|
|
155
|
+
}
|
|
115
156
|
|
|
116
|
-
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@PluginMethod
|
|
117
160
|
public void restorePurchases(PluginCall call) {
|
|
118
161
|
Log.d("NativePurchases", "restorePurchases");
|
|
119
162
|
|
|
@@ -158,38 +201,59 @@ public void getProducts(PluginCall call) {
|
|
|
158
201
|
}
|
|
159
202
|
|
|
160
203
|
Log.d("NativePurchases", "getProducts: " + productIdentifiers);
|
|
204
|
+
// Retrieve a value for "productDetails" by calling queryProductDetailsAsync()
|
|
205
|
+
// Get the offerToken of the selected offer
|
|
206
|
+
// String offerToken = productDetails
|
|
207
|
+
// .getSubscriptionOfferDetails()
|
|
208
|
+
// .get(selectedOfferIndex)
|
|
209
|
+
// .getOfferToken();
|
|
210
|
+
// Set the parameters for the offer that will be presented
|
|
211
|
+
// in the billing flow creating separate productDetailsParamsList variable
|
|
212
|
+
// ImmutableList<ProductDetailsParams> productDetailsParamsList =
|
|
213
|
+
// ImmutableList.of(
|
|
214
|
+
// BillingFlowParams.ProductDetailsParams.newBuilder()
|
|
215
|
+
// .setProductDetails(p)
|
|
216
|
+
// .setOfferToken(offerToken)
|
|
217
|
+
// .build()
|
|
218
|
+
// );
|
|
219
|
+
//
|
|
220
|
+
// BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
|
|
221
|
+
// .setProductDetailsParamsList(productDetailsParamsList)
|
|
222
|
+
// .build();
|
|
223
|
+
//
|
|
224
|
+
//// Launch the billing flow
|
|
225
|
+
// BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
|
|
161
226
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
product.put("
|
|
176
|
-
product.put("
|
|
177
|
-
product.put("
|
|
178
|
-
product.put("
|
|
179
|
-
product.put("
|
|
180
|
-
product.put("
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
227
|
+
// SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
|
|
228
|
+
// params.setSkusList(productIdentifiers).setType(BillingClient.SkuType.INAPP);
|
|
229
|
+
//
|
|
230
|
+
// billingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() {
|
|
231
|
+
// @Override
|
|
232
|
+
// public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) {
|
|
233
|
+
// if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && skuDetailsList != null) {
|
|
234
|
+
// JSObject ret = new JSObject();
|
|
235
|
+
// JSONArray products = new JSONArray();
|
|
236
|
+
//
|
|
237
|
+
// for (SkuDetails skuDetails : skuDetailsList) {
|
|
238
|
+
// JSObject product = new JSObject();
|
|
239
|
+
// product.put("productId", skuDetails.getSku());
|
|
240
|
+
// product.put("title", skuDetails.getTitle());
|
|
241
|
+
// product.put("description", skuDetails.getDescription());
|
|
242
|
+
// product.put("price", skuDetails.getPrice());
|
|
243
|
+
// product.put("priceAmountMicros", skuDetails.getPriceAmountMicros());
|
|
244
|
+
// product.put("priceCurrencyCode", skuDetails.getPriceCurrencyCode());
|
|
245
|
+
// product.put("type", skuDetails.getType());
|
|
246
|
+
// products.put(product);
|
|
247
|
+
// }
|
|
248
|
+
//
|
|
249
|
+
// ret.put("products", products);
|
|
250
|
+
// call.resolve(ret);
|
|
251
|
+
// } else {
|
|
252
|
+
// // Handle any other error codes.
|
|
253
|
+
// }
|
|
254
|
+
// }
|
|
255
|
+
// });
|
|
256
|
+
// }
|
|
193
257
|
}
|
|
194
258
|
|
|
195
259
|
//================================================================================
|