如何在Xamarin.Android中异步实现App In BillingClient中的Android

问题描述 投票:0回答:1

我正在尝试在C#中实现以下Java代码,引用Android documentation

List<String> skuList = new ArrayList<> ();
skuList.add("premium_upgrade");
skuList.add("gas");
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(SkuType.INAPP);
billingClient.querySkuDetailsAsync(params.build(),
    new SkuDetailsResponseListener() {
        @Override
        public void onSkuDetailsResponse(BillingResult billingResult,
                List<SkuDetails> skuDetailsList) {
            // Process the result.
        }
    });

我在这里有2个问题。我以为我会在如下所示的UI线程之外的单独线程上运行此代码,以在网络连接完成后保持ui的响应速度。那是正确的方法吗? QuerySkuDetailsAsync称为异步,但未实现为异步。这应该如何工作以及如何在c#中处理,因为它将触发并遗忘,但监听器可以处理响应。

public async Task<List<InAppBillingProduct>> GetProductsAsync(List<string> ProductIds)
        {
 var getSkuDetailsTask = Task.Factory.StartNew(() =>
            {

                var prms = SkuDetailsParams.NewBuilder();
                var type =   BillingClient.SkuType.Inapp;
                prms.SetSkusList(ProductIds).SetType(type);

                BillingClient.QuerySkuDetailsAsync(prms.Build(), new SkuDetailsResponseListener());

                return InAppBillingProducts;
            });
     return await getSkuDetailsTask;
        }

关于第二个问题的第二个问题,如下。如何从侦听器返回值。我需要InAppBillingProduct对象的返回列表。

 public class SkuDetailsResponseListener : Java.Lang.Object, ISkuDetailsResponseListener
    {
        public void OnSkuDetailsResponse(BillingResult billingResult, IList<SkuDetails> skus)
        {
             if (billingResult.ResponseCode == BillingResponseCode.Ok)
            {
                   // get list of Products here and return
            }
        }
    }
xamarin xamarin.android in-app-billing
1个回答
0
投票
FYI. This is how I did it. This is not a complete code but this will give you and idea.

Listener - PCL
============
private async Task EventClicked()
{
  var skuList = new List<string>();
  skuList.Add("[nameofsubscriptionfoundinyourgoogleplay]");

  if (await _billingClientLifecycle.Initialize(skuList, DisconnectedConnection))
        {
            var firstProduct = _billingClientLifecycle?.ProductsInStore?.FirstOrDefault();

            if (firstProduct != null)
            {
                //purchase here
            }
        }
}

private void DisconnectedConnection()
    { 
        //Todo.alfon. handle disconnection here...
    }


Interface - PCL
===========
public interface IInAppBillingMigratedNew
{
    List<InAppBillingPurchase> PurchasedProducts { get; set; }
    List<InAppBillingProduct> ProductsInStore { get; set; }
    Task<bool> Initialize(List<String> skuList, Action onDisconnected = null);
}


Dependency - Platform Droid
===============
[assembly: XF.Dependency(typeof(InAppBillingMigratedNew))]
public class InAppBillingMigratedNew : Java.Lang.Object, IBillingClientStateListener
    , ISkuDetailsResponseListener, IInAppBillingMigratedNew
{
    private Activity Context => CrossCurrentActivity.Current.Activity 
        ?? throw new NullReferenceException("Current Context/Activity is null");
    private BillingClient _billingClient;
    private List<string> _skuList = new List<string>();
    private TaskCompletionSource<bool> _tcsInitialized;
    private Action _disconnectedAction;
    private Dictionary<string, SkuDetails> _skusWithSkuDetails = new Dictionary<string, SkuDetails>();

    public List<InAppBillingPurchase> PurchasedProducts { get; set; }
    public List<InAppBillingProduct> ProductsInStore { get; set; }
    public IntPtr Handle => throw new NotImplementedException();

    public Task<bool> Initialize(List<string> skuList, Action disconnectedAction = null)
    {
        _disconnectedAction = disconnectedAction;
        _tcsInitialized = new TaskCompletionSource<bool>();
        var taskInit = _tcsInitialized.Task;
        _skuList = skuList;
        _billingClient = BillingClient.NewBuilder(Context)
           .SetListener(this)
           .EnablePendingPurchases()
           .Build();

        if (!_billingClient.IsReady)
        {
            _billingClient.StartConnection(this);
        }

        return taskInit;
    }

    #region IBillingClientStateListener

    public void OnBillingServiceDisconnected()
    {
        Console.WriteLine($"Connection disconnected.");
        _tcsInitialized?.TrySetResult(false);
        _disconnectedAction?.Invoke();
    }

    public void OnBillingSetupFinished(BillingResult billingResult)
    {  
        var responseCode = billingResult.ResponseCode;
        var debugMessage = billingResult.DebugMessage;

        if (responseCode == BillingResponseCode.Ok)
        {
            QuerySkuDetails();
            QueryPurchases();
            _tcsInitialized?.TrySetResult(true);
        }
        else
        {
            Console.WriteLine($"Failed connection {debugMessage}");
            _tcsInitialized?.TrySetResult(false);
        }
    }

    #endregion

    #region ISkuDetailsResponseListener

    public void OnSkuDetailsResponse(BillingResult billingResult, IList<SkuDetails> skuDetailsList)
    {
        if (billingResult == null)
        {
            Console.WriteLine("onSkuDetailsResponse: null BillingResult");
            return;
        }

        var responseCode = billingResult.ResponseCode;
        var debugMessage = billingResult.DebugMessage;

        switch (responseCode)
        {
            case BillingResponseCode.Ok:
                if (skuDetailsList == null)
                {
                    _skusWithSkuDetails.Clear();
                }
                else
                {
                    if (skuDetailsList.Count > 0)
                    {
                        ProductsInStore = new List<InAppBillingProduct>();
                    }

                    foreach (var skuDetails in skuDetailsList)
                    {
                        _skusWithSkuDetails.Add(skuDetails.Sku, skuDetails);

                        //ToDo.alfon. make use mapper here
                        ProductsInStore.Add(new InAppBillingProduct
                        {
                            Name = skuDetails.Title,
                            Description = skuDetails.Description,
                            ProductId = skuDetails.Sku,
                            CurrencyCode = skuDetails.PriceCurrencyCode,
                            LocalizedIntroductoryPrice = skuDetails.IntroductoryPrice,
                            LocalizedPrice = skuDetails.Price,
                            MicrosIntroductoryPrice = skuDetails.IntroductoryPriceAmountMicros,
                            MicrosPrice = skuDetails.PriceAmountMicros                                
                        });
                    }
                }
                break;
            case BillingResponseCode.ServiceDisconnected:
            case BillingResponseCode.ServiceUnavailable:
            case BillingResponseCode.BillingUnavailable:
            case BillingResponseCode.ItemUnavailable:
            case BillingResponseCode.DeveloperError:
            case BillingResponseCode.Error:
                Console.WriteLine("onSkuDetailsResponse: " + responseCode + " " + debugMessage);
                break;
            case BillingResponseCode.UserCancelled:
                Console.WriteLine("onSkuDetailsResponse: " + responseCode + " " + debugMessage);
                break;
            // These response codes are not expected.
            case BillingResponseCode.FeatureNotSupported:
            case BillingResponseCode.ItemAlreadyOwned:
            case BillingResponseCode.ItemNotOwned:
            default:
                Console.WriteLine("onSkuDetailsResponse: " + responseCode + " " + debugMessage);
                break;
        }
    }

    #endregion

    #region Helper Methods Private

    private void ProcessPurchases(List<Purchase> purchasesList)
    {
        if (purchasesList == null)
        {
            Console.WriteLine("No purchases done.");
            return;
        }

        if (IsUnchangedPurchaseList(purchasesList))
        {
            Console.WriteLine("Purchases has not changed.");
            return;
        }

        _purchases.AddRange(purchasesList);
        PurchasedProducts = _purchases.Select(sku => new InAppBillingPurchase
        {
            PurchaseToken = sku.PurchaseToken
        })?.ToList();

        if (purchasesList != null)
        {
            LogAcknowledgementStatus(purchasesList);
        }
    }

    private bool IsUnchangedPurchaseList(List<Purchase> purchasesList)
    {
        // TODO: Optimize to avoid updates with identical data.
        return false;
    }

    private void LogAcknowledgementStatus(List<Purchase> purchasesList)
    {
        int ack_yes = 0;
        int ack_no = 0;

        foreach (var purchase in purchasesList)
        {
            if (purchase.IsAcknowledged)
            {
                ack_yes++;
            }
            else
            {
                ack_no++;
            }
        }
        //Log.d(TAG, "logAcknowledgementStatus: acknowledged=" + ack_yes +
        //        " unacknowledged=" + ack_no);
    }

    private void QuerySkuDetails()
    {
        var parameters = SkuDetailsParams
            .NewBuilder()
            .SetType(BillingClient.SkuType.Subs)
            .SetSkusList(_skuList)
            .Build();
        _billingClient.QuerySkuDetailsAsync(parameters, this);
    }

    private void QueryPurchases()
    {
        if (!_billingClient.IsReady)
        {
            Console.WriteLine("queryPurchases: BillingClient is not ready");
        }

        var result = _billingClient.QueryPurchases(BillingClient.SkuType.Subs);
        ProcessPurchases(result?.PurchasesList?.ToList());
    }

    #endregion
}
© www.soinside.com 2019 - 2024. All rights reserved.