InApp-Billing

2

Posts

  • @RaphaelSchindler you are right the error is showing in a wrong place, this is not the error

    MessagingCenter.Send(this, AppConstants.MessagingKeys.ShowAlert, new Alert("Get full version", string.Format("{1}" + System.Environment.NewLine + "Cost - {2}", product.Description, product.FormattedPrice), true, "Cancel", "Buy"));

    Above statement causing error, after you said I commented everything and kept this line and found it. Thank you very much.

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @ManikantaPratapVarma No problem, you're welcome :)

  • Hi @RaphaelSchindler, I am having some problem with how do we determine whether user purchased the product or not, but not able to achieve it
    In IOS I used this method which returns false always I am not sure is it because I am testing or not

     public async Task<bool> IsPurchased(string productId)
            {
                bool RetVal = false;
                await Task.Run(() =>
                {
                    RetVal = AppDelegate.PurchaseManager.ProductPurchased(productId);
                });
                return RetVal;
            }
    

    In android I use below code

        public async Task<bool> IsPurchased(string productId)
            {
                List<Xamarin.InAppBilling.Purchase> purchases = null;
                if (!isConnected)
                    await Task.Run(async () =>
                    {
                        int retryCount = 0;
                        Connect();
                        do
                        {
                            await Task.Delay(250);
                            retryCount++;
                            if (retryCount == 500)
                                break;
                        } while (!isConnected);
                    });
                await Task.Run(() => { purchases = _serviceConnection.BillingHandler.GetPurchases(ItemType.Product).ToList(); });
                return purchases.Any(m=>m.ProductId.Equals(productId));
            }
    

    Not tested in android yet, but my question is the purchase manager will use the logged in Icloud account to find he user purchased or not ?

    Could you please help me with this.

  • @RaphaelSchindler or @nadjib could you please help me how to find whether the product is purchased or not ?

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @ManikantaPratapVarma Your code looks right for iOS. I bet it is because of testing. Take a look in the doc's, there's written how you can make test purchases.

    Here's mine which is almost the same:

    public bool GetPurchases()
    {
        if (AppDelegate.PurchaseManager.ProductPurchased("product.premium"))
        {
            //Do stuff
            return true;
        }
        else
        {
            return false;
        }
    }
    

    This is my android version:

    public bool GetPurchases()
    {
        if (ServiceConnection.BillingHandler == null)
        {
            ConnectBillingHandler();
        }
        else
        {
            var purchases = ServiceConnection.BillingHandler.GetPurchases("product.premium");
            if (purchases != null && purchases.Count != 0)
            {
                Settings.ProVersion = true;
            }
            return true;
        }
        return false;
    }
    
  • @RaphaelSchindler thank you very much

  • Hi @RaphaelSchindler Sorry to bother you again, I am not ablt to check the purchases yet. I thought it's because of the sandbox and submitted for app review to apple but they rejected saying ads are not removed after purchase. Not sure how to make this work.

    where as in android I purchased with my main account, My credit card charged but ServiceConnection.BillingHandler.GetPurchases always returns 0 purchases

    could you please help me. This is the last piece blocking me.

  • JenalynParagadosJenalynParagados USMember
    edited July 2016

    Hi, @nadjib thank you for the posted codes. It really a great help.

  • alessandrosuppiejalessandrosuppiej ITMember ✭✭

    @nadjib said:

    Then all you need in Shared/PCL ViewModel is:

    var iapService = DependencyService.Get<IIAPService>();
    // To get products list (to show them in a List for eg.)
    var products = await iapService.GetProducts(new List<string> { "myapp.product1", "myapp.product2" });
    
    // To buy a product
    

    var purchaseResult = iapService.Purchase("myapp.product1");

    var isReceiptValid = await CheckPurchaseReceipt(purchaseResult); // Check receipt server-side...

    if (isReceiptValid)
    {
        // Do whatever (unlock feature, give game gold/coins...)
    }
    

    Sorry, a question : why don't you await Purchase?
    without awaiting it you have alwais a task awaiting for activation.
    What am i doing wrong?

    thanks in advance

  • nadjibnadjib DZMember ✭✭✭✭

    It's just a typo, of course we have to await the Purchase task.

  • JenalynParagadosJenalynParagados USMember
    edited July 2016

    Hi @nadjib, I have used your codes in implementing In App Purchase for IOS but then I got errors on these lines of codes:

    AppDelegate.PurchaseManager.InAppProductPurchased += HandleInAppProductPurchased;
    AppDelegate.PurchaseManager.InAppProductPurchaseUserCanceled += HandleInAppProductPurchaseUserCanceled;
    AppDelegate.PurchaseManager.InAppProductPurchaseFailed += HandleInAppProductPurchaseFailed;
    

    There are the errors:

    No overload for 'HandleInAppProductPurchaseUserCanceled' matches delegate 'InAppPurchaseManager.InAppProductPurchaseUserCanceledDelegate'
    No overload for 'HandleInAppProductPurchaseFailed' matches delegate 'InAppPurchaseManager.InAppProductPurchaseFailedDelegate'
    No overload for 'HandleInAppProductPurchase' matches delegate 'InAppPurchaseManager.InAppProductPurchaseDelegate'
    

    By the way, I was not able to install Xamarin.InAppPurchase library in the NuGet Package Manager in my VS because I couldn't find the library when I search it. I just copied the Xamarin.InAppPurchase.dll in my project.

    Could you please help me with this.

    Thank you

  • nadjibnadjib DZMember ✭✭✭✭

    @JenalynParagados it's not a nuget package, it's a Xamarin component:

    https://components.xamarin.com/view/xamarin.inapppurchase iOS
    https://components.xamarin.com/view/xamarin.inappbilling Android

    Use Visual/Xamarin Studio to install the components

    As for your error, the method signatures/event args have been probably updated/changed from the time I posted my solution, just adapt them to new ones.

  • Hi @nadjib, Thank you so much for responding my question and it really helps. I have successfully added the component and after it, the errors were gone.:D

  • JenalynParagadosJenalynParagados USMember
    edited July 2016

    Hi @nadjib I have used this codes to get all the Purchased History:

    await Task.Run(() => { purchases = _serviceConnection.BillingHandler.GetPurchases(ItemType.Subscription).ToList(); });

    But then the purchases always null or the count is 0.
    When I tried to to buy the product, one of the subscription I have in the In App Products at Developer Console.,
    It will return an error message saying " You're already subscribed to Searching Payment. Manage subscription."

    Why does it always returns 0 where in fact all of those products were already subscribed by my account. I cannot proceed to Consuming the product since no data returns in getting the Purchased history. What is the best thing that I can do to consume the product so that I can re purchase it?

  • JohnHardmanJohnHardman GBUniversity ✭✭✭✭✭

    Late joining this thread. I can see that there are components for handling iOS and Android in-app purchases/billing. What is used for UWP?

    Does anybody know of any component that "just works" across iOS, Android and UWP, rather than all of us having to implement multiple solutions via dependency services?

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @JohnHardman I found this article. Maybe this will help you.

    No, I don't know any component for this. But the Dependency Services are easy to set up.

  • Hi, @nadjib , I need your help. BuyProduct is not working for me. The contentpage has a buy button like this

    buyNow.Clicked += async (sender, eventArgs) => { try { // To buy a product iapServicePurchase = DependencyService.Get<IInAppPurchase>(); var purchaseResult = await iapServicePurchase.Purchase(item.Sku); if (purchaseResult?.Result == false) { await DisplayAlert("Item Not Purchased Successfully", purchaseResult?.ErrorMessage, "Ok"); } else { await DisplayAlert("Item Purchased Successfully", purchaseResult?.ErrorMessage, "Ok"); } } catch (Exception ex) { await DisplayAlert("Item Purchase Error", "Please try again, Error Details - " + ex.Message, "Ok"); } };

    Code of Purchase is as below

    `
    public async Task Purchase(string productId)
    {
    try
    {
    purchaseTask = new TaskCompletionSource();

                if (AppDelegate.PurchaseManager.CanMakePayments)
                {
                    AppDelegate.PurchaseManager.InAppProductPurchased += HandleInAppProductPurchased;
    
                    AppDelegate.PurchaseManager.InAppProductPurchaseUserCanceled +=
                        HandleInAppProductPurchaseUserCanceled;
    
                    AppDelegate.PurchaseManager.InAppProductPurchaseFailed += HandleInAppProductPurchaseFailed;
    
                    AppDelegate.PurchaseManager.BuyProduct(productId);
    
                }
                else
                {
                    purchaseTask.SetException(new Exception(
                      "In App Purchase is disabled. Go to Settings > General > Restrictions. Toggle In App Purchases."
                    ));
                }
            }
            catch (OperationCanceledException operationCanceledException)
            {
                purchaseTask.SetException(new Exception("Purchase aborted"));
            }
            catch (Exception exception)
            {
                purchaseTask.SetException(new Exception(exception.Message));
            }
    
            return await purchaseTask.Task;
        }
    
        void HandleInAppProductPurchaseFailed(SKPaymentTransaction transaction, InAppProduct product)
        {
            AppDelegate.PurchaseManager.InAppProductPurchaseFailed -= HandleInAppProductPurchaseFailed;
            purchaseTask?.SetException(new Exception(transaction.Error.Description));
        }
    
        void HandleInAppProductPurchaseUserCanceled(SKPaymentTransaction transaction, InAppProduct product)
        {
            AppDelegate.PurchaseManager.InAppProductPurchaseUserCanceled -= HandleInAppProductPurchaseUserCanceled;
            purchaseTask?.SetCanceled();
        }
    
        void HandleInAppProductPurchased(SKPaymentTransaction transaction, InAppProduct product)
        {
            try
            {
                AppDelegate.PurchaseManager.InAppProductPurchased -= HandleInAppProductPurchased;
    
                if (transaction != null)
                {
                    if (transaction.TransactionReceipt != null && transaction.TransactionReceipt.Any())
                    {
                        if (purchaseTask == null)
                            purchaseTask.SetException(new Exception("purchaseTask null!"));
                        else
                        {
                            var Receipt = Convert.ToBase64String(transaction.TransactionReceipt.ToArray());
                            var isReceiptValid = CheckPurchaseReceipt(Receipt);
                            if (isReceiptValid)
                            {
                                RestorePurchases();
                                purchaseTask.SetResult(new NativePurchaseResult
                                {
                                    Result = true
                                });
                            }
                            else
                            {
                                purchaseTask.SetException(new Exception("Unable to Verify transaction receipt"));
                            }
                        }
                    }
                    else
                    {
                        purchaseTask.SetException(new ArgumentNullException("transaction"));
                    }
                }
                else
                {
                    purchaseTask.SetException(new ArgumentNullException("transaction"));
                }
            }
            catch (Exception exception)
            {
                purchaseTask.SetException(new Exception(exception.Message));
            }
        }
        private bool CheckPurchaseReceipt(string Receipt)
        {
            string verifyUrl = "https://sandbox.itunes.apple.com/verifyReceipt";
            // string verifyUrl = "https://buy.itunes.apple.com/verifyReceipt";
    
            var receiptData = new ReceiptData
            {
                receiptdata = Receipt
            };
    
            var data = JsonConvert.SerializeObject(receiptData);
            var result = ApplePostAPI(verifyUrl, data);
            result.Wait();
            var resultString = result.Result;
            var returnResult = JsonConvert.DeserializeObject<VerifyResponse>(resultString);
    
    
            if (returnResult?.status == 0)
            {
                return true;
            }
            return false;
        }
    
    
        async Task<string> ApplePostAPI(string url, string json)
        {
            HttpResponseMessage response = null;
            HttpClient client = new HttpClient();
            client.MaxResponseContentBufferSize = 256000;
            client.Timeout = TimeSpan.FromSeconds(10);
    
            var uri = new Uri(url);
            var content = new StringContent(json, Encoding.UTF8, "application/json");
            response = await client.PostAsync(uri, content);
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadAsStringAsync();
    
        }
    
        public class ReceiptData
        {
            public string receiptdata { get; set; }
        }
    
    
        public class VerifyResponse
        {
            public int status { get; set; }
            public object receipt { get; set; }
        }
    

    `

    Now the problem is, when I click the Buy Now button, the call goes to the Purchase method, but the page hangs(becomes irresponsive). Please provide me with some working smaple for reference. Im stuck for more than 2days now.

  • Also another question, is verifying the receipt mandatory? What if I skip it?

  • JohnHardmanJohnHardman GBUniversity ✭✭✭✭✭

    For InAppBilling on Android, what are people using for the developer payload string that can be passed to BillingHandler.BuyProduct ? A GUID might be fine for consumable items, but what about non-consumable items? The Android documentaiton says "You should pass in a string token that helps your application to identify the user who made the purchase" ... "Do not use the user's email address"

  • JohnHardmanJohnHardman GBUniversity ✭✭✭✭✭
    edited December 2016

    @nadjib @RaphaelSchindler @AnthonyRamirez

    Cross-posting from Forum › Tools and Libraries › Libraries, Components, and Plugins

    I've implemented in-app billing on Android using the Xamarin.InAppBilling component. There's no mention in the documentation for the component about ConsumePurchase having to be called on a thread other than the UI-thread. However, the Google documentation for the In-App Billing version 3 API says "Don't call the consumePurchase method on the main thread". So, I am wondering whether the Xamarin.InAppBilling component makes the underlying call on a new thread, or whether my code calling BillingHandler.ConsumePurchase should do so from a different thread. Does anybody know? Is the source code available anywhere?

    I then wonder if GetPurchases should be called on a different thread too, or whether the Xamarin.InAppBilling component makes the underlying call from a different thread already? Does anybody know?

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @JohnHardman As far as I'm aware everything that goes over the Component is handled in a new thread.

  • JohnHardmanJohnHardman GBUniversity ✭✭✭✭✭

    @RaphaelSchindler - BuyProduct has to be on the main thread (presumably as it pop's up stuff on the UI), but I'm hoping the component puts other, potentially slow, calls onto a separate thread. Do you know if the source code is available anywhere?

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @JohnHardman Do you mean the PlayStore stuff? I haven't seen the source code in the wild though.

  • JohnHardmanJohnHardman GBUniversity ✭✭✭✭✭

    @RaphaelSchindler - Yes, the source for the Xamarin.InAppBilling component.

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @JohnHardman I meant this

    BuyProduct has to be on the main thread (presumably as it pop's up stuff on the UI),

  • JohnHardmanJohnHardman GBUniversity ✭✭✭✭✭

    @RaphaelSchindler

    BuyProduct has to be called from the main thread - that's in the Xamarin.InAppBilling Getting Started documentation.

    Unfortunately, the Getting Started documentation doesn't provide any info about whether any other calls have to be from the main thread, or have to be from a different thread. The Google Play In-App Billing documentation says that the consumePurchase call in the underlying API should not be called from the main thread, but the Xamarin.InAppBilling documentation does not say whether that is taken care of for us, or whether we should call ConsumePurchase explicitly from a different thread.

  • JohnHardmanJohnHardman GBUniversity ✭✭✭✭✭

    Also, is the product ReservedTestProductIDs.Purchased ("android.test.purchased") supposed to also work for testing a subscription purchase on Android? If not, is there an alternative that can be used?

  • TravisKlinkerTravisKlinker USMember

    @JenalynParagados @nadjib I am stuck with the same error you raised earlier (errors listed below) for iOS. After researching all avenues on Google for a week, I am no further along and could use some help. On a side note, I haven't even started to work through this for Android. I just want to get iOS working first.

    Project specifics:
    Xamarin.Forms PCL project
    All views and models managed in PCL
    Xamarin.InAppPurchase Component v2.8 installed on iOS project
    Service setup as defined in this thread between PCL and iOS project

    iOS Service:
    `public class IAPService : IIAPService
    {
    private TaskCompletionSource purchaseTask;

        public async Task<NativePurchaseResult> Purchase(string productId)
        {
            try
            {
                purchaseTask = new TaskCompletionSource<NativePurchaseResult>();
    
    
                if (AppDelegate.PurchaseManager.CanMakePayments)
                {
                    AppDelegate.PurchaseManager.InAppProductPurchased += HandleInAppProductPurchased;
    
                    AppDelegate.PurchaseManager.InAppProductPurchaseUserCanceled += HandleInAppProductPurchaseUserCanceled;
    
                    AppDelegate.PurchaseManager.InAppProductPurchaseFailed += HandleInAppProductPurchaseFailed;
    
                    AppDelegate.PurchaseManager.BuyProduct(productId);
    
                }
                else
                {
                    purchaseTask.SetException(new Exception(
                      "In App Purchase is disabled. Go to Settings > General > Restrictions. Toggle In App Purchases."
                    ));
                }
            }
    
            catch (OperationCanceledException operationCanceledException)
            {
    
                purchaseTask.SetException(new Exception("Purchase aborted"));
            }
    
            catch (Exception exception)
            {
                purchaseTask.SetException(new Exception(exception.Message));
            }
    
            return await purchaseTask.Task;
        }
    
        void HandleInAppProductPurchaseFailed(SKPaymentTransaction transaction, InAppProduct product)
        {
            AppDelegate.PurchaseManager.InAppProductPurchaseFailed -= HandleInAppProductPurchaseFailed;
            purchaseTask?.SetException(new Exception(transaction.Error.Description));
        }
    
        void HandleInAppProductPurchaseUserCanceled(SKPaymentTransaction transaction, InAppProduct product)
        {
            AppDelegate.PurchaseManager.InAppProductPurchaseUserCanceled -= HandleInAppProductPurchaseUserCanceled;
            purchaseTask?.SetCanceled();
        }`
    

    I am getting these errors:
    No overload for 'HandleInAppProductPurchaseUserCanceled' matches delegate 'InAppPurchaseManager.InAppProductPurchaseUserCanceledDelegate' No overload for 'HandleInAppProductPurchaseFailed' matches delegate 'InAppPurchaseManager.InAppProductPurchaseFailedDelegate' No overload for 'HandleInAppProductPurchase' matches delegate 'InAppPurchaseManager.InAppProductPurchaseDelegate'

    Errors occur in these parts of the code:
    `AppDelegate.PurchaseManager.InAppProductPurchased += HandleInAppProductPurchased;
    AppDelegate.PurchaseManager.InAppProductPurchaseUserCanceled += HandleInAppProductPurchaseUserCanceled;
    AppDelegate.PurchaseManager.InAppProductPurchaseFailed += HandleInAppProductPurchaseFailed;

    AppDelegate.PurchaseManager.InAppProductPurchased -= HandleInAppProductPurchased;
    AppDelegate.PurchaseManager.InAppProductPurchaseUserCanceled -= HandleInAppProductPurchaseUserCanceled;
    AppDelegate.PurchaseManager.InAppProductPurchaseFailed -= HandleInAppProductPurchaseFailed;`

    @JenalynParagados you stated that once you installed InAppProduct component it cleared the errors. I have the component installed but I still have the above errors.

    Any help would be greatly appreciated.

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @AlessandroCaliaro Nice. Didn't knew we have a Plugin now

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭
    @JamesMontemagno has wake up yesterday, drink a coffe, eat an apple and write a plugin ;)
  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @AlessandroCaliaro I always imagined that @JamesMontemagno is more of a tea drinker^^
    Anyway, there's already a PR for UWP implementation. Just putting that info here if anyone wants to ask about it.

  • TravisKlinkerTravisKlinker USMember

    @AlessandroCaliaro Thank you! I actually was looking at it last night, but I must have been too tired to realize it was a plug in. I will check into it more.

  • TravisKlinkerTravisKlinker USMember

    @JamesMontemagno thank you! Just tested on iOS and works like a charm. You saved me hours of hunting through debugging issues.

  • TravisKlinkerTravisKlinker USMember

    @JamesMontemagno BTW, if you need testers for consumable products, please let me know. The app I am developing has both consumable and non-consumable products, so happy to test.

  • SreeSundaramSreeSundaram USMember ✭✭

    @JamesMontemagno Do you have a sample code snippet for UWP?

  • ManojkumarMaliManojkumarMali USMember ✭✭✭

    @nadjib said:
    Don't forget to add http://components.xamarin.com/view/xamarin.inappbilling to your Android project and add this on MainActivity.cs

    protected override void OnActivityResult(int requestCode, Result resultCode, global::Android.Content.Intent data)
    {

    if (IAPService._serviceConnection != null)
    IAPService._serviceConnection.BillingHandler.HandleActivityResult(requestCode, resultCode, data);
    }

    Then all you need in Shared/PCL ViewModel is:

    var iapService = DependencyService.Get<IIAPService>();
    // To get products list (to show them in a List for eg.)
    var products = await iapService.GetProducts(new List<string> { "myapp.product1", "myapp.product2" });
    
    // To buy a product
    

    var purchaseResult = iapService.Purchase("myapp.product1");

    var isReceiptValid = await CheckPurchaseReceipt(purchaseResult); // Check receipt server-side...

    if (isReceiptValid)
    {
        // Do whatever (unlock feature, give game gold/coins...)
    }
    

    Hi @nadjib ,

    I have written the same code, but i am getting iapService as null in PCL.

    var iapService = DependencyService.Get();

  • nadjibnadjib DZMember ✭✭✭✭
    There's an excellent plugin now by @JamesMontemagno. Use it instead.

    https://github.com/jamesmontemagno/InAppBillingPlugin
  • ManojkumarMaliManojkumarMali USMember ✭✭✭

    Hi @nadjib ,

    I have written the same code, but i am getting iapService as null in PCL.

    var iapService = DependencyService.Get();

    Ohhhh, its my mistake.. ;)

2
Sign In or Register to comment.