How to check availability of introductory offer in iOS

If you use introductory offers in your subscription application (trial, pay as you use or prepayment), then before you show the price on the payment screen, you need to determine the availability of the introductory offer to the user. If the user has already issued a trial, then for him you must display the full price.







image







Hi everyone, I ’m in touch Renat from Apphud - a service that simplifies the work with subscriptions in iOS-applications. Today I will tell you how to determine whether a single user has the right to activate an introductory sentence or not.







The introductory offer is valid within the same subscription group. This means that the user can issue a regular weekly subscription without a trial, unsubscribe and later issue a trial for a monthly subscription.







The Apple documentation has a diagram showing when an introductory sentence is available to the user:













It turns out that the user can use the introductory sentence if:









AND









To check the availability of the introductory sentence, you need to perform 3 steps:







1) Validate the App Store-check and pull out the array of transactions. If there are no transactions, then we do not check anything, an introductory sentence is available. If there are transactions, then perform the following two steps.







2) Check if the introductory sentence was previously used







3) Check current subscription status







Let's consider these steps in more detail.







1. Validation of the App Store check



To validate the check, you need to send a request to Apple, passing receiptData



and sharedSecret



. Replace the sharedSecret



value with your own. If you do not know your sharedSecret



, then it is described here where to get it.







 func isEligibleForIntroductory(callback: @escaping (Bool) -> Void){ guard let receiptUrl = Bundle.main.appStoreReceiptURL else { callback(true) return } #if DEBUG let urlString = "https://sandbox.itunes.apple.com/verifyReceipt" #else let urlString = "https://buy.itunes.apple.com/verifyReceipt" #endif let receiptData = try? Data(contentsOf: receiptUrl).base64EncodedString() let sharedSecret = "YOUR_SHARED_SECRET" let requestData = ["receipt-data" : receiptData ?? "", "password" : sharedSecret, "exclude-old-transactions" : false] as [String : Any] var request = URLRequest(url: URL(string: urlString)!) request.httpMethod = "POST" request.setValue("Application/json", forHTTPHeaderField: "Content-Type") let httpBody = try? JSONSerialization.data(withJSONObject: requestData, options: []) request.httpBody = httpBody URLSession.shared.dataTask(with: request) { (data, response, error) in // continue here }.resume() }
      
      





The example above uses the #if DEBUG



macro to determine the type of subscription: sandbox



or production



. If you use other macros, then you will need to update the code in this place.


2. Check if an introductory sentence has been used before



After receiving a response from Apple, we translate it into Dictionary



and get an array of transactions:







 // paste this code after "continue here" comment guard let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String : AnyHashable], let receipts_array = json["latest_receipt_info"] as? [[String : AnyHashable]] else { callback(true) return } // continue here
      
      





We go through the array of transactions and look at the values ​​of is_trial_period



and is_in_intro_offer_period



. If one of the values ​​is true



, then the user has already drawn up an introductory sentence. These values ​​come as a string, so for reliability we will try to convert the value in both Bool and string.







 // paste this code after "continue here" comment var latestExpiresDate = Date(timeIntervalSince1970: 0) let formatter = DateFormatter() for receipt in receipts_array { let used_trial : Bool = receipt["is_trial_period"] as? Bool ?? false || (receipt["is_trial_period"] as? NSString)?.boolValue ?? false let used_intro : Bool = receipt["is_in_intro_offer_period"] as? Bool ?? false || (receipt["is_in_intro_offer_period"] as? NSString)?.boolValue ?? false if used_trial || used_intro { callback(false) return } // continue here
      
      





3. Checking the current status of the subscription



To find out the current status of the subscription, we need to find the latest expires_date



and compare with the current date. If the subscription has not expired, the introductory offer is not available:







 // paste this code after "continue here" comment formatter.dateFormat = "yyyy-MM-dd HH:mm:ss VV" if let expiresDateString = receipt["expires_date"] as? String, let date = formatter.date(from: expiresDateString) { if date > latestExpiresDate { latestExpiresDate = date } } } if latestExpiresDate > Date() { callback(false) } else { callback(true) }
      
      





You can find a link to the full code of the method at the end of the article, however there is a lot of "But" in this method.







Underwater rocks





Checking the availability of a promotional offer



The condition for the availability of the promotional offer is simpler - the main thing is that the user has an active or expired subscription. To do this, look for the presence of pending_renewal_info



for your subscription group.







How it is implemented in the Apphud SDK



It is enough to call one method, passing your product



into it, which will return the result to you:







 Apphud.checkEligibilityForIntroductoryOffer(product: myProduct) { result in if result { // User is eligible to purchase introductory offer } }
      
      





And similarly for the promotional offer:







 Apphud.checkEligibilityForPromotionalOffer(product: myProduct) { result in if result { // User is eligible to purchase promotional offer } }
      
      





There are also methods for checking availability for several products at once in one call:







 func checkEligibilitiesForIntroductoryOffers(products: [SKProduct], callback: ApphudEligibilityCallback) func checkEligibilitiesForPromotionalOffers(products: [SKProduct], callback: ApphudEligibilityCallback)
      
      





Conclusion



The full method code can be downloaded here .







We at Apphud have already implemented a check on the availability of introductory and promotional offers in a convenient open-source SDK. Apphud also helps you track subscription status, analyze key metrics, automatically offer discounts to unsubscribed users, and much more. If you experience pain while working with subscriptions, try our solution for free.



All Articles