Is it possible to directly consume the Google Play BillingClient from a Xamarin Android app?
Asked Answered
I

2

5

I'm working on integrating subscriptions into a Xamarin Android app. All the examples I can find online specific to Xamarin use the Plugin.InAppBilling from Montemagno, et al.

This is certainly very convenient, but just for the sake of due dilligence, I want to look at what it would take to directly consume the BillingClient classes, as described in Google's documentation (for example, here: https://developer.android.com/google/play/billing/billing_java_kotlin).

Strangely, Xamarin documentation shows how to directly consume the iOS billing classes, but not the ones for Android. I thought that the Xamarin.GooglePlayServices NuGet packages might contain what I need, but I don't see one that seems to directly pertain to billing.

Any pointers would be greatly appreciated.

Identify answered 8/7, 2018 at 16:54 Comment(1)
the Plugin.InAppBilling source should be available on GitHubFulltime
C
7

TL;DR : Yes you can... (I use it...)

The classes that are shown in "Implement Google Play Billing" docs are wrapper classes that eventually make use of the Billing AIDL. That AIDL interface is THE actual billing API and the AIDL defines those IPC calls to it (this is not just for the cross-process method calling, but also for security)...

Android Studio, via Gradle, automatically imports the billing wrapper and AIDL and sets everything up for you when you add the billing api dependence to the build.gradle file. (of course, that is not an option via Visual Studio and MSBuild...)

Montemagno's Android in-app billing directly uses the AIDL interface methods and wraps those in a cross-platform way...

To use the Java wrapper classes, the basic steps are to grab the aar (billing-1.1.aar) from Jcenter Maven repo, create a Xamarin.Android binding library, add the aar, fix-up the warning (and namespace if desire) and reference that library in your Xamarin.Android application project...

Now you can directly use the Google docs, with some minor Xamarin.Android/C# normalizations, i.e.:

// I did not alter the original Java namespace in the binding lib
using Com.Android.Billingclient.Api; 

~~~

var billingClient = BillingClient
    .NewBuilder(this)
    .SetListener(this)
    .Build();

~~~

var flowParams = BillingFlowParams
    .NewBuilder()
    .SetSku("StackOverflowXamarinTag")
    .SetType("Answer")
    .Build();
Clifford answered 8/7, 2018 at 18:0 Comment(3)
Warning: AIDL is now deprecated and will be removed in a future release. To implement Google Play Billing features, use the Google Play Billing library. developer.android.com/google/play/billing/api Would be nice if xamarin would provide and official nuget. This has me worriedOmmatidium
@Ommatidium is that what you are looking for? nuget.org/packages/Xamarin.Android.Google.BillingClientKonstanze
@batmaci Yes. Glad it is available nowOmmatidium
A
2

using Android.BillingClient.Api.BillingClient; https://www.nuget.org/packages/Xamarin.Android.Google.BillingClient/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.BillingClient.Api;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using static Android.BillingClient.Api.BillingClient;

namespace Android.Basic.Core
{
    public  class BilingSupport : Java.Lang.Object, IPurchasesUpdatedListener, IBillingClientStateListener, ISkuDetailsResponseListener, IConsumeResponseListener
    {
        Context Context;
        public IList<SkuDetails> SkuDetails;
        Android.BillingClient.Api.BillingClient billingClient;
        private List<string> skuList = new List<string>() { "get_5_coins", "get_10_coins" };
       
        public BilingSupport(Context context)
        {
            this.Context = context;
            billingClient = Android.BillingClient.Api.BillingClient.NewBuilder(this.Context).SetListener(this).Build();
            billingClient.StartConnection(this);
        }
       
        public void LoadPurchases()
        {

            if (billingClient.IsReady)
            {
                var paramse = SkuDetailsParams.NewBuilder().SetSkusList(skuList).SetType(Android.BillingClient.Api.BillingClient.SkuType.Inapp).Build();
                billingClient.QuerySkuDetails(paramse, this);
            }
        }
        public void PurchaseNow(SkuDetails skuDetails)
        {
            var billingFlowParams = BillingFlowParams.NewBuilder().SetSkuDetails(skuDetails).Build();
            billingClient.LaunchBillingFlow(this.Context as Activity, billingFlowParams);
        }
        

        public void OnBillingServiceDisconnected()
        {
            Console.WriteLine("BILLING | onBillingServiceDisconnected | DISCONNECTED");
        }

        public void OnBillingSetupFinished(BillingResult p0)
        {
            if (p0.ResponseCode == BillingResponseCode.Ok)
            {

                Console.WriteLine("BILLING | startConnection | RESULT OK");

            }
            else
            {
                Console.WriteLine("BILLING | startConnection | RESULT: $billingResponseCode");
            }
        }
        //Response code 7 in OnPurchasesUpdated.It means: Item Already Owned.
        public void OnPurchasesUpdated(BillingResult p0, IList<Purchase> p1)
        {
            
        }
        public void OnSkuDetailsResponse(BillingResult p0, IList<SkuDetails> p1)
        {
            if (p0.ResponseCode == BillingResponseCode.Ok)
            {
                Console.WriteLine("querySkuDetailsAsync, responseCode: $responseCode");
                InitProductAdapter(p1);

            }
            else
            {
                Console.WriteLine("Can't querySkuDetailsAsync, responseCode: $responseCode");
            }
        }
        public event EventHandler<IList<SkuDetails>> SkuDetailsLoaded;
        public void InitProductAdapter(IList<SkuDetails> skuDetails)
        {
            this.SkuDetails = skuDetails;
            this.SkuDetailsLoaded(this, this.SkuDetails);
        }
        public void ClearOrConsumeAllPurchases()
        {
            
            var querylist = billingClient.QueryPurchases(Android.BillingClient.Api.BillingClient.SkuType.Inapp).PurchasesList;
            foreach (var query in querylist)
            {
                var consumeParams = ConsumeParams.NewBuilder().SetPurchaseToken(query.PurchaseToken).Build();
                billingClient.Consume(consumeParams, this);
            }        

        }

        public void OnConsumeResponse(BillingResult p0, string p1)
        {
            if (p0.ResponseCode == BillingResponseCode.Ok && p1 != null)
            {
                Console.WriteLine("onPurchases Updated consumeAsync, purchases token removed: $purchaseToken");
            }
            else
            {
                Console.WriteLine("onPurchases some troubles happened: $responseCode");
            }
        }

       
    }
}
Add answered 29/1, 2021 at 11:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.