iOS - Validation for consumable products - ios

I am wondering where I should store the receipt data when the validation for a consumable item failed.
To validate the receipt, we have to send a receipt data which is gained from below code to our server, but for some reasons it might be failed.
// Load the receipt from the app bundle.
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
if (!receipt) { /* No local receipt -- handle the error. */ }
/* ... Send the receipt data to your server ... */
In case for that, we have to store the receipt data in the app to send the receipt data again.
I tried using NSUserDefaults but I found that the data will disappear when the user delete the app itself.
How do you deal with the case?

Related

iOS - See contents of a receipt

I'm working on handling a scenario, where my app was paid on the app store and now I'm making free to download with in app purchase.
However anyone who has previously purchased I want it to be unlocked for them so they don't pay again.
I have the following code which actually gets the receipt:
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
if (!receipt) {
NSLog(#"NO RECP");
} else {
NSLog(#"GOTACH");
}
However looking at that NDData receipt its all binary data. How can I actually see whats inside that? I've seen various posts about making requests to some url - do I need to do that? I just want to see whatever in that file (hoping for something like version/bundle id when purchased or even date when first purchased).
And my second question, will that receipt only get the receipt for my app, or does it return all receipts on the device?
Thanks.

subscription receipt not received after reinstall app

I am implement renewing subscription in my application.
When I purchase pack then I get receipt from app store by following code
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
Question : When I reinstall my app. I get nil from receipt In iPhoneX(11.4.1) But working fine in iPod(9.3.5)
Thanks in advance

Lost connectivity before receiving purchase receipt from apple In-app purchase

I have implemented In-app purchase in my app. So what I do is, after user completes payment with app store & the control goes to
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions
then I update the purchase receipt to our server. Rest of the operations are done by server.
But one of our users faced an issue where he completed the payment but he lost internet connection before the above method was called. Resulting, our app does not know about the payment.
I know that the receipt is stored in the device. But is it the right way to send the receipt to the server from device every time user uses app??
Well, What i did to avoid this was, Keep a Check (like a boolean : transactionInProgress) when the transaction begin and when I have sent data to the server I change the value to "NO".
In this way the next time the app connects. just check if the transactionInProgress was checked, if it is then there was a transaction on going and you can fetch the receipt that must be stored by SKPaymentTransactions using
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
if (!receipt) { /* No local receipt -- handle the error. */ }

How do I read receipt data with existing paid iOS app?

I have a paid app that I'm thinking about making free with in app purchases. If I make the switch I'll need to check if the user has already paid for the app and then enable the paid features.
I think the below code should do what I need but I'm not sure how to test it. I built the app and ran it using my development provisioning profile on my device and receitpData is empty. So I built the app with a distribution provisioning profile and submitted it to the app store then downloaded the app using test flight but I'm still having the same problem.
How do I get the receipt data from an existing app?
Do I need to enable in-app purchases for this app to get this data?
NSURL *receiptUrl = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receiptData = [NSData dataWithContentsOfURL:receiptUrl];
I figured it out:
#import <StoreKit/StoreKit.h>
Don't forget to add its delegates
<SKPaymentTransactionObserver, SKProductsRequestDelegate>
Here's the code:
SKReceiptRefreshRequest* request = [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:nil];
request.delegate = self;
[request start];
and then:
-(void)requestDidFinish:(SKRequest*)request{
if([request isKindOfClass:[SKReceiptRefreshRequest class]]){
NSLog(#"YES, You purchased this app");
}
}
- (void)request:(SKRequest*)request didFailWithError:(NSError *)error{
NSLog(#"NO, you need to buy it");
}

Control push notification device registration

I am implementing the push notification service in my app. I created a the service on the Easy Apns style, but in a simpler way. I have a service that uses a MySql database to store the application tokens and a second service that accesses to the database, prepares the notifications and sends them.
It works, but I'm not sure if my registration part (on the client side) is correct.
The app delegate method:
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {
NSString *devToken = [[[[deviceToken description]
stringByReplacingOccurrencesOfString:#"<"withString:#""]
stringByReplacingOccurrencesOfString:#">" withString:#""]
stringByReplacingOccurrencesOfString: #" " withString: #""];
NSString *urlString = [#"/apns.php?"stringByAppendingString:#"task=register"];
urlString = [urlString stringByAppendingString:#"&appname="];
NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleDisplayName"];
urlString = [urlString stringByAppendingString:appName];
urlString = [urlString stringByAppendingString:#"&devicetoken="];
urlString = [urlString stringByAppendingString:devToken];
NSString *host = #"myservice.php";
NSURL *url = [[NSURL alloc] initWithScheme:#"http" host:host path:urlString];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
}
This code updates the token each time the app is restarted. Is it correct? Shouldn't the registration phase happen just once (for example, the first time the user accepts the notification service)? In my case, every time the app is restarted, the token is added to my database (so I have to control from the server side if it is a replicated token).
There's nothing wrong in the way you are registering to APNS, but you can do it more efficiently.
Apple suggests that you register to the APN service every time the app is launched (and not only on the first time it is launched), because theoretically the device token might change (though it practice it almost never does).
An application should register every time it launches and give its provider the current token.
By requesting the device token and passing it to the provider every time your application launches, you help to ensure that the provider has the current token for the device. If a user restores a backup to a device or computer other than the one that the backup was created for (for example, the user migrates data to a new device or computer), he or she must launch the application at least once for it to receive notifications again. If the user restores backup data to a new device or computer, or reinstalls the operating system, the device token changes. Moreover, never cache a device token and give that to your provider; always get the token from the system whenever you need it. If your application has previously registered, calling registerForRemoteNotificationTypes: results in the operating system passing the device token to the delegate immediately without incurring additional overhead.
You can store the device token locally in NSUserDefaults, and each time didRegisterForRemoteNotificationsWithDeviceToken is called, you can compare the newly received device token with the stored device token. You need to send the device token to your server only if it's different than the stored one. That would save unnecessary server calls.

Resources