Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/xamarin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Xamarin.Android中异步实现Android应用内计费客户端_Xamarin_Xamarin.android_In App Billing - Fatal编程技术网

如何在Xamarin.Android中异步实现Android应用内计费客户端

如何在Xamarin.Android中异步实现Android应用内计费客户端,xamarin,xamarin.android,in-app-billing,Xamarin,Xamarin.android,In App Billing,我正试图用c#实现下面提到Android的java代码 List skuList=newarraylist(); skuList.添加(“特优升级”); skuList。添加(“气体”); SkuDetailsParams.Builder params=SkuDetailsParams.newBuilder(); 参数setskulist(skuList).setType(SkuType.INAPP); billingClient.querySkuDetailsAsync(params.buil

我正试图用c#实现下面提到Android的java代码

List skuList=newarraylist();
skuList.添加(“特优升级”);
skuList。添加(“气体”);
SkuDetailsParams.Builder params=SkuDetailsParams.newBuilder();
参数setskulist(skuList).setType(SkuType.INAPP);
billingClient.querySkuDetailsAsync(params.build(),
新SkuDetailsResponseListener(){
@凌驾
公共无效详细信息响应(BillingResult BillingResult,
列表(详细信息列表){
//处理结果。
}
});
我有两个问题。我想我会在一个单独的线程上运行这段代码,而不是像下面这样的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;
        }
公共异步任务GetProductsAsync(列出ProductID)
{
var getsku detailstask=Task.Factory.StartNew(()=>
{
var prms=skudailsparams.NewBuilder();
var type=BillingClient.SkuType.Inapp;
prms.setskulist(productid).SetType(type);
BillingClient.QuerySkuDetailsAsync(prms.Build(),new SkuDetailsResponseListener());
退货不适用产品;
});
返回等待getskutailstask;
}
关于如何处理听众的第二个问题,如下所示。如何从侦听器返回值。我需要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
            }
        }
    }
公共类SkuDetailsResponseListener:Java.Lang.Object,ISkuDetailsResponseListener
{
公共无效详细信息响应(BillingResult BillingResult、IList SKU)
{
if(billingResult.ResponseCode==BillingResponseCode.Ok)
{
//在此处获取产品列表并返回
}
}
}
供参考。我就是这样做的。这不是一个完整的代码,但这将给你和想法。
监听器-PCL
============
私有异步任务EventClicked()
{
var skuList=新列表();
添加(“[nameofsubscriptionfoundinyourgoogleplay]”;
if(等待\u billingClientLifecycle.Initialize(skuList,断开连接))
{
var firstProduct=_billingClientLifecycle?.ProductsInStore?.FirstOrDefault();
if(firstProduct!=null)
{
//在这里购买
}
}
}
私有void DisconnectedConnection()
{ 
//托多·艾尔丰,这里处理断开连接。。。
}
接口-PCL
===========
公共接口IInAppBillingMigratedNew
{
列出PurchasedProducts{get;set;}
列表产品存储{get;set;}
任务初始化(列表skuList,操作onDisconnected=null);
}
依赖平台机器人
===============
[程序集:XF.Dependency(typeof(inapplingmigratednew))]
AppBillingMigratedNew中的公共类:Java.Lang.Object,IBillingClientStateListener
,ISkuDetailsResponseListener,IInapplingMigratedNew
{
私有活动上下文=>CrossCurrentActivity.Current.Activity
?抛出新的NullReferenceException(“当前上下文/活动为null”);
私人账单客户(BillingClient);;
私有列表_skuList=新列表();
私有任务完成源\u已初始化;
私人行动-断开连接;
专用词典_skuswithskuadetails=新词典();
公共列表PurchasedProducts{get;set;}
公共列表产品存储{get;set;}
public IntPtr Handle=>抛出新的NotImplementedException();
公共任务初始化(列表skuList,操作disconnectedAction=null)
{
_disconnectedAction=disconnectedAction;
_tcsInitialized=new TaskCompletionSource();
var taskInit=_.Task;
_skuList=skuList;
_billingClient=billingClient.NewBuilder(上下文)
.SetListener(此)
.EnablePendingPurchases()
.Build();
如果(!\u billingClient.IsReady)
{
_billingClient.StartConnection(此);
}
返回taskInit;
}
#区域IBillingClientStateListener
公共无效OnBillingServiceDisconnected()
{
Console.WriteLine($“连接已断开”);
_tcsInitialized?.TrySetResult(false);
_disconnectedAction?.Invoke();
}
BillingSetupFinished(BillingResult BillingResult)上的公共无效
{  
var responseCode=billingResult.responseCode;
var debugMessage=billingResult.debugMessage;
if(responseCode==BillingResponseCode.Ok)
{
QuerySkuDetails();
QueryPurchases();
_tcsInitialized?.TrySetResult(真);
}
其他的
{
WriteLine($“连接失败{debugMessage}”);
_tcsInitialized?.TrySetResult(false);
}
}
#端区
#区域ISkuDetailsResponseListener
公共无效OnSkuDetailsResponse(BillingResult BillingResult,IList skuDetailsList)
{
如果(billingResult==null)
{
Console.WriteLine(“onSkuDetailsResponse:null BillingResult”);
返回;
}
var responseCode=billingResult.responseCode;
var debugMessage=billingResult.debugMessage;
开关(响应代码)
{
案例BillingResponseCode。确定:
如果(skuDetailsList==null)
{
_skuswithskuadetails.Clear();
}
其他的
{
如果(skuDetailsList.Count>0)
{
ProductsInStore=新列表();
}
foreach(skuDetailsList中的变量skuDetails)
{
_skusWithSkuDetails。添加
 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
            }
        }
    }
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
}