Skip to content

Commit

Permalink
Merge pull request #25 from natetrost/master
Browse files Browse the repository at this point in the history
Play Billing Library plugin 1.1 patch for PBL v4
  • Loading branch information
Fredia Huya-Kouadio authored Nov 8, 2021
2 parents 6099435 + bf09bf2 commit 079b111
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 29 deletions.
4 changes: 2 additions & 2 deletions GodotGooglePlayBilling.gdap
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

name="GodotGooglePlayBilling"
binary_type="local"
binary="GodotGooglePlayBilling.1.0.1.release.aar"
binary="GodotGooglePlayBilling.1.1.0.release.aar"

[dependencies]
remote=["com.android.billingclient:billing:3.0.0"]
remote=["com.android.billingclient:billing:4.0.0"]
12 changes: 6 additions & 6 deletions godot-google-play-billing/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ plugins {
id 'com.android.library'
}

ext.pluginVersionCode = 2
ext.pluginVersionName = "1.0.1"
ext.pluginVersionCode = 3
ext.pluginVersionName = "1.1.0"

android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
compileSdkVersion 30
buildToolsVersion "30.0.3"

defaultConfig {
minSdkVersion 18
targetSdkVersion 29
targetSdkVersion 30
versionCode pluginVersionCode
versionName pluginVersionName
}
Expand All @@ -25,6 +25,6 @@ android {

dependencies {
implementation "androidx.legacy:legacy-support-v4:1.0.0"
implementation 'com.android.billingclient:billing:3.0.0'
implementation 'com.android.billingclient:billing:4.0.0'
compileOnly fileTree(dir: 'libs', include: ['godot-lib*.aar'])
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@
import com.android.billingclient.api.BillingResult;
import com.android.billingclient.api.ConsumeParams;
import com.android.billingclient.api.ConsumeResponseListener;
import com.android.billingclient.api.PriceChangeConfirmationListener;
import com.android.billingclient.api.PriceChangeFlowParams;
import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.PurchasesResponseListener;
import com.android.billingclient.api.PurchasesUpdatedListener;
import com.android.billingclient.api.SkuDetails;
import com.android.billingclient.api.SkuDetailsParams;
Expand All @@ -59,10 +62,12 @@
import java.util.List;
import java.util.Set;

public class GodotGooglePlayBilling extends GodotPlugin implements PurchasesUpdatedListener, BillingClientStateListener {
public class GodotGooglePlayBilling extends GodotPlugin implements PurchasesUpdatedListener, BillingClientStateListener, PriceChangeConfirmationListener {

private final BillingClient billingClient;
private final HashMap<String, SkuDetails> skuDetailsCache = new HashMap<>(); // sku → SkuDetails
private String obfuscatedAccountId;
private String obfuscatedProfileId;

public GodotGooglePlayBilling(Godot godot) {
super(godot);
Expand All @@ -72,6 +77,8 @@ public GodotGooglePlayBilling(Godot godot) {
.enablePendingPurchases()
.setListener(this)
.build();
obfuscatedAccountId = "";
obfuscatedProfileId = "";
}

public void startConnection() {
Expand All @@ -86,20 +93,27 @@ public boolean isReady() {
return this.billingClient.isReady();
}

public Dictionary queryPurchases(String type) {
Purchase.PurchasesResult result = billingClient.queryPurchases(type);

Dictionary returnValue = new Dictionary();
if (result.getBillingResult().getResponseCode() == BillingClient.BillingResponseCode.OK) {
returnValue.put("status", 0); // OK = 0
returnValue.put("purchases", GooglePlayBillingUtils.convertPurchaseListToDictionaryObjectArray(result.getPurchasesList()));
} else {
returnValue.put("status", 1); // FAILED = 1
returnValue.put("response_code", result.getBillingResult().getResponseCode());
returnValue.put("debug_message", result.getBillingResult().getDebugMessage());
}
public int getConnectionState() {
return billingClient.getConnectionState();
}

return returnValue;
public void queryPurchases(String type) {
billingClient.queryPurchasesAsync(type, new PurchasesResponseListener() {
@Override
public void onQueryPurchasesResponse(BillingResult billingResult,
List<Purchase> purchaseList) {
Dictionary returnValue = new Dictionary();
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
returnValue.put("status", 0); // OK = 0
returnValue.put("purchases", GooglePlayBillingUtils.convertPurchaseListToDictionaryObjectArray(purchaseList));
} else {
returnValue.put("status", 1); // FAILED = 1
returnValue.put("response_code", billingResult.getResponseCode());
returnValue.put("debug_message", billingResult.getDebugMessage());
}
emitSignal("query_purchases_response", (Object)returnValue);
}
});
}

public void querySkuDetails(final String[] list, String type) {
Expand Down Expand Up @@ -173,7 +187,37 @@ 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;
}

public Dictionary purchase(String sku) {
return purchaseInternal("", sku,
BillingFlowParams.ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY);
}

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)) {
Dictionary returnValue = new Dictionary();
returnValue.put("status", 1); // FAILED = 1
Expand All @@ -183,11 +227,23 @@ public Dictionary purchase(String sku) {
}

SkuDetails skuDetails = skuDetailsCache.get(sku);
BillingFlowParams purchaseParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.build();

BillingResult result = billingClient.launchBillingFlow(getActivity(), purchaseParams);
BillingFlowParams.Builder purchaseParamsBuilder = BillingFlowParams.newBuilder();
purchaseParamsBuilder.setSkuDetails(skuDetails);
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();
purchaseParamsBuilder.setSubscriptionUpdateParams(updateParams);
}
BillingResult result = billingClient.launchBillingFlow(getActivity(), purchaseParamsBuilder.build());

Dictionary returnValue = new Dictionary();
if (result.getResponseCode() == BillingClient.BillingResponseCode.OK) {
Expand All @@ -199,6 +255,13 @@ public Dictionary purchase(String sku) {
}

return returnValue;
}
public void setObfuscatedAccountId(String accountId) {
obfuscatedAccountId = accountId;
}

public void setObfuscatedProfileId(String profileId) {
obfuscatedProfileId = profileId;
}

@Override
Expand All @@ -210,6 +273,16 @@ public void onPurchasesUpdated(final BillingResult billingResult, @Nullable fina
}
}

@Override
public void onPriceChangeConfirmationResult(BillingResult billingResult) {
emitSignal("price_change_acknowledged", billingResult.getResponseCode());
}

@Override
public void onMainResume() {
emitSignal("billing_resume");
}

@NonNull
@Override
public String getPluginName() {
Expand All @@ -219,7 +292,7 @@ public String getPluginName() {
@NonNull
@Override
public List<String> getPluginMethods() {
return Arrays.asList("startConnection", "endConnection", "purchase", "querySkuDetails", "isReady", "queryPurchases", "acknowledgePurchase", "consumePurchase");
return Arrays.asList("startConnection", "endConnection", "confirmPriceChange", "purchase", "updateSubscription", "querySkuDetails", "isReady", "getConnectionState", "queryPurchases", "acknowledgePurchase", "consumePurchase");
}

@NonNull
Expand All @@ -229,11 +302,14 @@ public Set<SignalInfo> getPluginSignals() {

signals.add(new SignalInfo("connected"));
signals.add(new SignalInfo("disconnected"));
signals.add(new SignalInfo("billing_resume"));
signals.add(new SignalInfo("connect_error", Integer.class, String.class));
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("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));
signals.add(new SignalInfo("purchase_consumed", String.class));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.SkuDetails;

import java.util.ArrayList;
import java.util.List;

public class GooglePlayBillingUtils {
Expand All @@ -45,8 +46,14 @@ public static Dictionary convertPurchaseToDictionary(Purchase purchase) {
dictionary.put("purchase_state", purchase.getPurchaseState());
dictionary.put("purchase_time", purchase.getPurchaseTime());
dictionary.put("purchase_token", purchase.getPurchaseToken());
dictionary.put("quantity", purchase.getQuantity());
dictionary.put("signature", purchase.getSignature());
dictionary.put("sku", purchase.getSku());
// PBL V4 replaced getSku with getSkus to support multi-sku purchases,
// use the first entry for "sku" and generate an array for "skus"
ArrayList<String> skus = purchase.getSkus();
dictionary.put("sku", skus.get(0));
String[] skusArray = skus.toArray(new String[0]);
dictionary.put("skus", skusArray);
dictionary.put("is_acknowledged", purchase.isAcknowledged());
dictionary.put("is_auto_renewing", purchase.isAutoRenewing());
return dictionary;
Expand Down

0 comments on commit 079b111

Please sign in to comment.