locked
IAP crashes phone when MockIAPLib works fine RRS feed

  • Question

  • Alright, I've recently submitted my app for certification only to have it fail due to a crash. Everything worked fine in the mockIAPLib and was able to process it. However, in the release it would not retrieve the formatted price, only an empty string. And when the user pressed purchase and cancel, the app would crash. However, it would not crash when the user went through with the purchase.

    Here is the Stack Trace of the crash report generated when certification failed.

    Frame    Image             Function          Offset       
    0        KERNELBASE.dll    RaiseException    0x00000036   
    1        coreclr.dll                         0x00039b78

    So why is this happening (What other information would you like to see?) and why isn't it happening in the MockIAPLib but only the release version?

    Friday, March 1, 2013 11:44 PM

Answers

  • Hey Jonathan,

    I am the author of the MockIAP Library as well as on the product team for In App Purchase. 

    First off, you should wrap your RequestProductPurchaseAsync call in a try/catch since if the user clicks on 'Cancel', our API will let you know by throwing an exception. So a try/catch is needed. You can opt to do something in the catch like saying "why you no buy????" but I am assuming you probably don't care about the case of no purchase. 

    The MockIAP library actually does the same if you click on Cancel. I will double check, maybe I messed up. Yep...just looked at the code. Sigh... my bad. I am preparing a new version anyway and will make sure to make it throw an exception here as well. Sorry about that :( 


    Nazeeh ElDirghami - XNA Team

    • Proposed as answer by Nazeeh Friday, March 15, 2013 7:02 PM
    • Marked as answer by Jonathan Pearl Wednesday, April 10, 2013 2:59 AM
    Friday, March 15, 2013 7:02 PM

All replies

  • Can you share the code which is using IAP and handling the response?

    -Eric.

    Monday, March 4, 2013 6:46 PM
  • private async void PurchaseRemoval_Click(object sender, RoutedEventArgs e)
    {
        Button img = sender as Button;
    
        string key = img.Tag.ToString();
    
        if (!Store.CurrentApp.LicenseInformation.ProductLicenses[key].IsActive)
        {
            ListingInformation li = await Store.CurrentApp.LoadListingInformationAsync();
            string pID = li.ProductListings[key].ProductId;
    
            string receipt = await Store.CurrentApp.RequestProductPurchaseAsync(pID, false);
    
                    
            initStoreItem();
            updateMessageDisplay();
            //RenderStoreItems();
        }
    }

    That is the code for purchasing

    And this is the code used to set up the state (Is called on page load and after every purchase attempt)

    private async void initStoreItem()
    {
        //StoreManager mySM = new StoreManager();
        ListingInformation li = await Store.CurrentApp.LoadListingInformationAsync();
        ProductListing prod;
    
        if (li.ProductListings != null)
        {
            if (li.ProductListings.TryGetValue("adRemove", out prod))
            {
                error = false;
                price = prod.FormattedPrice;
    
                if (Store.CurrentApp.LicenseInformation.ProductLicenses["adRemove"].IsActive == true)
                {
                    GlobalState.noAds = true;
                }
                removeAdsButton.Tag = "adRemove";
            }
            else
            {
                //Item not found
                error = true;
            }
        }
        else
        {
            //Item not found
            error = true;
        }
    }

    And here is how the IAP product looks in my dashboard

    In-app product ID : adRemove

    In-app product alias : BloomRemoveAds

    Type : Durable

    State : Published

    Monday, March 4, 2013 11:07 PM
  • It probably wouldn't hurt to put some try/catch error handling around that code but I'm not sure that it would help either.

      The stack trace you posted earlier is not much help since it only shows the RaiseException function.  (...that location in coreclr.dll is a forwarder to RaiseException in the Kernel.) 
      Did the report include any other information like exception code?


    -Eric.

    Tuesday, March 5, 2013 5:15 PM
  • I just feel like it should at least work since it has worked in the MockIAP. Otherwise, it should have triggered the "not found" conditions and turned error to true. I don't know why it behaved so oddly. It knew what the product was, but didn't know the formatted price and then it crashes on cancel. I have absolutely no clue what went wrong and the report does not contain any other pertinent information. I don't have a windows phone myself, this is the first app I've attempted to make so I can't test it on my own device. I have a friend who has a Windows Phone 8 device but that would require me to get another beta app up which would take another day to sign etc.

    I just don't know where the rub is -- The situation should be alike in the MockIAP and the Store version.

    Tuesday, March 5, 2013 7:01 PM
  • The only difference I can think of at the moment is that the mockIAP library does not cause a process context switch, when showing the confirmation page, where-as the actual Store API may be causing a process context switch.


    -Eric.

    Tuesday, March 5, 2013 11:49 PM
  • Well, the app still works if they go through with the purchase, just not if they cancel the purchase.

    EDIT: I'm trying to get a beta app up today and I'll try to print out the exception with a message box and see how that goes.

    EDIT2: Okay, apparently it won't let him get to the purchase prompt again because he had bought it on the previous beta version. I tried recreating the in-app product but that didn't reset it, sadly.
    Wednesday, March 6, 2013 10:34 AM
  • Alright. I managed to flesh out the code to use a different ID and updated the store appropriately and I finally replicated the error. Here is the stack trace (I typed it by hand so there might be some typos as the picture was sent to me was blurry)

    System.Runtime.InteropServices.COMException (0x80004005): Error HRESULT E_FAIL has been returned from a call to a COM component.

    at

    System.Runtime.CompilerServices.Task.Awaiter.ThrowForNonSuccess(Task task)

    at

    System.Runtime.CompilerServices.Task.Awaiter.HandleNonSuccessAndDebuggerNotification(Task task)

    at

    System.Runtime.CompilerSrvices.TaskAwaiter`1.GetResult()

    at

    PhoneApp3.Page2.<PurchaseRemoval_Click>d_5.MoveNext()

    Does this answer anything?

    Friday, March 8, 2013 11:34 PM
  • Well, PurchaseRemoval_Click is mentioned in the stack and it also indicates the error is occurring in one of the await operations ... you may be able to handle the exception by wrapping the 'await xxx' calls with try/catch.

    If that doesn't work, try expand these calls to handle the async operations in the classic way (i.e. without using await.)


    -Eric.

    Tuesday, March 12, 2013 6:07 PM
  • But the formatted price still doesn't work. It still returns an empty string and I would like to distribute to the UK so I can't just put in a dollar amount. Also hardcoding the cost for all of the denominations doesn't sound appealing because I may change the price and I would hate to have to update the app package to update the price display.

    Also, how would I expand the async operations to not use await? Am I creating another thread to run with the program? I'm not too experienced in concurrency (read: not even experienced a little) with C#.

    And thank you for staying with me on this problem thus far.

    Wednesday, March 13, 2013 12:39 PM
  • Hey Jonathan,

    I am the author of the MockIAP Library as well as on the product team for In App Purchase. 

    First off, you should wrap your RequestProductPurchaseAsync call in a try/catch since if the user clicks on 'Cancel', our API will let you know by throwing an exception. So a try/catch is needed. You can opt to do something in the catch like saying "why you no buy????" but I am assuming you probably don't care about the case of no purchase. 

    The MockIAP library actually does the same if you click on Cancel. I will double check, maybe I messed up. Yep...just looked at the code. Sigh... my bad. I am preparing a new version anyway and will make sure to make it throw an exception here as well. Sorry about that :( 


    Nazeeh ElDirghami - XNA Team

    • Proposed as answer by Nazeeh Friday, March 15, 2013 7:02 PM
    • Marked as answer by Jonathan Pearl Wednesday, April 10, 2013 2:59 AM
    Friday, March 15, 2013 7:02 PM
  • Alright. Thank you, that has helped tremendously, but there is still the problem with the formatted price not working in the Release IAP. Do you have any ideas about that or should I just remove it entirely?

    Thank you,

    Jon.

    Saturday, March 16, 2013 3:49 AM
  • I am going to have to double check for your Jonathan, but I am pretty sure that is not supported for WP (vs Windows). I would not depend on it. I'll get back to you for sure though.


    Nazeeh ElDirghami - XNA Team

    Saturday, March 16, 2013 5:08 PM
  • Oh, the only reason I ask is because it's listed as a Windows Phone function on the MSDN:

    http://msdn.microsoft.com/en-us/library/windows/apps/windows.applicationmodel.store.productlisting.formattedprice

    I guess I can just leave it out completely and leave it up to the prompt, but it would be nice for the formatted price functionality to work. But I'll still wait for your input before I go about resubmitting.
    Sunday, March 17, 2013 7:46 AM
  • Sorry for bothering, but it's been a week since the last message. Any news on the formattedPrice?
    Monday, March 25, 2013 12:37 AM
  • Can you give some more detail regarding how FormattedPrice is failing? 

    i.e. What are the symptoms and conditions?


    -Eric.

    Monday, March 25, 2013 2:29 PM
  • But the formatted price still doesn't work. It still returns an empty string and I would like to distribute to the UK so I can't just put in a dollar amount. Also hardcoding the cost for all of the denominations doesn't sound appealing because I may change the price and I would hate to have to update the app package to update the price display.

    Also, how would I expand the async operations to not use await? Am I creating another thread to run with the program? I'm not too experienced in concurrency (read: not even experienced a little) with C#.

    And thank you for staying with me on this problem thus far.

    ok... I talked to some guys on my team and they said formatted price should work but if you are not seeing that, maybe there's a bug. I will follow up and see what's up internally. In the meantime, if you can do without it, don't let it block your submission.

    As for not using await/async, can you tell me more why you don't want to use them? Things that use await do spawn a thread yes but it's all done for you and shouldn't affect you negatively at all. 



    Nazeeh ElDirghami - XNA Team

    Monday, March 25, 2013 4:20 PM
  • For an elaboration, it simply does not return the price string. It will return "" while in the MockIAP it would return "$1.49" or whatever the price had been assigned.

    Also, it's not that I am actively choosing to use/not to use them, it's that I'm not entirely sure how to. When I look at the functions they seem to be asynchronous already, and I'm not sure what I would have to do differently. I'll submit it without for now, but I'll still be active in this thread in order to resolve this problem.

    Monday, March 25, 2013 4:37 PM
  • For an elaboration, it simply does not return the price string. It will return "" while in the MockIAP it would return "$1.49" or whatever the price had been assigned.

    Also, it's not that I am actively choosing to use/not to use them, it's that I'm not entirely sure how to. When I look at the functions they seem to be asynchronous already, and I'm not sure what I would have to do differently. I'll submit it without for now, but I'll still be active in this thread in order to resolve this problem.

    async/await basically takes an asynchronous method and makes calling it look like a synchronous method. The IAP methods are all async which without using async/await would mean your code flow would have to be broken up to making a call to the method and then having a callback come in another method in your code. It makes programming that stuff a bit of a pain since your code flow is broken up over a bunch of methods. With await, it does all that in the background for you without letting you have to organize your code differently. As far as you're concerned, it's just a method call like any other :) It's awesome!

    Nazeeh ElDirghami - XNA Team

    Monday, March 25, 2013 6:19 PM
  • Oh, I've used async and await before, and it's shown in the code I posted in my first reply. Am I doing something incorrectly? Or is there something I don't know about?
    Monday, March 25, 2013 8:07 PM
  • Oh, I've used async and await before, and it's shown in the code I posted in my first reply. Am I doing something incorrectly? Or is there something I don't know about?
    Nope. You got it exactly right. :) 

    Nazeeh ElDirghami - XNA Team

    Tuesday, March 26, 2013 8:18 PM
  • Hi Jonathan,
    this is a really interesting thread. I just want to do something very similar and have a question that nobody has answered so far. Reading your code I guess you should be able to answer my question: what is the difference between the "key" variable one uses to get the ProductListing from the ProductListings dictionary and the "productId" variable used in the RequestProductPurchaseAsync? And how do they map to the properties of the submitted IAP product?

    In your code you use "adRemove" to get the ProductListing - so it seams to me that you use the productId also as key in ProductListings. Is this correct? Is it the same?

    Thanks for any feedback

    Hans-Peter

    Tuesday, May 21, 2013 1:35 PM
  • when i  navigate to storefront in my app i receive this exception  

    Error HRESULT E_FAIL has been returned from a call to a COM component. COM component


    DesertQueen

    Tuesday, July 30, 2013 12:34 PM