diff --git a/source/com.android.billingclient/billing/Additions/Additions.cs b/source/com.android.billingclient/billing/Additions/Additions.cs index 0c13c4a69..763f0ed2e 100644 --- a/source/com.android.billingclient/billing/Additions/Additions.cs +++ b/source/com.android.billingclient/billing/Additions/Additions.cs @@ -4,6 +4,18 @@ namespace Android.BillingClient.Api { + public partial class BillingResult + { + internal BillingResult Clone() + { + return BillingResult.NewBuilder() + .SetResponseCode((int)ResponseCode) + .SetDebugMessage(DebugMessage) + .SetOnPurchasesUpdatedSubResponseCode(OnPurchasesUpdatedSubResponseCode) + .Build(); + } + } + public class ConsumeResult { public BillingResult BillingResult { get; set; } @@ -33,12 +45,7 @@ public QueryProductDetailsResult() { } public BillingResult Result { get; set; } - [Obsolete ($"Use {nameof(ProductDetailsList)} instead")] - public IList ProductDetails - { - get => ProductDetailsList; - set { /* Obsolete property setter does nothing */ } - } + public IList ProductDetails { get; set; } } public class QueryPurchasesResult @@ -129,9 +136,14 @@ public Task QueryProductDetailsAsync(QueryProductDeta { var tcs = new TaskCompletionSource(); + // NOTE: this creates a new QueryProductDetailsResult to avoid ObjectDisposedException var listener = new InternalProductDetailsResponseListener { - ProductDetailsResponseHandler = (r, queryResult) => tcs.TrySetResult(queryResult) + ProductDetailsResponseHandler = (r, s) => tcs.TrySetResult(new QueryProductDetailsResult + { + Result = r, + ProductDetails = s + }) }; QueryProductDetails(productDetailsParams, listener); @@ -196,7 +208,10 @@ internal class InternalAcknowledgePurchaseResponseListener : Java.Lang.Object, I public Action AcknowledgePurchaseResponseHandler { get; set; } public void OnAcknowledgePurchaseResponse(BillingResult result) - => AcknowledgePurchaseResponseHandler?.Invoke(result); + { + // Create a copy of the BillingResult to ensure it stays alive after the callback + AcknowledgePurchaseResponseHandler?.Invoke(result.Clone()); + } } internal class InternalBillingClientStateListener : Java.Lang.Object, IBillingClientStateListener @@ -209,21 +224,30 @@ public void OnBillingServiceDisconnected() => BillingServiceDisconnectedHandler?.Invoke(); public void OnBillingSetupFinished(BillingResult result) - => BillingSetupFinishedHandler?.Invoke(result); + { + // Create a copy of the BillingResult to ensure it stays alive after the callback + BillingSetupFinishedHandler?.Invoke(result.Clone()); + } } internal class InternalConsumeResponseListener : Java.Lang.Object, IConsumeResponseListener { public Action ConsumeResponseHandler { get; set; } public void OnConsumeResponse(BillingResult result, string str) - => ConsumeResponseHandler?.Invoke(result, str); + { + // Create a copy of the BillingResult to ensure it stays alive after the callback + ConsumeResponseHandler?.Invoke(result.Clone(), str); + } } internal class InternalPriceChangeConfirmationListener : Java.Lang.Object //, IPriceChangeConfirmationListener { public Action PriceChangeConfirmationHandler { get; set; } public void OnPriceChangeConfirmationResult(BillingResult result) - => PriceChangeConfirmationHandler?.Invoke(result); + { + // Create a copy of the BillingResult to ensure it stays alive after the callback + PriceChangeConfirmationHandler?.Invoke(result.Clone()); + } } internal class InternalPurchaseHistoryResponseListener : Java.Lang.Object, IPurchaseHistoryResponseListener @@ -231,14 +255,20 @@ internal class InternalPurchaseHistoryResponseListener : Java.Lang.Object, IPurc public Action> PurchaseHistoryResponseHandler { get; set; } public void OnPurchaseHistoryResponse(BillingResult result, IList history) - => PurchaseHistoryResponseHandler?.Invoke(result, history); + { + // Create a copy of the BillingResult to ensure it stays alive after the callback + PurchaseHistoryResponseHandler?.Invoke(result.Clone(), history); + } } internal class InternalPurchasesUpdatedListener : Java.Lang.Object, IPurchasesUpdatedListener { public Action> PurchasesUpdatedHandler { get; set; } public void OnPurchasesUpdated(BillingResult result, IList purchases) - => PurchasesUpdatedHandler?.Invoke(result, purchases); + { + // Create a copy of the BillingResult to ensure it stays alive after the callback + PurchasesUpdatedHandler?.Invoke(result.Clone(), purchases); + } } [Obsolete("Use QueryProductDetailsAsync(QueryProductDetailsParams) instead")] @@ -252,13 +282,12 @@ public void OnSkuDetailsResponse(BillingResult result, IList skuDeta internal class InternalProductDetailsResponseListener : Java.Lang.Object, IProductDetailsResponseListener { - public Action ProductDetailsResponseHandler { get; set; } + public Action> ProductDetailsResponseHandler { get; set; } public void OnProductDetailsResponse(BillingResult result, QueryProductDetailsResult queryResult) { - queryResult ??= new(); - queryResult.Result = result; - ProductDetailsResponseHandler?.Invoke(result, queryResult); + // Create a copy of the BillingResult to ensure it stays alive after the callback + ProductDetailsResponseHandler?.Invoke(result.Clone(), queryResult?.ProductDetailsList); } } diff --git a/source/com.android.billingclient/billing/PublicAPI/PublicAPI.Unshipped.txt b/source/com.android.billingclient/billing/PublicAPI/PublicAPI.Unshipped.txt index 7df2d4eb1..208f63051 100644 --- a/source/com.android.billingclient/billing/PublicAPI/PublicAPI.Unshipped.txt +++ b/source/com.android.billingclient/billing/PublicAPI/PublicAPI.Unshipped.txt @@ -315,7 +315,12 @@ Android.BillingClient.Api.QueryProductDetailsParams.Product.Zza() -> string! Android.BillingClient.Api.QueryProductDetailsParams.Product.Zzb() -> string! Android.BillingClient.Api.QueryProductDetailsParams.Zzb() -> string! Android.BillingClient.Api.QueryProductDetailsResult +Android.BillingClient.Api.QueryProductDetailsResult.ProductDetails.get -> System.Collections.Generic.IList! +Android.BillingClient.Api.QueryProductDetailsResult.ProductDetails.set -> void Android.BillingClient.Api.QueryProductDetailsResult.ProductDetailsList.get -> System.Collections.Generic.IList! +Android.BillingClient.Api.QueryProductDetailsResult.QueryProductDetailsResult() -> void +Android.BillingClient.Api.QueryProductDetailsResult.Result.get -> Android.BillingClient.Api.BillingResult! +Android.BillingClient.Api.QueryProductDetailsResult.Result.set -> void Android.BillingClient.Api.QueryProductDetailsResult.UnfetchedProductList.get -> System.Collections.Generic.IList! Android.BillingClient.Api.QueryPurchaseHistoryParams Android.BillingClient.Api.QueryPurchaseHistoryParams.Builder