Post not yet marked as solved
Hi @rami256 & Tawazon Team,
I think SKError.Code.unknown is more a catch-all code for a huge variety of possible uncategorised reasons as to why StoreKit returned an error - I doubt Apple are willing to specify a list of all possible reasons as to why there might have been a failure when this code is issued, for one because it might be a little embarrassing for them, ha.
In my experience so far, not that my app is yet live, it is mainly to do with a user's App Store account - i.e. invalid state, account access issue, payment problem, etc.
When this error is thrown, try printing out the details of the NSError to see if you can glean more detail as to what it might be - e.g. NSError.localizedDescription/underlyingErrors/userInfo/localizedFailureReason/localizedRecoveryOptions/localizedRecoverySuggestion, etc.
I used to get this error code a lot when first developing the auto-renewable subscription functionality in my app, but I don't get it anymore since properly hooking up my Sandbox user testing account.
Hope that helps you guys out anyway.
Cheers,
Ben
Post not yet marked as solved
Hi again @Niano,
I get your thinking here. You just don't want any lag in showing IAP prices to the user in that screen, just in case there is no internet connection or there's a slight lag in getting the SKProductsResponse due to a slow internet connection. You therefore have all your IAP prices cached/stored already and can therefore display them immediately. I mean, this 'should' be fine. Especially if you don't plan to change your products and prices. But as you said, I would definitely query regardless when that screen is opened and just overwrite the stored values in the UI (nothing should happen if they are the same).
Also worth noting that if you're only making an SKProductsRequest at app launch, the last update may be much older than you expect. For instance, a user may not actually terminate your app for months... in which case, the SKProductsRequest also wouldn't be called again for months. Which is why it's always worth calling it every time your IAP products are displayed.
My app's UI is also made in a similar way - a dedicated VC for displaying my three IAPs, as well as being the place where the user makes the purchase of an auto-renewable subscription. I get around the problem by showing an alert to the user and dismissing the VC if there is no internet connection or the user is in a country/region I don't support. But also, my three IAP products are selectable (with one purchase button), so the prices are only displayed when the user selects one of them, by which time the SKProductsResponse should have been received and the prices are available.
Post not yet marked as solved
Hi @rich,
If you can't do this in the Sandbox, how exactly do you test it then? Via Xcode based, local StoreKit testing perhaps?
I also presume that the correct way of being notified of any actual customer refunds (which are presumably pretty rare) is via a call being made to SKPaymentTransactionObserver.didRevokeEntitlementsForProductIdentifiers, right? I mean, that's what I've been able to garner to date from researching online about these.
Cheers,
Ben
Post not yet marked as solved
Hi @Niano,
I would recommend getting the product information (via SKProductsRequest) whenever you display your in-app purchases to the user in your UI.
The call to SKProductsRequest, and the subsequent SKProductsResponse received via SKProductsRequestDelegate's didReceive method is lightning fast, so you don't have to worry about lag times.
This also means you can be sure that your products, prices, etc. are always bang up to date whenever the user needs/asks to see them.
Finally, if there is no network connection when the SKProductsRequest happens - and you therefore can't get the product information you need for the purchase - you can then add logic that states this to the user via an alert and then escapes the view controller, allowing the user another opportunity to try again once there is network connection and thus ensuring you always have that product information before going through with the purchase. You'll know there has been an error getting it if SKProductsRequestDelegate's didFailWithError method gets called and requestDidFinish doesn't.
Does this strategy make sense?
Cheers,
Ben