From 06a7c77802c8069e44d8baa3c3f948278d990623 Mon Sep 17 00:00:00 2001 From: Andrei Date: Tue, 6 Mar 2018 21:43:08 +0300 Subject: [PATCH 1/2] https://github.com/jamesmontemagno/InAppBillingPlugin/issues/125 --- .../InAppBillingImplementation.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Plugin.InAppBilling.Android/InAppBillingImplementation.cs b/src/Plugin.InAppBilling.Android/InAppBillingImplementation.cs index 0cfc483..df8a8f3 100644 --- a/src/Plugin.InAppBilling.Android/InAppBillingImplementation.cs +++ b/src/Plugin.InAppBilling.Android/InAppBillingImplementation.cs @@ -286,12 +286,9 @@ public async override Task PurchaseAsync(string productId, async Task PurchaseAsync(string productSku, string itemType, string payload, IInAppBillingVerifyPurchase verifyPurchase) { - if (tcsPurchase != null && !tcsPurchase.Task.IsCompleted) return null; - tcsPurchase = new TaskCompletionSource(); - Bundle buyIntentBundle = serviceConnection.Service.GetBuyIntent(3, Context.PackageName, productSku, itemType, payload); var response = GetResponseCodeFromBundle(buyIntentBundle); @@ -323,9 +320,13 @@ async Task PurchaseAsync(string productSku, string itemType, string pa throw new InAppBillingPurchaseException(PurchaseError.AlreadyOwned); } + var pendingIntent = buyIntentBundle.GetParcelable(RESPONSE_BUY_INTENT) as PendingIntent; - if (pendingIntent != null) - Context.StartIntentSenderForResult(pendingIntent.IntentSender, PURCHASE_REQUEST_CODE, new Intent(), 0, 0, 0); + if (pendingIntent == null) + throw new InAppBillingPurchaseException(PurchaseError.GeneralError); + + tcsPurchase = new TaskCompletionSource(); + Context.StartIntentSenderForResult(pendingIntent.IntentSender, PURCHASE_REQUEST_CODE, new Intent(), 0, 0, 0); var result = await tcsPurchase.Task; From 0d2505ace9070a4673e5b8ac2e6646ae4be1f2a5 Mon Sep 17 00:00:00 2001 From: Andrei Date: Tue, 6 Mar 2018 21:48:16 +0300 Subject: [PATCH 2/2] added purchase lock object --- .../InAppBillingImplementation.cs | 77 ++++++++++--------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/src/Plugin.InAppBilling.Android/InAppBillingImplementation.cs b/src/Plugin.InAppBilling.Android/InAppBillingImplementation.cs index df8a8f3..468921e 100644 --- a/src/Plugin.InAppBilling.Android/InAppBillingImplementation.cs +++ b/src/Plugin.InAppBilling.Android/InAppBillingImplementation.cs @@ -286,47 +286,51 @@ public async override Task PurchaseAsync(string productId, async Task PurchaseAsync(string productSku, string itemType, string payload, IInAppBillingVerifyPurchase verifyPurchase) { - if (tcsPurchase != null && !tcsPurchase.Task.IsCompleted) - return null; + lock (purchaseLocker) + { + if (tcsPurchase != null && !tcsPurchase.Task.IsCompleted) + return null; - Bundle buyIntentBundle = serviceConnection.Service.GetBuyIntent(3, Context.PackageName, productSku, itemType, payload); - var response = GetResponseCodeFromBundle(buyIntentBundle); + Bundle buyIntentBundle = serviceConnection.Service.GetBuyIntent(3, Context.PackageName, productSku, itemType, payload); + var response = GetResponseCodeFromBundle(buyIntentBundle); + + switch (response) + { + case 0: + //OK to purchase + break; + case 1: + //User Cancelled, should try again + throw new InAppBillingPurchaseException(PurchaseError.UserCancelled); + case 2: + //Network connection is down + throw new InAppBillingPurchaseException(PurchaseError.ServiceUnavailable); + case 3: + //Billing Unavailable + throw new InAppBillingPurchaseException(PurchaseError.BillingUnavailable); + case 4: + //Item Unavailable + throw new InAppBillingPurchaseException(PurchaseError.ItemUnavailable); + case 5: + //Developer Error + throw new InAppBillingPurchaseException(PurchaseError.DeveloperError); + case 6: + //Generic Error + throw new InAppBillingPurchaseException(PurchaseError.GeneralError); + case 7: + //already purchased + throw new InAppBillingPurchaseException(PurchaseError.AlreadyOwned); + } - switch (response) - { - case 0: - //OK to purchase - break; - case 1: - //User Cancelled, should try again - throw new InAppBillingPurchaseException(PurchaseError.UserCancelled); - case 2: - //Network connection is down - throw new InAppBillingPurchaseException(PurchaseError.ServiceUnavailable); - case 3: - //Billing Unavailable - throw new InAppBillingPurchaseException(PurchaseError.BillingUnavailable); - case 4: - //Item Unavailable - throw new InAppBillingPurchaseException(PurchaseError.ItemUnavailable); - case 5: - //Developer Error - throw new InAppBillingPurchaseException(PurchaseError.DeveloperError); - case 6: - //Generic Error - throw new InAppBillingPurchaseException(PurchaseError.GeneralError); - case 7: - //already purchased - throw new InAppBillingPurchaseException(PurchaseError.AlreadyOwned); - } + var pendingIntent = buyIntentBundle.GetParcelable(RESPONSE_BUY_INTENT) as PendingIntent; + if (pendingIntent == null) + throw new InAppBillingPurchaseException(PurchaseError.GeneralError); - var pendingIntent = buyIntentBundle.GetParcelable(RESPONSE_BUY_INTENT) as PendingIntent; - if (pendingIntent == null) - throw new InAppBillingPurchaseException(PurchaseError.GeneralError); + tcsPurchase = new TaskCompletionSource(); - tcsPurchase = new TaskCompletionSource(); - Context.StartIntentSenderForResult(pendingIntent.IntentSender, PURCHASE_REQUEST_CODE, new Intent(), 0, 0, 0); + Context.StartIntentSenderForResult(pendingIntent.IntentSender, PURCHASE_REQUEST_CODE, new Intent(), 0, 0, 0); + } var result = await tcsPurchase.Task; @@ -566,6 +570,7 @@ class PurchaseResponse InAppBillingServiceConnection serviceConnection; static TaskCompletionSource tcsPurchase; + static readonly object purchaseLocker = new object(); static bool ValidOwnedItems(Bundle purchased) {