InApp-Billing

RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

Hey folks,
as I'm taking huge steps to release our app, I'm now at the point where I have to implement a payment function. And I was curious if anyone here used the InApp-Billing Components from the components store and has a few tips for me.

Since those are platform packages I guess the best way to use them is via DependencyService.

As the instructions from the components are good, maybe someone found a few hints for Forms.

Greetings

«13

Posts

  • nadjibnadjib DZMember ✭✭✭✭
    edited July 2015

    iOS/WP implementation is same as Android (nearly) (for iOS you need this component http://components.xamarin.com/view/xamarin.inapppurchase)

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    Thank you. That was everything I wanted to know :)

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @nadjibus One last question. Where does NativePurchaseResult and InAppProduct come from?

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭
    edited July 2015

    Nevermind got it from the code :smile:
    CheckPurchaseReceipt is from yourself?

  • nadjibnadjib DZMember ✭✭✭✭

    Yes, you check the receipt server side, else you'll get bankrupt (especially in Android, lot of cheaters!)

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    Alright and thank you again @nadjibus for your great help.

    I'm wondering if this is enough for iOS. How did you implemented it?

    await GetProducts(new List<string> { "product.premium", "product.broker" });
            NativePurchaseResult nativePurchase = null;
    
            ServiceConnection.InAppProductPurchaseFailed += ServiceConnectionOnInAppProductPurchaseFailed;
            ServiceConnection.InAppProductPurchased += ServiceConnectionOnInAppProductPurchased;
            ServiceConnection.InAppProductPurchaseUserCanceled +=    ServiceConnectionOnInAppProductPurchaseUserCanceled;
            ServiceConnection.InAppPurchaseProcessingError += ServiceConnectionOnInAppPurchaseProcessingError;
    
            if (ServiceConnection.CheckInternetConnection && ServiceConnection.CanMakePayments)
            {
                ServiceConnection.BuyProduct(productId);
                if (ServiceConnection.ProductPurchased(productId))
                {
                    //Do stuff
                    return nativePurchase = new NativePurchaseResult {Receipt = "pro", Result = true};
                }
                else
                {
                    return nativePurchase = new NativePurchaseResult {Receipt = "pro", Result = false};
                }
            }
            else
            {
                return
                    nativePurchase =
                        new NativePurchaseResult {Result = false, Receipt = "Kann nicht kaufen oder kein Internet"};
            }
    
  • nadjibnadjib DZMember ✭✭✭✭

    And you must implement for the 3 server side receipt validation of course :)

  • nadjibnadjib DZMember ✭✭✭✭
    edited July 2015

    Also my code is for consumable products; It should be easy to adapt if for non consumable (easier I think). You just need to implement an additional method in the interface:

    Task<bool> HasBoughtProduct(string productId)
    

    and remove the consume call in each platform (or separate it to another call so you can control whether or not consume a purchase)

  • FetFrumos911FetFrumos911 USMember
    edited August 2015

    to nadjibus

    Thank you very much for your code. But I have one question. How to verify the purchase of the product? I use simple check in my Android app

      var purchases = ServiceConnection.BillingHandler.GetPurchases(ItemType.Product);
      var isBuy = purchases.Select(i=>i.ProductId.Equals("mycode")).FirstOrDefault;
      if(isBuy != null)
      {
           ...
      }
    

    I try to verify the purchase of the device with the real code. The purchase is successful - but GetPurchases(ItemType.Product) return 0 items. I try in debug mode with test code "android.test.purchased". I after callig GetPurchases and getting 0 items:(. Tell me please the best way to verify the purchase.

  • HomeroBatistaKzamHomeroBatistaKzam BRMember ✭✭

    Could someone provide a code example?

  • You can make the app code using In App Purchase with Xamarin.Forms?

    I want to develop an app that certain functionality is only available if you pay a quarterly plan (3months). How do these settings in the Apple?

    Thank you.

  • AnthonyRamirezAnthonyRamirez USUniversity ✭✭✭
    edited October 2015

    Hi @Nadjib.Bait

    Thanks so much for providing the code above. It really helped me understand the flow and how to structure my class.

    I have one question. I can't seem to understand what the server side check would look like. What on the receipt would the server check?

    Thanks again,
    Ant

  • Just wanted to say thanks to @NadjibBait

    Seriously made the process of setting up IAP much more sensible and streamlined.

  • WilliamHWilliamH USMember

    Lot of great examples! I am kind of new to this - but where & how does NativePurchaseResult and InAppProduct get defined? Where I defined the interface IIAPService both NativePurchase and InAppProduct cannot be resolved. Thanks!!

  • AnthonyRamirezAnthonyRamirez USUniversity ✭✭✭

    @WilliamH the NativePurchaseResult and InAppProduct are a application specific class that @Nad defined for consumption in common areas of his app.

    This way he can set all the properties on the NativePurchaseResult object in platform specific code and return it back to the common code, for instance, in a PCL.

    Hope that helps :)

  • BillingHandler_OnProductPurchased is not getting called for me for some reason. I added the OnActivityResult, but it still won't work. Anyone know why this may be happening?

  • AnthonyRamirezAnthonyRamirez USUniversity ✭✭✭

    @JoshuaNovak.6915 do you know if is OnActivityResult is being called?

  • @AnthonyRamirez Yeah it is. Found out the issue. I forgot I was using android.test.canceled instead of android.test.purchased, so it never went through all the way.

  • Cansado2930Cansado2930 ESMember ✭✭

    Hi!
    I'm a developer of native Windows apps and recently I have started to develop with Xamarin Forms my apps on Android and iOS. And I need your experience in order to solve a problem with IAP. On Windows, An IAP can be a durable or consumable product. And durable products can be for always or small time (subscription). My app has subscriptions and I have read that there are 3 types on Android, is it trust? The documentation of Android said that there is third for subscriptions but I can’t find it. So, how should I implement it?
    Thanks!

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @Cansado2930 Yes, Android has 3 Items. One is the normal Premium product (consume once) then the Consumable product (consume more then once) and then there are subscriptions. You have to define them in the Developer Console under play.google.com and there under In-App-Products. Then you can get them in the payment code.

  • Cansado2930Cansado2930 ESMember ✭✭

    Thanks @RaphaelSchindler for your comment. I'm going to see it. I have an additional question. How should I implement it? I have checked the API, and there are available: _serviceConnection.BillingHandler.BuyProduct() and _serviceConnection.BillingHandler.ConsumePurchase(). What should I use in order to subscription?
    Thanks!

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @Cansado2930 I'm sorry but I can't answer that. Maybe you could get the info you want https://components.xamarin.com/view/xamarin.inappbilling there. Or @Nad can answer it

  • Cansado2930Cansado2930 ESMember ✭✭

    I have checked it and thanks, I hadn’t seen that there is information on the download page. If I don’t understand bad, 3 items use the same. I have to use “buyProduct()” and then check if it is confirmed from server. Ok. And then, examples of @RaphaelSchindler and @Nad are very usefull. But, if I have understood correctly, in Android, you can renoval the subscription automatically, is it correct? Then, How can I know when the subscription is finished? On Windows, when you ask store about products that have purchased, the store tells the day when it will finish. Here, I have ask to server every time in order to know if it has license to use today. Is it correct?
    Thanks

  • BrunoBarretteBrunoBarrette USMember

    @nadjib Do you have an updated example for your iOS implementation of the IAPService class ? The one posted here seems to have a couple of issues (serverProducts variable is not declared anywhere, the initialization of the purchaseTask object is done with a string instead of NativePurchaseResult as opposed to its declaration), and I'd like to make sure I get everything right to test this.

    Thanks in advance!
    Bruno

  • nadjibnadjib DZMember ✭✭✭✭
    edited May 2016

    @BrunoBarrette replace serverProducts.Count with productsIds.Count (forgot to remove my own code)

    and yes this is the correct thing as u guessed:

    purchaseTask = new TaskCompletionSource<NativePurchaseResult>();
    
  • BrunoBarretteBrunoBarrette USMember

    Thanks @nadjib for the quick reply! And mostly thanks for putting up the code to get all this running in Forms !

  • CaptainXamtasticCaptainXamtastic GBUniversity ✭✭✭

    Nice work chaps, in many respects this is better than a blog!

  • ManikantaPratapVarmaManikantaPratapVarma USMember
    edited May 2016

    @RaphaelSchindler said:
    @nadjibus One last question. Where does NativePurchaseResult and InAppProduct come from?

    @RaphaelSchindler Could you please tell me where you found NativePurchaseResult and InAppProduct ?

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @ManikantaPratapVarma They are classes that you have to define in your PCL

    public class InAppProduct
    {
        public string Sku { get; set; }
    
        public string Name { get; set; }
    
        public string Description { get; set; }
    
        public string Price { get; set; }
    }
    
    public class NativePurchaseResult
    {
        public string Receipt { get; set; }
    
        public string PaymentId { get; set; }
    
        public bool Result { get; set; }
    }
    
  • @RaphaelSchindler said:
    @ManikantaPratapVarma They are classes that you have to define in your PCL

    public class InAppProduct
    {
        public string Sku { get; set; }
    
        public string Name { get; set; }
    
        public string Description { get; set; }
    
        public string Price { get; set; }
    }
    
    public class NativePurchaseResult
    {
        public string Receipt { get; set; }
    
        public string PaymentId { get; set; }
    
        public bool Result { get; set; }
    }
    

    Thank you @RaphaelSchindler

  • ManikantaPratapVarmaManikantaPratapVarma USMember
    edited May 2016

    Hi @RaphaelSchindler

    I am getting following error

    System.FormatException: Index (zero based) must be greater than or equal to zero and less than the size of the argument list.
    public async Task<IEnumerable> GetProducts(IEnumerable productIds)
    {
    var products = new List();
    var maxRetries = 10;
    int retriesCount = 0;
    await Task.Run(async () =>
    {
    try
    {
    AppDelegate.PurchaseManager.QueryInventory(productIds.ToArray());
    do
    {
    // Ugly hack, Xamarin component is weird, most of times it only retrieve about 50% of products after QueryInventory call, so we have to wait until all products are loaded...
    retriesCount++;
    await Task.Delay(1000);
    } while (AppDelegate.PurchaseManager.Count < productIds.Count() && retriesCount < maxRetries);

                        if (AppDelegate.PurchaseManager.Count > 0)
                        {
                            foreach (Xamarin.InAppPurchase.InAppProduct prod in AppDelegate.PurchaseManager)
                            {
                                products.Add(new InAppProduct
                                {
                                    Name = prod.Title,
                                    Description = prod.Description,
                                    FormattedPrice = prod.FormattedPrice,
                                    Price = prod.Price,
                                    Sku = prod.ProductIdentifier
                                });
                            } 
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                });
                return products;
            }
    

    Not sure what's causing the error, debugger is not stopping there, I see products in the list but nothing works. Could you please help me.

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @ManikantaPratapVarma Looks more like an UI error than in the Purchase class. You should debug on your UI and see if thats the problem

  • @RaphaelSchindler Thank you for quick response, everything else works I get this error only when I click on get products button. I have instantiated purchase as below in appdelegate, do you think the order matters

     public override bool FinishedLaunching(UIApplication app, NSDictionary options)
            {
                Xamarin.Forms.Forms.Init();
                // registers for push
                var settings = UIUserNotificationSettings.GetSettingsForTypes(
                    UIUserNotificationType.Alert
                    | UIUserNotificationType.Badge
                    | UIUserNotificationType.Sound,
                    new NSSet());
    
                UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
                UIApplication.SharedApplication.RegisterForRemoteNotifications();
                ICrossDevice device = DependencyService.Get<ICrossDevice>();
                LoadApplication(new App());
                UIApplication.SharedApplication.SetStatusBarStyle(UIStatusBarStyle.LightContent, false);
                TestFairy.Begin("5fd8a2b6d5sdsd46eb5ecsdsd2cfd3sde8bce1b902919ca980");
                PurchaseManager = new InAppPurchaseManager();
                return base.FinishedLaunching(app, options);
            }
    
  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @ManikantaPratapVarma Hmm no. I don't think the order matters you're initializing it after Init() and LoadApplication() so this should be fine. If the debugger doesn't hold in the GetProducts() you should use a try-catch in you Click() function from the button maybe this can help you.

«13
Sign In or Register to comment.