Sunday, November 18, 2018

Handle ios inAppPurchase auto-renewing subscription without server side receipt validation

Instead of asking user to purchase your app before downloading it, inAppPurchase provides more options to allow user to purchase the app. In order to leverage ios inAppPurchase function, app developers need to integrate ios StoreKit into the application.

Auto renew subscription is a typical case for this purpose if you want to charge users periodically for using your app.

Two modules to be implemented in order to support auto renew inAppPurchase function
1. Get product information
Based on product id defined in app store connection, application can query the product information using SKProductsRequest object. In the didReceiveResponse delegate method, the product information (SKProduct) is available in the returned SKProductsResponse.products. User needs this information for making a purchase.

2. Purchase the subscription
2.1 In order to purchase a subscription, application first creates a SKPayment object based on SKProduct object returned in step 1, then call SKPaymentQueen.default.add(SKPayment:) method to start the purchase

2.2 StoreKit processes the purchase request submitted in SKPaymentQueue, and then inform the application about the purchase status and result in SKPaymentQueue's updatedTransactions method. To do that, application must add a queue observer (implementation of of SKPaymentTransactionObserver protocol) to get payment queue events.
SKPaymentQueue.default().add(self)

When purchased state is reported by updatedTransactions method, it indicates the purchase is finished, and the app should give user the permission to access the resource, and then call finishTransaction to remove the transaction from paymentQueue. Note finishTransaction should also be called even if the transaction failed.

func paymentQueue(_ queue: SKPaymentQueue,

                    updatedTransactions transactions: [SKPaymentTransaction]){
   switch transaction.transactionState {
      case .purchased:
         queue.finishTransaction(transaction)
         //give user permission
     case .restored:
          queue.finishTransaction(transaction)
         //restore the transaction and give user permission
     case .failed:
        queue.finishTransaction(transaction)
        //inform user the purchase failure
      }
    }
}

For auto-renewing subscription, the transaction date and related information can be stored in keychain, so if user deletes the app from device and then installed it again, the purchase record will still be there, so user does not need to restore the purchase record before using the app.

If user purchased the auto renew subscription and then switch to a different phone, then before let user to purchase the subscription, you should allow user to restore the subscription by calling the below method.
   SKPaymentQueue.default().restoreCompletedTransactions()
When the subscription gets restored on the new device, the application paymentQueue:updatedTransaction method will received the stored event. The original transaction is available in the transaction.origin property. The actual transaction date should come from transaction.origin.transactionDate property.

Note when the subscription is auto renewed, the application's paymentQueue:updatedTransaction  queue will be called after the AppStore automatically renew the subscription without user interaction. In this case, the transaction parameter contains the information for the current renew's information The transaction.origin contains the original initial transaction info. So transaction.transactionDate should be used to update the subscription date.

For simple application, it can just compare the current date with the transaction date extended with the subscription period, if the subscription is still within that period, then allow users to use the app. Otherwise, ask user to purchase or restore the subscription.

Choose inapppurchase product type:
1. users can purchase consumable products many times, but can only buy non-consumable project only once. If users try to buy non-consumable project again after previous purchase, iOS SDK will show an message box to user to prevent the purchase.
2. Although user can buy Non-Renewing Subscription more than once, but when user buy it second time, ios SDK will show a dialog saying "You've already purchased this subscription, tap buy to renew or extend it." This may cause confusion to user.
3. Auto-renewable subscription does not have a way for user to easily unsubscribe the product, this may cause concerns to users for using it. Although it is easy for application to handle renew as it automatically renewed by app store, and the application only needs to handle the renew transaction result.

Choose between free trial period and limited function before user buys 
Before users purchase your inapp purchase item, you may want to let users first experience your application. You can do this by either providing a free trial period, or you can limit only partial functions are available for users before they purchase the product.
Comparing with free trial period, it is relative easier to provide limited function for users, for example, you can only allow user to watch a single chapter of a book, or view few minutes of a movie. As with free trial period approach, you have to implement brand new logic in your application to manage the beginning and end of free trial period, and also properly handle the case when user delete and reinstall the app on the device. In addition, some inapppurchase product types may not support free trial period by App Store.

Prompt user for purchase result
When user subscribes an item, after the purchase is finished, iOS SDK will show a message box to user to report the success result. So application does not need to show a message box to report the result to user. However, if user restores an subscription to a device, after the restoring is finished, iOS SDK does not show anything to user, so application should show a message box to tell user the restoring has succeeded.

No comments:

Post a Comment