30

I am using this code for in-app purchases, took it from RaywernderLich's tutorial.

// Encode the receiptData for the itms receipt verification POST request.
NSString *jsonObjectString = [self encodeBase64:(uint8_t *)transaction.transactionReceipt.bytes
                                         length:transaction.transactionReceipt.length];

Now Xcode is saying

'transactionReceipt' is deprecated: first deprecated in iOS 7.0

How to fix it?

Pang
  • 9,564
  • 146
  • 81
  • 122
Ali Sufyan
  • 2,038
  • 3
  • 17
  • 27

3 Answers3

23

Regarding Deprecation

Since this question is technically asking how one should go about addressing the deprecated attribute its fair to assume that the OP is still deploying on an iOS version less than 7. Therefore you need to check for the availability of the newer API rather than calling it blindly:

Objective-C

Edit As pointed out in the comments you can't use the respondsToSelector on NSBundle since that API was private in previous iOS versions

NSData *receiptData;
if (NSFoundationVersionNumber >= NSFoundationVersionNumber_iOS_7_0) {
    receiptData = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];
} else {
    receiptData = transaction.transactionReceipt;
}
//now you can convert receiptData into string using whichever encoding:)

Swift

Since Swift can only be deployed on iOS 7 and above we can use the appStoreReceiptURL safely

if let receiptData = NSData(contentsOfURL: NSBundle.mainBundle().appStoreReceiptURL!) {
    //we have a receipt
}

Regarding Receipt Validation

The newer API the receipt now contains the list of all transactions performed by the user. The documentation clearly outlines what a receipt looks like:

receipt outline

Meaning that if you really, really wanted to, you can iterate through all the items contained in the receipt to validate against each transaction.

For more on receipt validation you can read obc.io

Daniel Galasko
  • 23,617
  • 8
  • 77
  • 97
  • 4
    You shouldn't use respondsToSelector in this particular case. Apple clearly states that it doesn't work in this case. You should compare the actual version numbers. RTFM ;) https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSBundle_Class/#//apple_ref/occ/instp/NSBundle/appStoreReceiptURL – Maciej Swic Dec 19 '14 at 09:31
  • Also, can you treat the new receipt just like the old one? I.e. was the old one PKCS7 encrypted and ASN.1 encoded as well? – Maciej Swic Dec 19 '14 at 09:33
  • @MaciejSwic We never changed the way we treated receipts so I don't think so and the docs don't mention anything either: https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateLocally.html – Daniel Galasko Dec 19 '14 at 09:39
  • Well thats only partly true, previously Apple didn't encourage local validation and the format was "closed" and subject to change at any time. But maybe it was the same all along and just became documented as of late, don't know the details just wanted to bring up the question. – Maciej Swic Dec 19 '14 at 09:40
  • @MaciejSwic you might be right, see this - http://stackoverflow.com/questions/19955352/invalid-transaction-receipt-returned-by-appstorereceipturl-nsdata-in-ios-7 That being said this question isn't about decoding the receipt:) – Daniel Galasko Dec 19 '14 at 09:41
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/67308/discussion-between-maciej-swic-and-daniel-galasko). – Maciej Swic Dec 19 '14 at 09:42
  • @MaciejSwic I'm not sure if I'm following your bounty correctly but we use renewable subscriptions and the receipt contains an array of all the purchases made by the user? Please see my updated post – Daniel Galasko Dec 19 '14 at 11:57
  • @DanielGalasko isn't the iOS version incorrect? I think you'd want to use if(NSFoundationVersionNumber >= NSFoundationVersionNumber_iOS_7_0) – Francesco Puglisi Aug 04 '15 at 15:00
  • @singingAtom you are correct! Thanks! Just updated my answer – Daniel Galasko Aug 04 '15 at 19:39
17

Replace with something like:

[NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];

Convert NSData to NSString after that.....

Sarat Patel
  • 856
  • 13
  • 32
Nikos M.
  • 13,685
  • 4
  • 47
  • 61
  • Read this: https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html#//apple_ref/doc/uid/TP40010573-CH104-SW1 – Nikos M. Oct 30 '13 at 14:47
  • were you able to use this for in-app-purchases? – locoboy Oct 21 '14 at 05:09
  • 1
    This is incorrect and not applicable to in app purchases which is what the tutorial is about. – Maciej Swic Dec 14 '14 at 12:02
  • It does in fact contain the IAP receipts as well: https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateLocally.html#//apple_ref/doc/uid/TP40010573-CH1-SW3 – Rick Dec 16 '14 at 09:43
10
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
if(!receipt) {
 /* No local receipt -- handle the error. */ 
}
NSString *jsonObjectString = [receipt base64EncodedString];
Phil
  • 1,018
  • 10
  • 10