Auto-renewable subscriptions for iOS

Part 2: Implementing auto-renewable subscription in the App

Balaji Malliswamy
May 18, 2018 · 5 min read

When the app deals with auto-renewable subscription, we need to know the appropriate logic to determine whether the subscription is currently active, if not then when it was active. We also need to react to new and renewed subscriptions and properly handle expired subscriptions. For integrating auto-renewal subscription in the app, we have to Setting up an auto-renewable subscription in iTunes Connect.

Implementing StoreKit

StoreKit allows the app to communicate with iTunes Connect and request in-app purchase information and handles the payment operations. Before integrating StoreKit we have to finish the in-app purchase setup in iTunes Connect.

  • Deny access for free users
  • Retrieve product information
  • Request payment
  • Complete the transaction
  • Restore the purchase

Before we implement the purchase logic, we have to restrict the free user from accessing the premium digital content. For example, Vookmark is one of our product where we are restricting a user from adding tags to videos and few other features like advanced search.

First of all get the product identifier from iTunes Connect (subscription product id). To create products in iTunes Connect with the same identifiers under the tab Features -> In-App Purchases and enable in-app purchases in project settings under capabilities tab. We have discussed this in detail with my part 1.

In this section, we are going to implement the logic for loading and fetching the product and also presenting the product to the user,

  • Load product identifier
  • Fetch the product information
  • Present product to the user

Import the StoreKit framework for implementing the logic of payment

import StoreKit

Create SKProductsRequest object for loading the product, we can load the product using product identifier we get from product we created in iTunes Connect.

var productIdentifier = "xxx.xxx.sampleProductId" //Get it from iTunes connect
var productID = ""
var productsRequest = SKProductsRequest()
var iapProducts = [SKProduct]()

Now, Lets make the product request to iTunes Connect for fetching the information about the product using StoreKit.

func fetchAvailableProducts() {
// Put here your IAP Products ID's
let productIdentifiers = NSSet(objects:
productIdentifier
)
guard let identifier = productIdentifiers as? Set<String> else { return }
productsRequest = SKProductsRequest(productIdentifiers: identifier)
productsRequest.delegate = self
productsRequest.start()
}

Now integrate SKProductsRequestDelegate,

func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
if response.products.count > 0 {
iapProducts = response.products
if iapProducts.count > 0 {
let purchasingProduct = response.products[0] as SKProduct
// Get its price from iTunes Connect
let numberFormatter = NumberFormatter()
numberFormatter.formatterBehavior = .behavior10_4
numberFormatter.numberStyle = .currency
numberFormatter.locale = purchasingProduct.priceLocale
if let price = numberFormatter.string(from: purchasingProduct.price {
// Show "Go Pro for \(price) / year" in the Buy button
// and stop animating/loading the button
}
} } }

We can get the product price from this delegate. Display the product information initiated from this function.

Requesting Payment

Now that you’ve got the product (subscription) information displayed to user. The next step will be initiating the payment for the subscription.

// MARK: - Make purchase of a product
func canMakePurchases() -> Bool {
return SKPaymentQueue.canMakePayments()
}
func purchaseProduct(product: SKProduct) {
if self.canMakePurchases() {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().add(payment)
productID = product.productIdentifier //also show loader
}
}

Purchase status will be available in this delegate method ,

func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
guard let productType = ProductType(rawValue: transaction.payment.productIdentifier) else {fatalError()}
switch transaction.transactionState {
case .purchasing:
case .purchased:
//receiptValidation
case .failed:
case .restored:
//receiptValidation
case .deferred:
}
}
}

Using this state changes we can do the changes in the UI for purchase.

Complete the Transaction

Technically in the previous steps, we did the payment request but complete the payment process in our logic. Apple will inform you on the successful purchase. From there it’s our responsibility to deliver the content/feature to the user.

After purchasing the auto-renewable subscription, the user receives the Receipt data for the app to update with subscription information. Receipts reside on the user’s device as cryptographic binary data.

Complete the transaction and deliver the product by validating the subscription receipt, developers can do this validation in two ways

1. Doing receipt handling on the device
2. Doing receipt handling on the server

Validating the subscription receipt for unlocking the content to the user.

Doing receipt handling in the device

you can refer the receipt validation here.

Once you’ve unpacked the receipt file, you are only interested in the latest expiration_date. You extract this by looping through all in-app purchase records in a receipt and finding the latest expiration_date field using this we can give the content access to the user.

Handling the renewal transaction is a common area of mistake. In a standard IAP flow, you only need to worry about the status of the StoreKit payment queue while a user is completing a purchase. With subscriptions, your app needs to be prepared to handle these transactions at any time. Now you need to handle purchases from literally anywhere in the app; the effect of a user’s subscription status changing needs to be considered on every screen.

The appropriate way to handle it: as soon as it appears on the StoreKit queue, validate the receipt, and update a user’s entitlements. However, this can be difficult.

Subscription validation with server means: rather than parsing a receipt on the device, you send that receipt to a server for validation and parsing.

Doing receipt handling in server-side

Handling the receipt validation on the server is more reliable because debugging and handling the user issue is more feasible in this approach. Polling and status notification are the key points for using subscription in Server.

Restore the purchase

Your app should handle restore subscription after user switched device or deleted the app. It is quite simple, all you have to do is call

SKPaymentQueue.default().add(self)
SKPaymentQueue.default().restoreCompletedTransactions()

If restoring was successful, the following method will be called:

func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction])

And you have to handle the “bad” case:

func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {
//handle the error and show the error to user
}

Next part: Testing auto-renewable subscription

Previous part: Setup an auto-renewable subscription in iTunes Connect



We are building Vookmark — an easy video bookmarking service which allows you to bookmark videos and watch them later any time on any device. More details on the website: https://vookmark.co


Find it a good read?

Recommend this post (by clicking 👏 button) so other people can see it too…
reach me on Twitter Balaji Malliswamy

Swift India

Swift Developer Community in India 🇮🇳

Thanks to Anas Zaheer and Prabha Mylvakanan

Balaji Malliswamy

Written by

 developer, Chennai & Writer at Swift India https://about.me/balajimalliswamy , https://unsplash.com/@blahji

Swift India

Swift Developer Community in India 🇮🇳

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade