SwiftyStoreKit icon indicating copy to clipboard operation
SwiftyStoreKit copied to clipboard

Fix "Nothing to Restore" even when transactions exist

Open mshibanami opened this issue 3 years ago • 3 comments

Hi,

I got the same problem with #620 on my macOS app. This PR is for fixing that.

Problem details

StoreKit calls the following delegate methods of SwiftyStoreKit's PaymentQueueController when restoring transactions is successful:

  1. paymentQueue(_:, updatedTransactions:)
  2. paymentQueueRestoreCompletedTransactionsFinished(_:)

I confirmed that these methods are called simultaneously on their own different threads. So if there are so many restored transactions, the code in method 1 takes long time and then the delegate method 2 finishes earlier than 1. In other words, the completion of restoring transactions is finished earlier than the code that processes restored transactions.

It seems that SwiftyStoreKit's PaymentQueueController doesn't handle this case correctly and nil is set to restorePurchases property of RestorePurchasesController before finishing the restoration. I think this is the cause.

I'm not sure how many transactions causes this problem. Maybe up to the machine power. This video is when 28 transactions exist:

https://user-images.githubusercontent.com/1333214/121888796-c40f7f00-cd5b-11eb-9fbc-9919112d6222.mov

Probably this happens on other platforms too.

Implementation

I newly defined restorationDispatchQueue in PaymentQueueController so that the code of delegate methods 1 and 2 run on the same thread in order.

This works fine on my Mac as follows:

https://user-images.githubusercontent.com/1333214/121888817-cb368d00-cd5b-11eb-84f4-e3d1045807de.mov

By the way, maybe other delegate methods, such as paymentQueue(_: updatedDownloads:), also need to be run on the same thread but since I'm neither familiar with StoreKit nor this library and I'm not too sure if it unnecessarily impacts other functionalities or not, I leave them as-is. (But please let me know if it actually doesn't impact or my approach is completely wrong.🙂)


Thanks so much for maintaining this great library!

mshibanami avatar Jun 14 '21 12:06 mshibanami

1 Error
:no_entry_sign: Tests were not updated

Generated by :no_entry_sign: Danger

bizz84 avatar Jun 14 '21 12:06 bizz84

Tests were not updated

Sorry I'm not sure how I should write tests in this case but I'm happy to write it if it makes sense.

mshibanami avatar Jun 14 '21 12:06 mshibanami

I noticed that sometimes paymentQueueRestoreCompletedTransactionsFinished(_:) is queued earlier than paymentQueue(_:, updatedTransactions:). It's understandable, since they're called at the same time. Therefore, I added tiny-enough delay (0.1ms) as e5bb4a5.

mshibanami avatar Jul 04 '21 10:07 mshibanami