I've seen a few topics on stackoverflow on promo codes handling: Detecting promo code, Handling promo code, Consumable promo codes and none of them have the right answer. There are some swift guides on how to create and redeem promo codes for in-app purchases, but nobody talks about what's happening later.
Redeeming an (in-app purchase) promo code on the AppStore:
lets you open the app on successful redeeming
notifies the transactionObserver declared preferably in the AppDelegate
Some people say it's all you have to do (and then when the user chooses payment there's suddenly no 9,99$ information, but something like 'Use promo code', which StoreKit handles behind the scenes). I'm afraid that doesn't work like that.
Should I handle it somehow in the AppDelegate - if there's a transaction coming right after the app launches (meaning that someone used promo code)? Should I present an alert telling the user he used the promo code, and unlock the functionality or add some 'gems' to his account (if it's consumables)?
EDIT: There are also these two apple developer forum topics: Few people have the same problem - no answer, Apple staff responded about where to place transactionObserver
EDIT2: Or perhaps promo codes cannot be applied to consumable products, which are used once and cannot be restored (using in-app promo codes is based on restoring I've read somewhere?)
For those who got stuck like me.
Indeed you need to declare a class (e.g. PurchaseHelper) importing StoreKit with SKProductsRequestDelegate and SKPaymentTransactionObserver extensions inside AppDelegate.
Then if the user redeems a promo code inside App Store - and he opens your app - 'updatedTransactions' func gets called and it's the only time you can do something with the purchased product.
What I did was - save an info/transactionId to UserDefaults, so in the main screen user gets an alert like "You redeemed a promo code. Choose your favorite spot and click Purchase to get it for free".
Of course a better solution is to do enable the product right away in the AppDelegate. If your promo code gives the user 100$ (consumable) then you can just add it (but there's still question if he is logged in).
If you know any better solutions, please tell me.
Related
I am new to the world of in-app purchase and I just watched the tutorial on iTunes about how to integrate it to my app. I am wondering how the developer would keep track of the items purchased WITHOUT having to verify the receipt. I thinking it would be nice if we could just store the purchased items in the app because then we would be able to identify items purchased without having internet connection.
What's the convention to do this? Is this a bad practice?
There are 2 way you can keep track of purchased items:
1 - Storage - Temporary / Permanent. Obviously Temporary storage doesn't protect you against deletion / device change. Permanent storage can be ensured if you store it in keychain or on your own server soon after purchase is successful.
2 - Apple's own API tells you - based on certain rules / condition.
Condition: If this is non-consumable purchase, and you try to purchase again.([SKPaymentQueue addPayment])
The response from itunes store will cause storekit to invoke updatedtransactions - with status - SKPaymentTransactionStateRestored. This simply means that product is already purchased, needs to be restored - so it is your responsibility to unlock it.
In short, it won't allow you to purchase again if it's nonconsumable purchase. Same must be true for subscriptions that haven't yet expired (not sure about it).
If you need step by step tutorial on how to integrate IAP - here is my own lecture series with SWIFT and Objective C. It also accompanies code sample.
This is a bad practice because, what happens when your user deletes and re-installs the app?
He won't have his purchased items anymore.
This tutorial is a very good one, it should point you in the right direction.
There should be an app or device feature that is allowed or is capable of recording and managing EVERY in-app purchase made through the Apple ID.
Problem is… The current setup of in-app purchases is not user friendly.
In short: Buying is your problem and recording your purchases is only a "convenient feature provided generously" by Apple Inc and app developers.
It shouldn't be like this though. Apple Inc and the app developers should consolidate user purchase info and make it transparent and easy to access/understand by the user.
This is the 21st century, after all.
I Have a strange problem with iphone in app purchase! i created a product in the ituneconnect and then (using MKstorekit) i bought the product in sandbox environment .. and everything went will the first time... i removed the app from the device and created another test account.
and i found in the debugger mode that it sees the product as already purchased !!
tried everything from cleaning the project and all the tricks for the cache problems.. but still the problem occure .. is that normal?? or i'm doing something wrong?
please advice
since you are deleting the app in that case there is no chance that NSUserDefault will be storing this purchase so only thing that comes to my mind is the type of purchase... what type of purchase did you state in itunesconnect consumable , non-consumable or subscription? it could be because you stated subscription as purchase type(subscription purchases can only be bought once)... hope this helps..
this is what I have come across at http://www.raywenderlich.com/2797/introduction-to-in-app-purchases
StoreKit will prompt the user “are you sure?”, ask them to enter their
username/password (if appropriate), make the charge, and send you a
success or failure. They’ll also handle the case where the user
already paid for the app and is just re-downloading it, and give you a
message for that as well.
I fount the solution..
in app delegate i have to call
- (BOOL) removeAllKeychainData
in MKStoreManager, call it once at beginning, and then remove it from code, you don't want to accidently leave that on release :S
We are developing an app that uses the non-renewing subscription IAP model. While testing the subscription purchase process in the sandbox, we are seeing two messages with ‘buy’ buttons pop up.
The first message is displayed with the product information: “Do you want to buy one subscription for $xx.xx?”
After you click ‘buy’ for the first message, a second message (with another buy button) is displayed: “You’ve already purchased this subscription. Tap Buy to renew or extend it.”
Is this normal iTunes/sandbox behavior for re-purchasing non-renewing subscriptions after they have expired? Does iTunes require you to tap a ‘buy’ button twice?
I checked the behavior of EverNote by extending their non-renweing-subs, and it seems that is the behavior which we can't avoid.
I encountered the same issue with Non-Renewing-Subs + MKStoreKit, and thought it has something to do with my settings first, but I don't think there is nothing we can do about it.
One thing you could try (although I'm not sure Apple will like this) is creating a bunch of identical products in the store (say 48 identical products but with different identifiers: subscription1, subscription2, ..., subscription48). Then, when you need to extend the subscription you just pick the next subscription. This way the user will not get that annoying message. With 48 different products you should be good for 4 years. Hopefully by then Apple has its sanity back :)
may be you have purchased it and it hasnt expired. or it may have been purchased in a diffferent device, but you still have old one. when its tried to purchase its found that its already bought hence asked to extend. IAP is tied to apple id.
Does anyone have any ideas on how to reset and/or clear the iOS in-app purchase sandbox?
I have an app that I'm testing with the sandbox, and I'd like to test new purchases without having to create a new test user every time I purchase something.
If I don't do this, then I (of course) always get a message that the in-app purchase item has already been purchased when I click on my app's buy button.
IMO there are 3 things you can do to make testing non-consumables bearable:
You can have many test accounts associated to one email. Gmail for example lets you add a "plus" string to the email to create aliases for an address: so tester+01#gmail.com and tester+02#gmail.com both really just go to tester#gmail.com. Probably other email hosts do the same. When you create a test account you need to introduce: first name, last name, email address, password, secret question, secret answer, date of birth, and iTunes store country. You can put exactly the same data (including password) for tester+01#gmail.com and tester+02#gmail.com and you will have two test accounts. Finally, in your tester#gmail.com inbox you will receive two verification emails from Apple to confirm both test accounts.
Say that you have a non-consumable with product ID #"Extra_Levels". Instead of writing #"Extra_Levels" in all methods (requestProduct, purchaseProduct, ...), just write PRODUCT_ID1 and at some header file put #define PRODUCT_ID1 #"Extra_Levels" (with no semicolon!), then the preprocessor will search PRODUCT_ID1 and substitute it for #"Extra_Levels". Then creating a new non-consumable called #"Extra_Levels_01" and changing the #define will be as good as resetting the purchases for all your test users.
As appsmatics pointed out, you can test the correct behavior of your code when you buy a non-consumable IAP by first using a consumable IAP (so that test user can make as many purchases as needed) to get rid of some bugs. Of course, you should also test the code with the real non-consumable IAP after that.
You can't do this, as far as I know. The sandbox backend works like a real account-- once it's purchased, it's purchased (and thus you can test restore). You should do most of your development with the store stuff shimmed out, and then when you get to testing it for real, just expect to create several test accounts.
You can clear the purchase history for a tester so that you can continue to use the same sandbox Apple ID for ongoing testing. Clearing purchase history will delete all past auto-renewable subscriptions and non-consumables purchased by the selected testers in the sandbox environment. In-app purchases made by customers on the App Store are not affected.
To clear tester purchase history:
From Users and Access, under Sandbox, click Testers.
Click Edit.
Select the checkbox for each tester you want to modify and click Clear Purchase History.
Click Clear Purchase History in the dialog that appears.
Sandbox Apple IDs with a high number of purchases may take longer to clear. This action cannot be reversed.
I have 2 in app purchase items.
1 for production.
and the other for testing. when I need to "clear" I delete the in app item and create new one (15 seconds in itunes connect and 1 second to change the product id in code)
if i dont need to test "new user", i use the production in app item.
Deleting your app and reinstalling works also for sandbox testing. Depends on the app obviously, but I'm testing a subscription based app that only purchases during sign up at the moment so it's been the easiest solution.
Well, technically you don't need that.
If you get SKPaymentTransactionStateRestored, it is 100% equivalent to the app store verifying the user and granting him the purchase. I have a switch like:
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for( SKPaymentTransaction *purch in transactions )
{
switch( purch.transactionState )
{
case SKPaymentTransactionStateRestored:
info( "PURCHASE RESTORE" ) ;
// fall thru
case SKPaymentTransactionStatePurchased:
[[SKPaymentQueue defaultQueue] finishTransaction:purch];
// Do regular changes to app state for this purchase,
// register in keychain, etc.
break ;
//.. other cases
}
}
}
The question of having your app logic / take back the purchase is simple: if you're caching purchases in keychain, delete your keychain. If you're doing it some other how, just change your local app state to pretend like the user never purchased it before. The request to purchase dialog is still exactly the same, the only difference is when you punch YES, it gives you SKPaymentTransactionStateRestored instead of SKPaymentTransactionStatePurchased.
You can clear the purchase history for a sandbox Apple ID in App Store Connect.
To clear tester purchase history:
From Users and Access, under Sandbox, click Testers.
Click Edit.
Select the checkbox for each tester you want to modify and click Clear Purchase History.
Click Clear Purchase History in the dialog that appears.
see Documentation https://help.apple.com/app-store-connect/#/dev7e89e149d
Check out SimStoreKit. It's a "simulated version of the iPhone's StoreKit, for testing store UIs on the iPhone Simulator, or even on device without having to set up IAP in Connect."
SimStoreKit stores purchases in the user defaults under the key ILSimSKTransactions. So to clear all purchases you can do:
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"ILSimSKTransactions"]
On the simulator, you can simply remove your app and install it again.
I've successfully used SimStoreKit to debug my app's store front before testing with the sandbox. The beauty of this library is that it can be set-up to use the same class names as the real StoreKit framework (by doing #define ILSimReplaceRealStoreKit 1 before doing #include <ILSimStoreKit.h>).
In source files where I need to access StoreKit, I include this header file:
#import <TargetConditionals.h>
#if TARGET_IPHONE_SIMULATOR
#define kILSimAllowSimulatedStoreKit 1
#define ILSimReplaceRealStoreKit 1
#import <ILSimStoreKit.h>
#else
#import <StoreKit/StoreKit.h>
#endif
This has the effect of using SimStoreKit when I run on the simulator and the real StoreKit when I run on the device.
This is now possible for subscriptions purchases through Reset Eligibility
On the test iOS device, open Settings > Apple ID > Media & Purchases (or iTunes &/or App Store for iOS 13 and earlier). Under the Sandbox Account section, tap your highlighted Sandbox Apple ID then tap Manage to open the sandbox Subscription Management page.
If the subscription has expired, tap one of the options to resubscribe.
Once you resubscribe or when you have a subscription going on, you can use the Reset Eligibility button to reset and redeem another introductory offer (trial or discounted price).
Just keep using the same test account, restoring purchases as opposed to completing new ones. After all, whether you start a new purchase or restore an old one, YOUR APP will do the same thing (at least initially, maybe the user interface will update differently upon completion). Apple are the folks handling things differently in those different situations - don't worry about it.
Place your delivery logic in the SKPaymentTransactionStateRestored case within this method's implementation for testing:
- (void)paymentQueue:(SKPaymentQueue *)queue
updatedTransactions:(NSArray *)transactions;
Then be sure to put that delivery logic into the SKPaymentTransactionStatePurchased case.
At the end, because most of us are obsessive-compulsive to varying degrees, do a final test with a fresh account (not a big deal to make a second one for absolute certainty).
The final thing to note: consider apple's position. If there was a problem with developers having to waste time creating tens or hundreds of accounts to test IAP thoroughly, they would have solved the problem. There is no problem.
alternatively to create multiple test user solution you can create multiple test in app purchases in iTunes connect then you don't need to change a user account.
I have had zero success with in app purchase. I have submitted the free app binary, and then rejected the binary. I have added the test product. I have approved the test product TAP001.
I have followed the code examples to no avail. I do a SKProducts request using both "com.companyname.appid.TAP001" and just "TAP001"
Regardless, I get an empty response.products and response.invalidProductIdentifiers with the product string I sent.
I created a test user, but seeing how I cannot get any product info, the test user doesn't really come into play yet.
Can in app purchase be tested in debug or release builds? Or does it have to be a distribution?
Must one have a fully accepted app in the app store prior to testing in app purchase?
I am simply trying to test the process out and I do not have an actual app yet. I went as far as to fill out all the bank and tax information. I have followed the steps in the app docs but clearly I have something wrong or missing.
Thanks
I just got it to work. I used only "TAP001" for a product instead of "com.companyname.appid.TAP001". and I got product information back.
I feel dumb but I know have tried "TAP001" in the past with no success but I have tried so many things prior to this that I must have had some other information wrong a the time I did.
For those who are struggling with this issue, I can say:
Your app does not need to be live in the store.
You do need an app in the App store submission. Reject the binary after uploading it.
Testing your app should work in Release or Debug modes
You do need an in app product "Cleared for sale"
Your product request only needs to contain the product id(s)
Here is an example:
- (IBAction)buyButton1Click:(id)sender{
NSSet *productList = [NSSet setWithObjects:#"TAP001", #"TAP002", nil];
SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers:productList];
request.delegate = self;
[request start];
}
According to Apple's itunes connect FAQ, you need to create a test user in order to use the itunes store sandbox environment.
That being said, even after creating such a user and setting my iphone to use that user, I am still experiencing the same issue that you report: all products are "invalid" according to the store kit API.
I'll update this post when I figure it out.
I've also heard that some times, you need to wait several hours before the in-app item goes through apple sand box servers, so it could be the reason it doesn't work yet. I'm in that case, i'm going to wait 24 hours to see, i'll let you know !!!
So: Imagine an extremely complicated and convoluted set of rules for how to test in app purchases. Now make it ten times more complicated. That is apple's solution. :)
You'll need to read the itunes connect developer guide, and probably also the In App Purchase guide. The short answer is that you'll need a special test account and you'll also need to use it in a very particular way if you want to test your in app purchase.
Good luck!