是否可以从Xamarin Android应用程序直接使用Google Play BillingClient?

是否可以从Xamarin Android应用程序直接使用Google Play BillingClient?,android,xamarin,xamarin.android,google-play,subscriptions,Android,Xamarin,Xamarin.android,Google Play,Subscriptions,我正在努力将订阅集成到Xamarin Android应用程序中。我在网上找到的所有关于Xamarin的例子都使用Montemagno等人的Plugin.InAppBilling 这当然非常方便,但为了谨慎起见,我想看看直接使用BillingClient类需要什么,如Google文档中所述(例如,这里:) 奇怪的是,Xamarin文档显示了如何直接使用iOS计费类,而不是Android。我认为Xamarin.GooglePlayServicesNuGet包可能包含我需要的内容,但我没有看到一个与计

我正在努力将订阅集成到Xamarin Android应用程序中。我在网上找到的所有关于Xamarin的例子都使用Montemagno等人的
Plugin.InAppBilling

这当然非常方便,但为了谨慎起见,我想看看直接使用
BillingClient
类需要什么,如Google文档中所述(例如,这里:)

奇怪的是,Xamarin文档显示了如何直接使用iOS计费类,而不是Android。我认为
Xamarin.GooglePlayServices
NuGet包可能包含我需要的内容,但我没有看到一个与计费直接相关的包

任何指点都将不胜感激。

TL;医生:是的,你可以。。。(我用它…)

“ImplementGooglePlayBilling”文档中显示的类是最终使用计费AIDL的包装类。AIDL接口是实际的计费API,AIDL定义了对它的IPC调用(这不仅是为了跨进程方法调用,也是为了安全)

Android Studio通过Gradle自动导入计费包装器和AIDL,并在您将计费api依赖项添加到
build.Gradle
文件时为您设置所有内容。(当然,这不是通过VisualStudio和MSBuild实现的选项…)

Montemagno的Android应用内计费直接使用AIDL接口方法,并以跨平台方式包装这些方法

要使用Java包装类,基本步骤是从Jcenter Maven repo获取aar(
billing-1.1.aar
),创建一个Xamarin.Android绑定库,添加aar,修复警告(以及名称空间,如果需要),并在Xamarin.Android应用程序项目中引用该库

现在,您可以直接使用Google文档,并进行一些较小的Xamarin.Android/C规范化,即:

// 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();

使用Android.BillingClient.Api.BillingClient;

使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用Android.App;
使用Android.BillingClient.Api;
使用Android.Content;
使用Android.OS;
使用Android.Runtime;
使用Android.Views;
使用Android.Widget;
使用静态Android.BillingClient.Api.BillingClient;
名称空间Android.Basic.Core
{
公共类BilingSupport:Java.Lang.Object、IPurchasesUpdatedListener、IBillingClientStateListener、ISkuDetailsResponseListener、IConsumerResponseListener
{
语境;
公共信息系统的详细信息;
Android.BillingClient.Api.BillingClient-BillingClient;
私有列表skuList=新列表(){“获取5枚硬币”、“获取10枚硬币”};
公共双语支持(上下文)
{
this.Context=Context;
billingClient=Android.billingClient.Api.billingClient.NewBuilder(this.Context).SetListener(this.Build();
billingClient.StartConnection(此);
}
公共采购()
{
如果(billingClient.IsReady)
{
var paramse=skudailsparams.NewBuilder().setskulist(skuList).SetType(Android.BillingClient.Api.BillingClient.SkuType.Inapp).Build();
billingClient.QuerySkuDetails(参数,this);
}
}
公开作废立即购买(SkuDetails SkuDetails)
{
var billingFlowParams=billingFlowParams.NewBuilder().SetSkuDetails(skuDetails.Build();
billingClient.LaunchBillingFlow(this.Context作为活动,billingFlowParams);
}
公共无效OnBillingServiceDisconnected()
{
Console.WriteLine(“计费| onBillingServiceDisconnected | DISCONNECTED”);
}
BillingSetupfinished上的公共无效(BillingResult p0)
{
如果(p0.ResponseCode==BillingResponseCode.Ok)
{
Console.WriteLine(“计费|开始连接|结果正常”);
}
其他的
{
Console.WriteLine(“计费|开始连接|结果:$billingResponseCode”);
}
}
//OnPurchasesUpdated中的响应代码7。它表示:项目已拥有。
购买时的公共无效支持(BillingResult p0,IList p1)
{
}
公共无效详细信息响应(BillingResult p0,IList p1)
{
如果(p0.ResponseCode==BillingResponseCode.Ok)
{
Console.WriteLine(“queryskuedetailsasync,responseCode:$responseCode”);
初始适配器(p1);
}
其他的
{
WriteLine(“无法查询kudetailsasync,responseCode:$responseCode”);
}
}
公开事件事件处理程序SkuDetailsLoaded;
public void InitProductAdapter(IList skuDetails)
{
this.SkuDetails=SkuDetails;
this.SkuDetailsLoaded(this,this.SkuDetails);
}
公共无效清算或消费购买()
{
var querylist=billingClient.QueryPurchases(Android.billingClient.Api.billingClient.SkuType.Inapp);
foreach(querylist中的var查询)
{
var consumerparams=consumerparams.NewBuilder().SetPurchaseToken(query.PurchaseToken.Build();
billingClient.Consume(consumerparams,this);
}        
}
消费者响应的公共无效(BillingResult p0,字符串p1)
{
如果(p0.ResponseCode==BillingResponseCode.Ok&&p1!=null)
{
WriteLine(“onPurchases更新的consumerasync,删除的购买令牌:$purchaseToken”);
}
其他的
{
WriteLine(“onpurchasesomeproblems:$responseCode”);
}
}
}
}
P
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");
            }
        }

       
    }
}