4

I want to publish an iOS app that has an auto renewing subscription. While there is a ton of information regarding this, much is outdated so I will state what I have accomplished so far.

  1. I am working in Swift 2.0, so any objective C code will not help me.

  2. I will not be using my own server to communicate with Apple to verify the receipt, so I believe I either need to have the app communicate with Apple servers directly or I can parse the receipt locally on the device.

  3. I have been able to locate a receipt on the device (not sure if there are multiple ones) using the following code

    func checkForReceipt() {
        let receiptUrl = NSBundle.mainBundle().appStoreReceiptURL
    
        let fileExists = NSFileManager.defaultManager().fileExistsAtPath(receiptUrl!.path!)
    
        if fileExists {
    
            let receiptData = NSData(contentsOfURL: receiptUrl!)
    
            //Now what do I do to decode the data and validate the receipt
    
        } else{
            requestReceipt()
        }
    }
    

However, I cannot figure out how to decode the receipt so then I can determine the expiration date and other verification steps to ensure it is a valid receipt.

I have to say it is very frustrating that something very essential and useful to developers has to be so difficult to follow and locate. Any help is much appreciated and hopefully will be useful to many others.

MrByte11
  • 300
  • 2
  • 9
gbotha
  • 1,231
  • 17
  • 23

1 Answers1

4

Here is a link I found helpful

Refer to it if my code was not clear

Below is the functional code I used to check the subscription status of my ar-iap

Read further below for some extra info on each corresponding * found as comment

func checkForReceipt() {
    let receiptUrl = NSBundle.mainBundle().appStoreReceiptURL

    let fileExists = NSFileManager.defaultManager().fileExistsAtPath(receiptUrl!.path!)

    if fileExists {

        let receiptData = NSData(contentsOfURL: receiptUrl!)

        let receiptToString = receiptData!.base64EncodedStringWithOptions([])
        let dict = ["receipt-data" : receiptToString, "password" : "YOUR SHARED SECRET"] //**
        do {
            let request = try NSJSONSerialization.dataWithJSONObject(dict, options: []) as NSData!
            let storeURL = NSURL(string:"https://sandbox.itunes.apple.com/verifyReceipt")! //***
            let storeRequest = NSMutableURLRequest(URL: storeURL)
            storeRequest.HTTPMethod = "POST"
            storeRequest.HTTPBody = request

            let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
            let dataTask = session.dataTaskWithRequest(storeRequest, completionHandler: { (data: NSData?, response: NSURLResponse?, connection: NSError?) -> Void in
                do {
                    let jsonResponse: NSDictionary = try (NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary)!
                    //****
                    let expDate: NSDate = self.expirationDateFromResponse(jsonResponse)!
                    print(expDate)
                } catch {
                     //handle NSJSONSerialization errors
                }

            })
            dataTask.resume()
        } catch {
            //handle NSJSONSerialization errors
        }
    } else {
        requestReceipt()
    }
}

** You can get the shared secret from you iTunes Connect Account: Go to MyApps > "yourappname" > Features > View Shared Secret > Generate Shared Secret then insert your generated secret in the password field in dict

*** make sure to change the storeURL to "https://buy.itunes.apple.com/verifyReceipt" when you go to production

**** expirationDateFromResponse(jsonResponse: NSDictionary) -> NSDate? is a function that reads apple's json response and returns the expiration date of the ar iap

MrByte11
  • 300
  • 2
  • 9
  • 1
    Note the following comment in the Apple documentation linked above: **"Important: Do not call the App Store server /verifyReceipt endpoint from your app."** What you will want to do instead is either a) send the receipt to your own server backend for validation, which in turn would call /verifyReceipt on Apple’s server, or b) validate the receipt locally using OpenSSL / ASN.1 as described here: https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateLocally.html#//apple_ref/doc/uid/TP40010573-CH1-SW2 – Frederik Aug 09 '18 at 10:11