0

I'm testing my app auto-renewable subscriptions but SKPaymentTransaction.transactionState never changes to .purchased and it's always .restored. Everything was working ok but I can get nothing but .restored since I first called SKPaymentQueue.default().restoreCompletedTransactions(). I tried deleting the app from my iPhone, relogin into my sandbox account, creating a new sandbox account, restarting Xcode, cleaning the build folder,... What I'm doing wrong? Please find my code below:

func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
    for transaction in transactions {
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        switch transaction.transactionState {
        case .purchased:
            SKPaymentQueue.default().finishTransaction(transaction)
            print(".purchased")
        case .failed:
            SKPaymentQueue.default().finishTransaction(transaction)
            print(".failed")
        case .restored:
            SKPaymentQueue.default().finishTransaction(transaction)
            print(".restored")
        default:
            break
        }
    }
}

@IBAction func restore(_ sender: UIBarButtonItem) {
    SKPaymentQueue.default().restoreCompletedTransactions()
}

func subscribe() {
    if SKPaymentQueue.canMakePayments() {
        let payment = SKPayment(product: availableProducts[indexPath.row])
        SKPaymentQueue.default().add(payment)
    }
}

override func viewDidLoad() {
    super.viewDidLoad()

    SKPaymentQueue.default().add(self)
}
Daniel García Baena
  • 1,191
  • 4
  • 19
  • 33

3 Answers3

0

Probably,it's always .restored, because the transaction is not finished.


Usually we put SKPaymentQueue.default().add(observer) in AppDelegate,

so that the transaction will always get handled.

 class AppDelegate{

      func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
            SKPaymentQueue.default().add(self)
      }

}

extension AppDelegate: SKPaymentTransactionObserver {

      func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
            // ...
      }
}

When u put SKPaymentQueue.default().add(observer) in ViewController, since ViewController maybe get pushed and popped.

That is to say , the ViewController instance get allocated and deallocated .

Since the transaction handling is asynchronous, the ViewController instance corresponding to its transaction, maybe not existed, or not the same one.

So it behaves wieldly.

dengApro
  • 3,848
  • 2
  • 27
  • 41
  • I can see your point but I waited for several minutes (just for testing) and it doesn't seem to "be able to finish" the transaction – Daniel García Baena May 12 '20 at 11:17
  • I found this and it solves my problem: https://stackoverflow.com/a/36091267/488019 Should I permanently include something like that in my `didFinishLaunchingWithOptions ` to avoid it from happening again? – Daniel García Baena May 12 '20 at 11:37
0

I found here: Clearing SKPAymentsQueue : Forcing Unfinished Transactions To Finish that my problem was that I had some unfinished pending transactions so I added this into my viewDidLoad to "force" finishing them all. Should I permanently include it to avoid it from happening again?

let currentQueue: SKPaymentQueue = SKPaymentQueue.default();
for transaction in currentQueue.transactions {
    currentQueue.finishTransaction(transaction);
}
Daniel García Baena
  • 1,191
  • 4
  • 19
  • 33
0

You should check result of queue

let transactions = queue.transactions
    if transactions.count > 0 {
        for transaction in queue.transactions {
            if (transaction.transactionState == SKPaymentTransactionState.failed) {
                //possibly handle the error
                purchaseStatusBlock?(.failed)
            } else if (transaction.transactionState == SKPaymentTransactionState.purchased) {
                //deliver the content to the user
                purchaseStatusBlock?(.purchased)
            } else if (transaction.transactionState == SKPaymentTransactionState.restored) {
                //deliver the content to the user
                purchaseStatusBlock?(.restored)
            } else {
                //handle other transaction states
            }
        }
    } else {
        purchaseStatusBlock?(.failed)
    }
Emre Gürses
  • 1,992
  • 1
  • 23
  • 28