From 265e78c7b61930cc5d0e8f7bacaaaf26ea888e8c Mon Sep 17 00:00:00 2001 From: Timo Schwarzer Date: Thu, 1 Sep 2022 22:07:12 +0200 Subject: [PATCH 1/5] Upgrade Gradle plugins, SDK version and Google Play Billing Library --- .clang-format | 128 ++++++++++++++++++ GodotGooglePlayBilling.gdap | 4 +- build.gradle | 6 +- godot-google-play-billing/build.gradle | 16 ++- .../GodotGooglePlayBilling.java | 126 +++++++++-------- .../utils/GooglePlayBillingUtils.java | 73 ++++++---- gradle/wrapper/gradle-wrapper.properties | 6 +- 7 files changed, 266 insertions(+), 93 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..cb67d39 --- /dev/null +++ b/.clang-format @@ -0,0 +1,128 @@ +# Commented out parameters are those with the same value as base LLVM style +# We can uncomment them if we want to change their value, or enforce the +# chosen value in case the base style changes (last sync: Clang 6.0.1). +--- +### General config, applies to all languages ### +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: DontAlign +# AlignConsecutiveAssignments: false +# AlignConsecutiveDeclarations: false +# AlignEscapedNewlines: Right +# AlignOperands: true +AlignTrailingComments: false +AllowAllParametersOfDeclarationOnNextLine: false +# AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: true +# AllowShortLoopsOnASingleLine: false +# AlwaysBreakAfterDefinitionReturnType: None +# AlwaysBreakAfterReturnType: None +# AlwaysBreakBeforeMultilineStrings: false +# AlwaysBreakTemplateDeclarations: false +# BinPackArguments: true +# BinPackParameters: true +# BraceWrapping: +# AfterClass: false +# AfterControlStatement: false +# AfterEnum: false +# AfterFunction: false +# AfterNamespace: false +# AfterObjCDeclaration: false +# AfterStruct: false +# AfterUnion: false +# AfterExternBlock: false +# BeforeCatch: false +# BeforeElse: false +# IndentBraces: false +# SplitEmptyFunction: true +# SplitEmptyRecord: true +# SplitEmptyNamespace: true +# BreakBeforeBinaryOperators: None +# BreakBeforeBraces: Attach +# BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: false +# BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: AfterColon +# BreakStringLiterals: true +ColumnLimit: 0 +# CommentPragmas: '^ IWYU pragma:' +# CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 8 +Cpp11BracedListStyle: false +# DerivePointerAlignment: false +# DisableFormat: false +# ExperimentalAutoDetectBinPacking: false +# FixNamespaceComments: true +# ForEachMacros: +# - foreach +# - Q_FOREACH +# - BOOST_FOREACH +# IncludeBlocks: Preserve +IncludeCategories: + - Regex: '".*"' + Priority: 1 + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*' + Priority: 3 +# IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: true +# IndentPPDirectives: None +IndentWidth: 4 +# IndentWrappedFunctionNames: false +# JavaScriptQuotes: Leave +# JavaScriptWrapImports: true +# KeepEmptyLinesAtTheStartOfBlocks: true +# MacroBlockBegin: '' +# MacroBlockEnd: '' +# MaxEmptyLinesToKeep: 1 +# NamespaceIndentation: None +# PenaltyBreakAssignment: 2 +# PenaltyBreakBeforeFirstCallParameter: 19 +# PenaltyBreakComment: 300 +# PenaltyBreakFirstLessLess: 120 +# PenaltyBreakString: 1000 +# PenaltyExcessCharacter: 1000000 +# PenaltyReturnTypeOnItsOwnLine: 60 +# PointerAlignment: Right +# RawStringFormats: +# - Delimiter: pb +# Language: TextProto +# BasedOnStyle: google +# ReflowComments: true +# SortIncludes: true +# SortUsingDeclarations: true +# SpaceAfterCStyleCast: false +# SpaceAfterTemplateKeyword: true +# SpaceBeforeAssignmentOperators: true +# SpaceBeforeParens: ControlStatements +# SpaceInEmptyParentheses: false +# SpacesBeforeTrailingComments: 1 +# SpacesInAngles: false +# SpacesInContainerLiterals: true +# SpacesInCStyleCastParentheses: false +# SpacesInParentheses: false +# SpacesInSquareBrackets: false +TabWidth: 4 +UseTab: Always +--- +### C++ specific config ### +Language: Cpp +Standard: Cpp03 +--- +### ObjC specific config ### +Language: ObjC +Standard: Cpp03 +ObjCBlockIndentWidth: 4 +# ObjCSpaceAfterProperty: false +# ObjCSpaceBeforeProtocolList: true +--- +### Java specific config ### +Language: Java +# BreakAfterJavaFieldAnnotations: false +JavaImportGroups: ['org.godotengine', 'android', 'androidx', 'com.android', 'com.google', 'java', 'javax'] +... diff --git a/GodotGooglePlayBilling.gdap b/GodotGooglePlayBilling.gdap index b6fddfd..0a7ec01 100644 --- a/GodotGooglePlayBilling.gdap +++ b/GodotGooglePlayBilling.gdap @@ -2,7 +2,7 @@ name="GodotGooglePlayBilling" binary_type="local" -binary="GodotGooglePlayBilling.1.1.2.release.aar" +binary="GodotGooglePlayBilling.2.0.0-rc.1.release.aar" [dependencies] -remote=["com.android.billingclient:billing:4.0.0"] +remote=["com.android.billingclient:billing:5.0.0"] diff --git a/build.gradle b/build.gradle index 25a626a..c206ca6 100644 --- a/build.gradle +++ b/build.gradle @@ -2,10 +2,10 @@ buildscript { repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath "com.android.tools.build:gradle:4.0.0" + classpath "com.android.tools.build:gradle:7.2.2" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -15,7 +15,7 @@ buildscript { allprojects { repositories { google() - jcenter() + mavenCentral() } } diff --git a/godot-google-play-billing/build.gradle b/godot-google-play-billing/build.gradle index 8e987ea..238fe39 100644 --- a/godot-google-play-billing/build.gradle +++ b/godot-google-play-billing/build.gradle @@ -2,19 +2,23 @@ plugins { id 'com.android.library' } -ext.pluginVersionCode = 4 -ext.pluginVersionName = "1.1.2" +ext.pluginVersionCode = 5 +ext.pluginVersionName = "2.0.0-rc.1" android { - compileSdkVersion 30 - buildToolsVersion "30.0.3" + compileSdkVersion 33 + buildToolsVersion "33.0.0" defaultConfig { minSdkVersion 18 - targetSdkVersion 30 + targetSdkVersion 33 versionCode pluginVersionCode versionName pluginVersionName } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_9 + targetCompatibility JavaVersion.VERSION_1_9 + } libraryVariants.all { variant -> variant.outputs.all { output -> @@ -25,6 +29,6 @@ android { dependencies { implementation "androidx.legacy:legacy-support-v4:1.0.0" - implementation 'com.android.billingclient:billing:4.0.0' + implementation 'com.android.billingclient:billing:5.0.0' compileOnly fileTree(dir: 'libs', include: ['godot-lib*.aar']) } diff --git a/godot-google-play-billing/src/main/java/org/godotengine/godot/plugin/googleplaybilling/GodotGooglePlayBilling.java b/godot-google-play-billing/src/main/java/org/godotengine/godot/plugin/googleplaybilling/GodotGooglePlayBilling.java index a519223..afd884c 100644 --- a/godot-google-play-billing/src/main/java/org/godotengine/godot/plugin/googleplaybilling/GodotGooglePlayBilling.java +++ b/godot-google-play-billing/src/main/java/org/godotengine/godot/plugin/googleplaybilling/GodotGooglePlayBilling.java @@ -34,6 +34,7 @@ import org.godotengine.godot.Godot; import org.godotengine.godot.plugin.GodotPlugin; import org.godotengine.godot.plugin.SignalInfo; +import org.godotengine.godot.plugin.UsedByGodot; import org.godotengine.godot.plugin.googleplaybilling.utils.GooglePlayBillingUtils; import androidx.annotation.NonNull; @@ -50,13 +51,18 @@ import com.android.billingclient.api.ConsumeResponseListener; import com.android.billingclient.api.PriceChangeConfirmationListener; import com.android.billingclient.api.PriceChangeFlowParams; +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.QueryPurchasesParams; import com.android.billingclient.api.SkuDetails; import com.android.billingclient.api.SkuDetailsParams; import com.android.billingclient.api.SkuDetailsResponseListener; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -65,7 +71,7 @@ public class GodotGooglePlayBilling extends GodotPlugin implements PurchasesUpdatedListener, BillingClientStateListener, PriceChangeConfirmationListener { private final BillingClient billingClient; - private final HashMap skuDetailsCache = new HashMap<>(); // sku → SkuDetails + private final HashMap productDetailsCache = new HashMap<>(); // sku → SkuDetails private boolean calledStartConnection; private String obfuscatedAccountId; private String obfuscatedProfileId; @@ -83,28 +89,35 @@ public GodotGooglePlayBilling(Godot godot) { obfuscatedProfileId = ""; } + @UsedByGodot public void startConnection() { calledStartConnection = true; billingClient.startConnection(this); } + @UsedByGodot public void endConnection() { billingClient.endConnection(); } + @UsedByGodot public boolean isReady() { return this.billingClient.isReady(); } + @UsedByGodot public int getConnectionState() { return billingClient.getConnectionState(); } + @UsedByGodot public void queryPurchases(String type) { - billingClient.queryPurchasesAsync(type, new PurchasesResponseListener() { + QueryPurchasesParams params = QueryPurchasesParams.newBuilder().setProductType(type).build(); + + billingClient.queryPurchasesAsync(params, new PurchasesResponseListener() { @Override public void onQueryPurchasesResponse(BillingResult billingResult, - List purchaseList) { + @NonNull List purchaseList) { Dictionary returnValue = new Dictionary(); if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { returnValue.put("status", 0); // OK = 0 @@ -119,29 +132,34 @@ public void onQueryPurchasesResponse(BillingResult billingResult, }); } + @UsedByGodot public void querySkuDetails(final String[] list, String type) { - List skuList = Arrays.asList(list); + ArrayList products = new ArrayList<>(); + + for (String productId : list) { + products.add(QueryProductDetailsParams.Product.newBuilder().setProductId(productId).setProductType(type).build()); + } - SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder() - .setSkusList(skuList) - .setType(type); + QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder() + .setProductList(products) + .build(); - billingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() { + billingClient.queryProductDetailsAsync(params, new ProductDetailsResponseListener() { @Override - public void onSkuDetailsResponse(BillingResult billingResult, - List skuDetailsList) { + public void onProductDetailsResponse(@NonNull BillingResult billingResult, @NonNull List list) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { - for (SkuDetails skuDetails : skuDetailsList) { - skuDetailsCache.put(skuDetails.getSku(), skuDetails); + for (ProductDetails productDetails : list) { + productDetailsCache.put(productDetails.getProductId(), productDetails); } - emitSignal("sku_details_query_completed", (Object)GooglePlayBillingUtils.convertSkuDetailsListToDictionaryObjectArray(skuDetailsList)); + emitSignal("product_details_query_completed", (Object)GooglePlayBillingUtils.convertProductDetailsListToDictionaryObjectArray(list)); } else { - emitSignal("sku_details_query_error", billingResult.getResponseCode(), billingResult.getDebugMessage(), list); + emitSignal("product_details_query_error", billingResult.getResponseCode(), billingResult.getDebugMessage(), list); } } }); } + @UsedByGodot public void acknowledgePurchase(final String purchaseToken) { AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder() @@ -149,7 +167,7 @@ public void acknowledgePurchase(final String purchaseToken) { .build(); billingClient.acknowledgePurchase(acknowledgePurchaseParams, new AcknowledgePurchaseResponseListener() { @Override - public void onAcknowledgePurchaseResponse(BillingResult billingResult) { + public void onAcknowledgePurchaseResponse(@NonNull BillingResult billingResult) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { emitSignal("purchase_acknowledged", purchaseToken); } else { @@ -159,6 +177,7 @@ public void onAcknowledgePurchaseResponse(BillingResult billingResult) { }); } + @UsedByGodot public void consumePurchase(String purchaseToken) { ConsumeParams consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(purchaseToken) @@ -190,60 +209,58 @@ public void onBillingServiceDisconnected() { emitSignal("disconnected"); } - public Dictionary confirmPriceChange(String sku) { - if (!skuDetailsCache.containsKey(sku)) { - Dictionary returnValue = new Dictionary(); - returnValue.put("status", 1); // FAILED = 1 - returnValue.put("response_code", null); // Null since there is no ResponseCode to return but to keep the interface (status, response_code, debug_message) - returnValue.put("debug_message", "You must query the sku details and wait for the result before confirming a price change!"); - return returnValue; - } - - SkuDetails skuDetails = skuDetailsCache.get(sku); - - PriceChangeFlowParams priceChangeFlowParams = - PriceChangeFlowParams.newBuilder().setSkuDetails(skuDetails).build(); - - billingClient.launchPriceChangeConfirmationFlow(getActivity(), priceChangeFlowParams, this); - - Dictionary returnValue = new Dictionary(); - returnValue.put("status", 0); // OK = 0 - return returnValue; - } - + @UsedByGodot public Dictionary purchase(String sku) { - return purchaseInternal("", sku, - BillingFlowParams.ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); + return purchaseInternal("", sku, + BillingFlowParams.ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); } + @UsedByGodot public Dictionary updateSubscription(String oldToken, String sku, int prorationMode) { return purchaseInternal(oldToken, sku, prorationMode); } - private Dictionary purchaseInternal(String oldToken, String sku, int prorationMode) { - if (!skuDetailsCache.containsKey(sku)) { + private Dictionary purchaseInternal(String oldToken, String productId, int prorationMode) { + if (!productDetailsCache.containsKey(productId)) { Dictionary returnValue = new Dictionary(); returnValue.put("status", 1); // FAILED = 1 returnValue.put("response_code", null); // Null since there is no ResponseCode to return but to keep the interface (status, response_code, debug_message) - returnValue.put("debug_message", "You must query the sku details and wait for the result before purchasing!"); + returnValue.put("debug_message", "You must query the product details and wait for the result before purchasing!"); return returnValue; } - SkuDetails skuDetails = skuDetailsCache.get(sku); + ProductDetails productDetails = productDetailsCache.get(productId); + assert productDetails != null; + + // TODO: Allow for selecting other than the default/first offer + + String offerToken = null; + if (productDetails.getSubscriptionOfferDetails() != null && !productDetails.getSubscriptionOfferDetails().isEmpty()) { + offerToken = productDetails.getSubscriptionOfferDetails().get(0).getOfferToken(); + } + + List params = List.of( + BillingFlowParams.ProductDetailsParams.newBuilder() + .setOfferToken(offerToken) + .setProductDetails(productDetails) + .build()); + BillingFlowParams.Builder purchaseParamsBuilder = BillingFlowParams.newBuilder(); - purchaseParamsBuilder.setSkuDetails(skuDetails); + purchaseParamsBuilder.setProductDetailsParamsList(params); + if (!obfuscatedAccountId.isEmpty()) { purchaseParamsBuilder.setObfuscatedAccountId(obfuscatedAccountId); } if (!obfuscatedProfileId.isEmpty()) { purchaseParamsBuilder.setObfuscatedProfileId(obfuscatedProfileId); } + if (!oldToken.isEmpty() && prorationMode != BillingFlowParams.ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY) { BillingFlowParams.SubscriptionUpdateParams updateParams = - BillingFlowParams.SubscriptionUpdateParams.newBuilder() - .setOldSkuPurchaseToken(oldToken) - .setReplaceSkusProrationMode(prorationMode) - .build(); + BillingFlowParams.SubscriptionUpdateParams.newBuilder() + .setOldPurchaseToken(oldToken) + .setReplaceProrationMode(prorationMode) + .build(); purchaseParamsBuilder.setSubscriptionUpdateParams(updateParams); } BillingResult result = billingClient.launchBillingFlow(getActivity(), purchaseParamsBuilder.build()); @@ -258,11 +275,14 @@ private Dictionary purchaseInternal(String oldToken, String sku, int prorationMo } return returnValue; - } + } + + @UsedByGodot public void setObfuscatedAccountId(String accountId) { obfuscatedAccountId = accountId; } + @UsedByGodot public void setObfuscatedProfileId(String profileId) { obfuscatedProfileId = profileId; } @@ -294,12 +314,6 @@ public String getPluginName() { return "GodotGooglePlayBilling"; } - @NonNull - @Override - public List getPluginMethods() { - return Arrays.asList("startConnection", "endConnection", "confirmPriceChange", "purchase", "updateSubscription", "querySkuDetails", "isReady", "getConnectionState", "queryPurchases", "acknowledgePurchase", "consumePurchase", "setObfuscatedAccountId", "setObfuscatedProfileId"); - } - @NonNull @Override public Set getPluginSignals() { @@ -312,8 +326,8 @@ public Set getPluginSignals() { signals.add(new SignalInfo("purchases_updated", Object[].class)); signals.add(new SignalInfo("query_purchases_response", Object.class)); signals.add(new SignalInfo("purchase_error", Integer.class, String.class)); - signals.add(new SignalInfo("sku_details_query_completed", Object[].class)); - signals.add(new SignalInfo("sku_details_query_error", Integer.class, String.class, String[].class)); + signals.add(new SignalInfo("product_details_query_completed", Object[].class)); + signals.add(new SignalInfo("product_details_query_error", Integer.class, String.class, String[].class)); signals.add(new SignalInfo("price_change_acknowledged", Integer.class)); signals.add(new SignalInfo("purchase_acknowledged", String.class)); signals.add(new SignalInfo("purchase_acknowledgement_error", Integer.class, String.class, String.class)); diff --git a/godot-google-play-billing/src/main/java/org/godotengine/godot/plugin/googleplaybilling/utils/GooglePlayBillingUtils.java b/godot-google-play-billing/src/main/java/org/godotengine/godot/plugin/googleplaybilling/utils/GooglePlayBillingUtils.java index 1c1cb28..d4b7d58 100644 --- a/godot-google-play-billing/src/main/java/org/godotengine/godot/plugin/googleplaybilling/utils/GooglePlayBillingUtils.java +++ b/godot-google-play-billing/src/main/java/org/godotengine/godot/plugin/googleplaybilling/utils/GooglePlayBillingUtils.java @@ -32,6 +32,7 @@ import org.godotengine.godot.Dictionary; +import com.android.billingclient.api.ProductDetails; import com.android.billingclient.api.Purchase; import com.android.billingclient.api.SkuDetails; @@ -51,33 +52,59 @@ public static Dictionary convertPurchaseToDictionary(Purchase purchase) { dictionary.put("signature", purchase.getSignature()); // PBL V4 replaced getSku with getSkus to support multi-sku purchases, // use the first entry for "sku" and generate an array for "skus" - ArrayList skus = purchase.getSkus(); - dictionary.put("sku", skus.get(0)); - String[] skusArray = skus.toArray(new String[0]); - dictionary.put("skus", skusArray); + String[] products = purchase.getProducts().toArray(new String[0]); + dictionary.put("products", products); dictionary.put("is_acknowledged", purchase.isAcknowledged()); dictionary.put("is_auto_renewing", purchase.isAutoRenewing()); return dictionary; } - public static Dictionary convertSkuDetailsToDictionary(SkuDetails details) { + public static Dictionary convertProductDetailsToDictionary(ProductDetails details) { Dictionary dictionary = new Dictionary(); - dictionary.put("sku", details.getSku()); + dictionary.put("id", details.getProductId()); dictionary.put("title", details.getTitle()); dictionary.put("description", details.getDescription()); - dictionary.put("price", details.getPrice()); - dictionary.put("price_currency_code", details.getPriceCurrencyCode()); - dictionary.put("price_amount_micros", details.getPriceAmountMicros()); - dictionary.put("free_trial_period", details.getFreeTrialPeriod()); - dictionary.put("icon_url", details.getIconUrl()); - dictionary.put("introductory_price", details.getIntroductoryPrice()); - dictionary.put("introductory_price_amount_micros", details.getIntroductoryPriceAmountMicros()); - dictionary.put("introductory_price_cycles", details.getIntroductoryPriceCycles()); - dictionary.put("introductory_price_period", details.getIntroductoryPricePeriod()); - dictionary.put("original_price", details.getOriginalPrice()); - dictionary.put("original_price_amount_micros", details.getOriginalPriceAmountMicros()); - dictionary.put("subscription_period", details.getSubscriptionPeriod()); - dictionary.put("type", details.getType()); + dictionary.put("type", details.getProductType()); + + ProductDetails.OneTimePurchaseOfferDetails oneTimePurchaseOfferDetails = details.getOneTimePurchaseOfferDetails(); + if (oneTimePurchaseOfferDetails != null) { + Dictionary oneTimePurchaseDetailsDictionary = new Dictionary(); + oneTimePurchaseDetailsDictionary.put("formatted_price", oneTimePurchaseOfferDetails.getFormattedPrice()); + oneTimePurchaseDetailsDictionary.put("price_amount_micros", oneTimePurchaseOfferDetails.getPriceAmountMicros()); + oneTimePurchaseDetailsDictionary.put("price_currency_code", oneTimePurchaseOfferDetails.getPriceCurrencyCode()); + dictionary.put("one_time_purchase_details", oneTimePurchaseDetailsDictionary); + } + + List subscriptionOfferDetailsList = details.getSubscriptionOfferDetails(); + + if (subscriptionOfferDetailsList != null && !subscriptionOfferDetailsList.isEmpty()) { + ArrayList subscriptionOfferDetailsDictionaryList = new ArrayList<>(); + + for (ProductDetails.SubscriptionOfferDetails subscriptionOfferDetails : subscriptionOfferDetailsList) { + Dictionary subscriptionOfferDetailsDictionary = new Dictionary(); + subscriptionOfferDetailsDictionary.put("offer_token", subscriptionOfferDetails.getOfferToken()); + subscriptionOfferDetailsDictionary.put("offer_tags", subscriptionOfferDetails.getOfferTags()); + + ArrayList pricingPhasesDictionaryList = new ArrayList<>(); + for (ProductDetails.PricingPhase pricingPhase : subscriptionOfferDetails.getPricingPhases().getPricingPhaseList()) { + Dictionary pricingPhasesDictionary = new Dictionary(); + pricingPhasesDictionary.put("billing_cycle_count", pricingPhase.getBillingCycleCount()); + pricingPhasesDictionary.put("billing_period", pricingPhase.getBillingPeriod()); + pricingPhasesDictionary.put("formatted_price", pricingPhase.getFormattedPrice()); + pricingPhasesDictionary.put("price_amount_micros", pricingPhase.getPriceAmountMicros()); + pricingPhasesDictionary.put("price_currency_code", pricingPhase.getPriceCurrencyCode()); + pricingPhasesDictionary.put("recurrence_mode", pricingPhase.getRecurrenceMode()); + pricingPhasesDictionaryList.add(pricingPhasesDictionary); + } + + subscriptionOfferDetailsDictionary.put("pricing_phases", pricingPhasesDictionaryList); + + subscriptionOfferDetailsDictionaryList.add(subscriptionOfferDetailsDictionary); + } + + dictionary.put("subscription_offer_details", subscriptionOfferDetailsDictionaryList); + } + return dictionary; } @@ -91,11 +118,11 @@ public static Object[] convertPurchaseListToDictionaryObjectArray(List return purchaseDictionaries; } - public static Object[] convertSkuDetailsListToDictionaryObjectArray(List skuDetails) { - Object[] skuDetailsDictionaries = new Object[skuDetails.size()]; + public static Object[] convertProductDetailsListToDictionaryObjectArray(List productDetails) { + Object[] skuDetailsDictionaries = new Object[productDetails.size()]; - for (int i = 0; i < skuDetails.size(); i++) { - skuDetailsDictionaries[i] = GooglePlayBillingUtils.convertSkuDetailsToDictionary(skuDetails.get(i)); + for (int i = 0; i < productDetails.size(); i++) { + skuDetailsDictionaries[i] = GooglePlayBillingUtils.convertProductDetailsToDictionary(productDetails.get(i)); } return skuDetailsDictionaries; diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index fef635c..1cb2d14 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Jun 15 13:39:16 CEST 2020 +#Thu Sep 01 20:58:16 CEST 2022 distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip +zipStoreBase=GRADLE_USER_HOME From 2d8a1022d9bf871f32b6f8e24cf65279e7b22461 Mon Sep 17 00:00:00 2001 From: Max Parkhomenko Date: Sun, 18 Jun 2023 18:23:53 +0300 Subject: [PATCH 2/5] Update billing library ver. 5.2.0 Support for Gradle 7.3.3 Support for Java 17 Support "getProducts" API method --- GodotGooglePlayBilling.gdap | 4 ++-- godot-google-play-billing/build.gradle | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/GodotGooglePlayBilling.gdap b/GodotGooglePlayBilling.gdap index 0a7ec01..6103f6d 100644 --- a/GodotGooglePlayBilling.gdap +++ b/GodotGooglePlayBilling.gdap @@ -2,7 +2,7 @@ name="GodotGooglePlayBilling" binary_type="local" -binary="GodotGooglePlayBilling.2.0.0-rc.1.release.aar" +binary="GodotGooglePlayBilling.2.0.0-rc.2.release.aar" [dependencies] -remote=["com.android.billingclient:billing:5.0.0"] +remote=["com.android.billingclient:billing:5.2.0"] diff --git a/godot-google-play-billing/build.gradle b/godot-google-play-billing/build.gradle index 238fe39..9a21f8e 100644 --- a/godot-google-play-billing/build.gradle +++ b/godot-google-play-billing/build.gradle @@ -3,7 +3,7 @@ plugins { } ext.pluginVersionCode = 5 -ext.pluginVersionName = "2.0.0-rc.1" +ext.pluginVersionName = "2.0.0-rc.2" android { compileSdkVersion 33 @@ -29,6 +29,6 @@ android { dependencies { implementation "androidx.legacy:legacy-support-v4:1.0.0" - implementation 'com.android.billingclient:billing:5.0.0' + implementation 'com.android.billingclient:billing:5.2.0' compileOnly fileTree(dir: 'libs', include: ['godot-lib*.aar']) } From 7aa99207b6ee95d26ac4d4d911570376c424b37e Mon Sep 17 00:00:00 2001 From: Max Parkhomenko Date: Thu, 22 Jun 2023 21:09:09 +0300 Subject: [PATCH 3/5] Add cheat sheet for add requred vars --- linux_exports.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 linux_exports.txt diff --git a/linux_exports.txt b/linux_exports.txt new file mode 100644 index 0000000..0902d81 --- /dev/null +++ b/linux_exports.txt @@ -0,0 +1,11 @@ +# use java 11 +sudo update-alternatives --config java + +# java and SDK PATH +# use your system path +# for example: +export JAVA_HOME=/usr +export ANDROID_SDK_ROOT=/home/max/coding/Android/Sdk + +# and build +./gradlew build From 9c2d2b4e1e82027f2c18848b99a82b8ef3685193 Mon Sep 17 00:00:00 2001 From: Max Parkhomenko Date: Tue, 19 Sep 2023 13:58:17 +0200 Subject: [PATCH 4/5] Builds for target SDK 34 using: - Billing API 5.2.0 - buildToolsVersion "34.0.0" - gradle-7.6.2-bin.zip - Android Gradle plugin API 7.4.2 --- build.gradle | 2 +- godot-google-play-billing/build.gradle | 6 +++--- gradle/wrapper/gradle-wrapper.properties | 4 +++- linux_exports.md | 20 ++++++++++++++++++++ linux_exports.txt | 11 ----------- 5 files changed, 27 insertions(+), 16 deletions(-) create mode 100644 linux_exports.md delete mode 100644 linux_exports.txt diff --git a/build.gradle b/build.gradle index c206ca6..b353528 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { mavenCentral() } dependencies { - classpath "com.android.tools.build:gradle:7.2.2" + classpath "com.android.tools.build:gradle:7.4.2" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/godot-google-play-billing/build.gradle b/godot-google-play-billing/build.gradle index 9a21f8e..26db85e 100644 --- a/godot-google-play-billing/build.gradle +++ b/godot-google-play-billing/build.gradle @@ -6,12 +6,12 @@ ext.pluginVersionCode = 5 ext.pluginVersionName = "2.0.0-rc.2" android { - compileSdkVersion 33 - buildToolsVersion "33.0.0" + compileSdkVersion 34 + buildToolsVersion "34.0.0" defaultConfig { minSdkVersion 18 - targetSdkVersion 33 + targetSdkVersion 34 versionCode pluginVersionCode versionName pluginVersionName } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1cb2d14..5ec5d44 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,8 @@ #Thu Sep 01 20:58:16 CEST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +#distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +#distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/linux_exports.md b/linux_exports.md new file mode 100644 index 0000000..58ccdb9 --- /dev/null +++ b/linux_exports.md @@ -0,0 +1,20 @@ +How to build (with linux :)) + +1. Clone this Git repository + +2. Set java and SDK PATH +# use your system path +# for example: +export JAVA_HOME=/usr +export ANDROID_SDK_ROOT=/home/max/coding/Android/Sdk + +3. Put `godot-lib.***.release.aar` in `./godot-google-play-billing/libs/` + +4. Run `./gradlew build` in the cloned repository + + +# use java 11 +sudo update-alternatives --config java + + + diff --git a/linux_exports.txt b/linux_exports.txt deleted file mode 100644 index 0902d81..0000000 --- a/linux_exports.txt +++ /dev/null @@ -1,11 +0,0 @@ -# use java 11 -sudo update-alternatives --config java - -# java and SDK PATH -# use your system path -# for example: -export JAVA_HOME=/usr -export ANDROID_SDK_ROOT=/home/max/coding/Android/Sdk - -# and build -./gradlew build From f211a9416d4f2900523ea2bbebaf6d4e3a08c09e Mon Sep 17 00:00:00 2001 From: Max Parkhomenko Date: Fri, 13 Oct 2023 11:44:12 +0200 Subject: [PATCH 5/5] Upgarade IAP depend to 5.2.1 --- godot-google-play-billing/build.gradle | 2 +- godot-google-play-billing/src/main/AndroidManifest.xml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/godot-google-play-billing/build.gradle b/godot-google-play-billing/build.gradle index 26db85e..efc63ba 100644 --- a/godot-google-play-billing/build.gradle +++ b/godot-google-play-billing/build.gradle @@ -29,6 +29,6 @@ android { dependencies { implementation "androidx.legacy:legacy-support-v4:1.0.0" - implementation 'com.android.billingclient:billing:5.2.0' + implementation 'com.android.billingclient:billing:5.2.1' compileOnly fileTree(dir: 'libs', include: ['godot-lib*.aar']) } diff --git a/godot-google-play-billing/src/main/AndroidManifest.xml b/godot-google-play-billing/src/main/AndroidManifest.xml index f64f031..49ecb59 100644 --- a/godot-google-play-billing/src/main/AndroidManifest.xml +++ b/godot-google-play-billing/src/main/AndroidManifest.xml @@ -1,6 +1,8 @@ + +