I am using Plugin.InAppBilling
for subscription in my MAUI application. For the Android part I need to do Acknowledgement after successful purchase.
Option 1: ConsumePurchaseAsync
if (DeviceInfo.Platform == DevicePlatform.Android)
{
var consumed = await CrossInAppBilling.Current.ConsumePurchaseAsync(productId, purchase.PurchaseToken);
if (!consumed)
{
Debug.WriteLine("Purchase consumption/acknowledgment failed");
return;
}
Debug.WriteLine("Purchase acknowledged successfully");
}
But I am getting below exception:
16:05:10:848 [0:] purchaseEx:>>Plugin.InAppBilling.InAppBillingPurchaseException: Unable to process purchase.
16:05:10:848 at Plugin.InAppBilling.InAppBillingImplementation.ParseBillingResult(BillingResult result, Boolean ignoreInvalidProducts)
16:05:10:848 at Plugin.InAppBilling.InAppBillingImplementation.ConsumePurchaseAsync(String productId, String transactionIdentifier)
16:05:10:848 at MyProjectName.Pages.ListPlansPage.PlanClicked(Object sender, EventArgs e) in E:\My Projects\MAUI
16:05:10:848 eedhelp-app-maui\MyProjectName\Pages\Subscription\ListPlansPage.xaml.cs:line 371
16:05:10:909 The thread 25 has exited with code 0 (0x0).
Exception is on the below line:
var consumed = await CrossInAppBilling.Current.ConsumePurchaseAsync(productId, purchase.PurchaseToken);
Option 2: DependencyService
Created an interface: IPurchaseAcknowledgment
public interface IPurchaseAcknowledgment
{
Task<bool> AcknowledgePurchaseAsync(string purchaseToken);
}
Implemented IPurchaseAcknowledgment
on MainActivity
:
public class MainActivity : MauiAppCompatActivity, IPurchaseAcknowledgment
{
/// <summary>
/// Acknowledge purchase using Google Play BillingClient
/// </summary>
public async Task<bool> AcknowledgePurchaseAsync(string purchaseToken)
{
var billingClient = BillingClient.NewBuilder(Android.App.Application.Context)
.SetListener(new PurchaseUpdateListener()) // You can implement your own listener if needed
.EnablePendingPurchases()
.Build();
// Connect to the BillingClient
var billingConnectionTaskCompletionSource = new TaskCompletionSource<BillingResult>();
billingClient.StartConnection(new BillingClientStateListener(
onBillingSetupFinished: billingResult => billingConnectionTaskCompletionSource.SetResult(billingResult),
onBillingServiceDisconnected: () => billingConnectionTaskCompletionSource.SetException(new System.Exception("Billing service disconnected"))
));
var connectionResult = await billingConnectionTaskCompletionSource.Task;
if (connectionResult.ResponseCode != BillingResponseCode.Ok)
{
return false; // Connection failed
}
// Acknowledge the purchase
var acknowledgeParams = AcknowledgePurchaseParams.NewBuilder()
.SetPurchaseToken(purchaseToken)
.Build();
var acknowledgeTaskCompletionSource = new TaskCompletionSource<BillingResult>();
billingClient.AcknowledgePurchase(acknowledgeParams, new AcknowledgePurchaseResponseListener(
result => acknowledgeTaskCompletionSource.SetResult(result)
));
var acknowledgeResult = await acknowledgeTaskCompletionSource.Task;
// End connection
billingClient.EndConnection();
return acknowledgeResult.ResponseCode == BillingResponseCode.Ok;
}
/// <summary>
/// Listener for purchase updates (can be extended if required)
/// </summary>
private class PurchaseUpdateListener : Java.Lang.Object, IPurchasesUpdatedListener
{
public void OnPurchasesUpdated(BillingResult billingResult, IList<Purchase> purchases)
{
// Handle purchase updates here if needed
}
}
/// <summary>
/// Listener for billing client state
/// </summary>
private class BillingClientStateListener : Java.Lang.Object, IBillingClientStateListener
{
private readonly System.Action<BillingResult> onBillingSetupFinished;
private readonly System.Action onBillingServiceDisconnected;
public BillingClientStateListener(System.Action<BillingResult> onBillingSetupFinished, System.Action onBillingServiceDisconnected)
{
this.onBillingSetupFinished = onBillingSetupFinished;
this.onBillingServiceDisconnected = onBillingServiceDisconnected;
}
public void OnBillingSetupFinished(BillingResult billingResult)
{
onBillingSetupFinished?.Invoke(billingResult);
}
public void OnBillingServiceDisconnected()
{
onBillingServiceDisconnected?.Invoke();
}
}
/// <summary>
/// Listener for acknowledge purchase response
/// </summary>
private class AcknowledgePurchaseResponseListener : Java.Lang.Object, IAcknowledgePurchaseResponseListener
{
private readonly System.Action<BillingResult> onAcknowledgeResponse;
public AcknowledgePurchaseResponseListener(System.Action<BillingResult> onAcknowledgeResponse)
{
this.onAcknowledgeResponse = onAcknowledgeResponse;
}
public void OnAcknowledgePurchaseResponse(BillingResult billingResult)
{
onAcknowledgeResponse?.Invoke(billingResult);
}
}
}
Finally after plan purchase:
if (DeviceInfo.Platform == DevicePlatform.Android)
{
var acknowledgmentService = DependencyService.Get<IPurchaseAcknowledgment>();
var acknowledged = await acknowledgmentService.AcknowledgePurchaseAsync(purchase.PurchaseToken);
if (!acknowledged)
{
Debug.WriteLine("Purchase acknowledgment failed");
return;
}
Debug.WriteLine("Purchase acknowledged successfully");
}
But getting below exception:
16:23:24:835 [0:] exception:>>System.NullReferenceException: Object reference not set to an instance of an object.
16:23:24:835 at MyProjectName.Pages.ListPlansPage.PlanClicked(Object sender, EventArgs e) in E:\My Projects\MAUI
16:23:24:835 eedhelp-app-maui\MyProjectName\Pages\Subscription\ListPlansPage.xaml.cs:line 383
Exception is on the below line:
var acknowledged = await acknowledgmentService.AcknowledgePurchaseAsync(purchase.PurchaseToken);
Is there any other solution?
UPDATE
I tried like below:
var consumed = await CrossInAppBilling.Current.ConsumePurchaseAsync(purchase.ProductId, purchase.TransactionIdentifier);
But getting below exception:
12:43:02:766 [0:] purchaseEx:>>Plugin.InAppBilling.InAppBillingPurchaseException: Unable to process purchase.
12:43:02:766 at Plugin.InAppBilling.InAppBillingImplementation.ParseBillingResult(BillingResult result, Boolean ignoreInvalidProducts)
12:43:02:766 at Plugin.InAppBilling.InAppBillingImplementation.ConsumePurchaseAsync(String productId, String transactionIdentifier)
12:43:02:766 at MyProjectName.Pages.ListPlansPage.PlanClicked(Object sender, EventArgs e) in E:\My Projects\MAUI
12:43:02:766 eedhelp-app-maui\MyProjectName\Pages\Subscription\ListPlansPage.xaml.cs:line 372
Im using v 7.1.3 and after calling the purchase Like this with my own internal productId:
purchase = await CrossInAppBilling.Current.PurchaseAsync(productId.ToString(), ItemType.Subscription);
i do the acknowledge like this:
//possibility that a null came through.
if (purchase == null) {
//did not purchase
return false;
}else if (purchase.State == PurchaseState.Purchased) {
#if ANDROID
// only need to finalize if on Android unless you turn off auto finalize on iOS
//V 7.1.3
IEnumerable<(string, bool)> ack;
ack = await CrossInAppBilling.Current.FinalizePurchaseAsync(purchase.TransactionIdentifier);
// TODO: Handle if acknowledge was successful or not
#endif
}