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.
Related
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
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. */ }
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");
}
I'm testing in-app-purchase functionality and stuck in receipt validation step.
My receipt validation is customized and based on number of checks I proceed on server-side(calling my server API) and one them is condition for transactionID uniqueness to confirm payment.
So, using RMStore I'm getting receipt successfully and addPayment function return unique transaction to success block. After that I'm running verifyTransaction and call receiptURL inside success block.
Unfortunately, it looks like I'm always get the same receipt using receiptURL and when I send it to my server it responds me with error that transactionID already exists in DB and transactionID is not unique. This error indicates that I send the same receipt even I do new payment. Please, note I use consumable product.
Can someone show me the right workflow for functions I provide below(?):
[RMStore productRequest] - I call it right in init function.
[RMStore addPayment] - It is start of consequence I need to understand.
[[[RMStore defaultStore].transactionPersistor consumeProductOfIdentifier:pID]
-- Do I need to call this function at all? Apple sends me unique transactinID each time I pay and calling this function has no influence.
[[[RMStore] defaultStore].receiptVerificator verifyTransaction:transaction]
-- Do I need to call transaction verification?
[RMStore receiptURL] or [[NSBundle mainBundle] appStoreReceiptURL]
-- are those ways to get receiptURL equal ? Both don't work as I expect.
[NSData dataWithContentOfURL:receiptURL] - here is the main problem I'm experiencing. After different attempts with combination of functions I mentioned upper, this method always return the receipt with the same transactionID. This makes me think that there is a cash I need to refresh before run #5, #6 to get the last receipt, but it is not clear how to do that.
So, RMStore wiki looks good, but I always expect that library will give me a chance do not fully understand what is going on under the hood. Unfortunately for RMStore I have to investigate how Apple in app purchase API works. This can be resolved if a consequence of function calls will be provided, but I cannot find it anywhere(!)
Can someone review the list of functions I provided upper and help me with putting them in right order what let me fix my issue with getting the last receipt after the purchase I do?
I have two answers here to my questions:
The code:
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
, works fine(i.e. it return correct receipt body), but for some reason Apple can return TWO(or even array[]) payments where first transactionID can be the same as you previously got. As my server developer said this is unexpected behaviour. So, when I get receipt and send receipt to server it read only first transactionID which could be the same what you got previously.As result, server return FALSE as verification result(it looks like you try to pay twice). So, since it is not clear why Apple send me two or more transaction records in receipt, but as workaround I asked server side developer to check all transactions in receipt for any unique transactionID.
More investigation is needed to understand Apple behaviour but it can take more time. I did not find the answer and go ahead for now.
What is related to RMStore workflow I realised that actually we have just two most important functions: addPayment and verifyTransaction.
The addPayment function will call verifyTransaction implicitly. You should overload verifyTransaction and call serverAPI verification function inside. So, if verification is success you go to success block of addPayment and do what you need for successful payment. If not - do something else. My mistake was to call verifyTransaction inside addPayment successful block what means to call it twice.
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?