diff --git a/package-lock.json b/package-lock.json index 758e1dd8c..7e5bf9637 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,16 @@ { "name": "com.foxdebug.acode", + + "version": "1.11.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "com.foxdebug.acode", + "version": "1.11.5", + "license": "MIT", "dependencies": { "@deadlyjack/ajax": "^1.2.6", diff --git a/src/lib/acode.js b/src/lib/acode.js index 8c6409c07..ea024037e 100644 --- a/src/lib/acode.js +++ b/src/lib/acode.js @@ -343,7 +343,7 @@ export default class Acode { ); return helpers.promisify( iap.purchase, - product.json, + product.productId, ); }); } diff --git a/src/lib/installPlugin.js b/src/lib/installPlugin.js index 8521c014d..e7a651aa4 100644 --- a/src/lib/installPlugin.js +++ b/src/lib/installPlugin.js @@ -343,7 +343,7 @@ async function resolveDep(manifest) { iap.setPurchaseUpdatedListener(...purchaseListener(onpurchase, onerror)); loaderDialog.setMessage(strings["loading..."]); - await helpers.promisify(iap.purchase, product.json); + await helpers.promisify(iap.purchase, product.productId); async function onpurchase(e) { const purchase = await getPurchase(product.productId); diff --git a/src/lib/removeAds.js b/src/lib/removeAds.js index 9bbe87486..2188e810e 100644 --- a/src/lib/removeAds.js +++ b/src/lib/removeAds.js @@ -13,7 +13,7 @@ export default function removeAds() { iap.setPurchaseUpdatedListener(...purchaseListener(onpurchase, reject)); iap.purchase( - product.json, + product.productId, (code) => { // ignore }, diff --git a/src/pages/donate/product.hbs b/src/pages/donate/product.hbs index e33fe74f9..9b5a5a4b9 100644 --- a/src/pages/donate/product.hbs +++ b/src/pages/donate/product.hbs @@ -13,7 +13,7 @@ {{#author}}

- {{author}}

{{/author}} - diff --git a/src/pages/plugin/plugin.js b/src/pages/plugin/plugin.js index f72be3277..c5be9e394 100644 --- a/src/pages/plugin/plugin.js +++ b/src/pages/plugin/plugin.js @@ -240,7 +240,7 @@ export default async function PluginInclude( iap.setPurchaseUpdatedListener(...purchaseListener(onpurchase, onerror)); $button.textContent = strings["loading..."]; - await helpers.promisify(iap.purchase, product.json); + await helpers.promisify(iap.purchase, product.productId); async function onpurchase(e) { const purchase = await getPurchase(product.productId); diff --git a/src/plugins/iap/plugin.xml b/src/plugins/iap/plugin.xml index 8cfdfdf54..f1d6300c1 100644 --- a/src/plugins/iap/plugin.xml +++ b/src/plugins/iap/plugin.xml @@ -22,6 +22,6 @@ - + \ No newline at end of file diff --git a/src/plugins/iap/src/com/foxdebug/iap/Iap.java b/src/plugins/iap/src/com/foxdebug/iap/Iap.java index 979b84661..469443986 100644 --- a/src/plugins/iap/src/com/foxdebug/iap/Iap.java +++ b/src/plugins/iap/src/com/foxdebug/iap/Iap.java @@ -7,23 +7,24 @@ import com.android.billingclient.api.AcknowledgePurchaseResponseListener; import com.android.billingclient.api.BillingClient; import com.android.billingclient.api.BillingClient.BillingResponseCode; -import com.android.billingclient.api.BillingClient.SkuType; import com.android.billingclient.api.BillingClientStateListener; import com.android.billingclient.api.BillingFlowParams; import com.android.billingclient.api.BillingResult; import com.android.billingclient.api.ConsumeParams; import com.android.billingclient.api.ConsumeResponseListener; +import com.android.billingclient.api.PendingPurchasesParams; +import com.android.billingclient.api.ProductDetails; +import com.android.billingclient.api.ProductDetailsResponseListener; import com.android.billingclient.api.Purchase; import com.android.billingclient.api.PurchasesResponseListener; import com.android.billingclient.api.PurchasesUpdatedListener; +import com.android.billingclient.api.QueryProductDetailsParams; +import com.android.billingclient.api.QueryProductDetailsResult; import com.android.billingclient.api.QueryPurchasesParams; -import com.android.billingclient.api.SkuDetails; -import com.android.billingclient.api.SkuDetailsParams; -import com.android.billingclient.api.SkuDetailsResponseListener; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.lang.ref.WeakReference; import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaInterface; import org.apache.cordova.CordovaPlugin; @@ -103,9 +104,10 @@ public void run() { } private BillingClient getBillingClient() { - return BillingClient - .newBuilder(this.contextRef.get()) - .enablePendingPurchases() + return BillingClient.newBuilder(this.contextRef.get()) + .enablePendingPurchases( + PendingPurchasesParams.newBuilder().enableOneTimeProducts().build() + ) .setListener( new PurchasesUpdatedListener() { public void onPurchasesUpdated( @@ -143,8 +145,7 @@ private void setPurchaseUpdatedListener(CallbackContext callbackContext) { } private void consume(String token, CallbackContext callbackContext) { - ConsumeParams consumeParams = ConsumeParams - .newBuilder() + ConsumeParams consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(token) .build(); billingClient.consumeAsync( @@ -200,37 +201,49 @@ private void getProducts( callbackContext.error("Billing client is not connected"); return; } - SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); - params.setSkusList(idList).setType(SkuType.INAPP); + List productList = new ArrayList<>(); + for (String productId : idList) { + productList.add( + QueryProductDetailsParams.Product.newBuilder() + .setProductId(productId) + .setProductType(BillingClient.ProductType.INAPP) + .build() + ); + } + QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder() + .setProductList(productList) + .build(); - billingClient.querySkuDetailsAsync( - params.build(), - new SkuDetailsResponseListener() { - public void onSkuDetailsResponse( + billingClient.queryProductDetailsAsync( + params, + new ProductDetailsResponseListener() { + public void onProductDetailsResponse( BillingResult billingResult, - List skuDetailsList + QueryProductDetailsResult queryProductDetailsResult ) { try { int responseCode = billingResult.getResponseCode(); if (responseCode == BillingResponseCode.OK) { + List productDetailsList = queryProductDetailsResult.getProductDetailsList(); JSONArray products = new JSONArray(); - Log.d("IAP", "Got " + skuDetailsList.size() + " products"); - for (SkuDetails skuDetails : skuDetailsList) { + for (ProductDetails productDetails : productDetailsList) { JSONObject product = new JSONObject(); - product.put("json", skuDetails.getOriginalJson()); - product.put("productId", skuDetails.getSku()); - product.put("title", skuDetails.getTitle()); - product.put("description", skuDetails.getDescription()); - product.put("price", skuDetails.getPrice()); - product.put( - "priceAmountMicros", - skuDetails.getPriceAmountMicros() - ); - product.put( - "priceCurrencyCode", - skuDetails.getPriceCurrencyCode() - ); - product.put("type", skuDetails.getType()); + ProductDetails.OneTimePurchaseOfferDetails offerDetails = productDetails.getOneTimePurchaseOfferDetails(); + if (offerDetails != null) { + product.put("productId", productDetails.getProductId()); + product.put("title", productDetails.getTitle()); + product.put("description", productDetails.getDescription()); + product.put("price", offerDetails.getFormattedPrice()); + product.put( + "priceAmountMicros", + offerDetails.getPriceAmountMicros() + ); + product.put( + "priceCurrencyCode", + offerDetails.getPriceCurrencyCode() + ); + product.put("type", productDetails.getProductType()); + } products.put(product); } callbackContext.success(products); @@ -245,21 +258,64 @@ public void onSkuDetailsResponse( ); } - private void purchase(String json, CallbackContext callbackContext) { + private void purchase(String productIdOrJson, CallbackContext callbackContext) { try { - SkuDetails skuDetails = new SkuDetails(json); - BillingResult result = billingClient.launchBillingFlow( - activityRef.get(), - BillingFlowParams.newBuilder().setSkuDetails(skuDetails).build() - ); - int responseCode = result.getResponseCode(); - if (responseCode == BillingResponseCode.OK) { - callbackContext.success(); - } else { - callbackContext.error(responseCode); + if (productIdOrJson == null || productIdOrJson.trim().isEmpty()) { + callbackContext.error("Product ID cannot be null or empty"); + return; } - } catch (JSONException e) { - callbackContext.error(e.getMessage()); + + final String productId = productIdOrJson; + + List productList = new ArrayList<>(); + productList.add( + QueryProductDetailsParams.Product.newBuilder() + .setProductId(productId) + .setProductType(BillingClient.ProductType.INAPP) + .build() + ); + QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder() + .setProductList(productList) + .build(); + + billingClient.queryProductDetailsAsync( + params, + new ProductDetailsResponseListener() { + public void onProductDetailsResponse( + BillingResult billingResult, + QueryProductDetailsResult queryProductDetailsResult + ) { + if (billingResult.getResponseCode() == BillingResponseCode.OK) { + List productDetailsList = queryProductDetailsResult.getProductDetailsList(); + if (!productDetailsList.isEmpty()) { + ProductDetails productDetails = productDetailsList.get(0); + BillingResult result = billingClient.launchBillingFlow( + activityRef.get(), + BillingFlowParams.newBuilder().setProductDetailsParamsList( + Arrays.asList( + BillingFlowParams.ProductDetailsParams.newBuilder() + .setProductDetails(productDetails) + .build() + ) + ).build() + ); + int responseCode = result.getResponseCode(); + if (responseCode == BillingResponseCode.OK) { + callbackContext.success(); + } else { + callbackContext.error(responseCode); + } + } else { + callbackContext.error("No product details found for: " + productId); + } + } else { + callbackContext.error(billingResult.getResponseCode()); + } + } + } + ); + } catch (Exception e) { + callbackContext.error("Purchase error: " + e.getMessage()); } } @@ -270,8 +326,7 @@ private void getPurchases(CallbackContext callbackContext) { return; } - QueryPurchasesParams params = QueryPurchasesParams - .newBuilder() + QueryPurchasesParams params = QueryPurchasesParams.newBuilder() .setProductType(BillingClient.ProductType.INAPP) .build(); billingClient.queryPurchasesAsync( @@ -310,8 +365,7 @@ private void acknowledgePurchase( return; } - AcknowledgePurchaseParams params = AcknowledgePurchaseParams - .newBuilder() + AcknowledgePurchaseParams params = AcknowledgePurchaseParams.newBuilder() .setPurchaseToken(purchaseToken) .build(); @@ -339,10 +393,8 @@ private JSONObject purchaseToJson(Purchase purchase) throws JSONException { } item.put("productIds", skuArray); item.put("orderId", purchase.getOrderId()); - item.put("sate", purchase.getPurchaseState()); item.put("signature", purchase.getSignature()); item.put("purchaseTime", purchase.getPurchaseTime()); - item.put("isAcknowledged", purchase.isAcknowledged()); item.put("purchaseToken", purchase.getPurchaseToken()); item.put("purchaseState", purchase.getPurchaseState()); item.put("isAcknowledged", purchase.isAcknowledged()); @@ -365,22 +417,6 @@ private String getString(JSONArray args, int index) { } } - private int getInt(JSONArray args, int index) { - try { - return args.getInt(index); - } catch (JSONException e) { - return 0; - } - } - - private boolean getBoolean(JSONArray args, int index) { - try { - return args.getBoolean(index); - } catch (JSONException e) { - return false; - } - } - private List getStringList(JSONArray args, int index) { try { JSONArray array = args.getJSONArray(index); diff --git a/src/sidebarApps/extensions/index.js b/src/sidebarApps/extensions/index.js index f540d3672..2199f0bf0 100644 --- a/src/sidebarApps/extensions/index.js +++ b/src/sidebarApps/extensions/index.js @@ -534,7 +534,7 @@ function ListItem({ icon, name, id, version, downloads, installed, source }) { iap.setPurchaseUpdatedListener( ...purchaseListener(onpurchase, onerror), ); - await helpers.promisify(iap.purchase, product.json); + await helpers.promisify(iap.purchase, product.productId); async function onpurchase(e) { const purchase = await getPurchase(product.productId);