4

We're working on the app with auto-renewal subscription. We have just one option - monthly auto-renewal subscription with one week free trial. We also use "Subscription Status URL" to receive subscription notifications.

The app itself is similar to "TO DO LIST" applications, that can share tasks between multiple users. Thus, we keep data on the server.

Each time user loads the app or creates a task, data comes from the server with current_subscription_status parameter, e.g. we do subscription status validation on the server by simply checking receipt expiration date against current date on the server.

Currently we have only iOS version, but working on Android version as well. And user should be able to sing in to his/her account on different devices with different apple id.

The problem, we've met, is we don't receive actual purchase (subscription) notifications. E.g. when user taps "Start your free 1-week trial" button and subscribes we receive a notification (type INITIAL_BUY). After this one week trial period, we supposed to get another notification with type of something like "RENEWAL", but we receive nothing.

We contacted Apple developer support, but didn't get a real help. They just send links to Apple documentation. Where we found the following note (here is the link):

"To obtain up-to-date information as you process events, your app should verify the latest receipt with the App Store."

So, based on this, I have a question about a possible use case scenario:

User subscribes on iOS device for monthly auto-renewal subscription, e.g. he/she would like to be charged of his/her apple iTunes account. But, after initial purchase he/she closes (kills) the app and doesn't even open it on iOS device anymore. User downloads the app to Android device and use the app only on Android. So, App Store supposed to charge this user each month and send subscription status notifications to the server even if user never opened the app on his iOS device again. So, "...latest receipt verification..." never happens with the iOS app. How can this be implemented?

Tech details:

We use SwiftyStoreKit. These are two parts of in-app purchase implementation:

  1. In AppDelegate we have:

            // Auto-renewal complete transactions
        SwiftyStoreKit.completeTransactions(atomically: true) { purchases in
            for purchase in purchases {
                if purchase.transaction.transactionState == .purchased || purchase.transaction.transactionState == .restored {
                    if purchase.needsFinishTransaction {
                        // Deliver content from server, then:
                        SwiftyStoreKit.finishTransaction(purchase.transaction)
                    }
                }
            }
        }
    
  2. Here is subscribe function called when user taps "Start free trial button":

    func subscribe(completion: @escaping (_ response:Bool, _ message: String?) -> Void) {
    
    SwiftyStoreKit.purchaseProduct(self.productId, atomically: true) { result in
    
        if case .success(let purchase) = result {
            if purchase.needsFinishTransaction {
                SwiftyStoreKit.finishTransaction(purchase.transaction)
            }
            let appleValidator = AppleReceiptValidator(service: self.env, sharedSecret: self.sharedSecret)
            SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in
    
                if case .success(let receipt) = result {
                    let purchaseResult = SwiftyStoreKit.verifySubscription(
                        type: .autoRenewable,
                        productId: self.productId,
                        inReceipt: receipt)
                    switch purchaseResult {
                    case .purchased(let expiryDate, let receiptItems):
    
                        if let receiptItem = receiptItems.first {
                            // Send receipt to the server functionality
                            .............................
                        }
                        completion(true, nil)
                    case .expired(let expiryDate, let receiptItems):
                        completion(false, "Receipt has been expired")
                    case .notPurchased:
                        completion(false, "Purchase has not been processed")
                    }
                } else {
                    // receipt verification error
                    completion(false, "ERROR OCCURED")
                }
            }
        } else {
            // purchase error
            completion(false, "Canceled")
        }
    }}
    
Cœur
  • 37,241
  • 25
  • 195
  • 267
  • did you ever solve this as im exactly facing same issue? While in sandbox mode, i do get everything as expected but not in production mode. – Qaiser Butt Nov 04 '19 at 12:15

0 Answers0