SwiftyStoreKit icon indicating copy to clipboard operation
SwiftyStoreKit copied to clipboard

InAppReceiptRefreshRequest's refreshReceiptRequest not call requestDidFinish or didFailWithError

Open zhihanhe opened this issue 5 years ago • 2 comments

Platform

  • [x ] iOS
  • [ ] macOS
  • [ ] tvOS

In app purchase type

  • [x ] Consumable
  • [ ] Non-consumable
  • [ x] Auto-Renewable Subscription
  • [ ] Non-Renewing Subscription

Environment

  • [ x] Sandbox
  • [ x] Production

Version

0.10.7

Related issues

Report

Issue summary

  1. when do a purchase. I use SwiftyStoreKit.verifyReceipt to check whether have unfinished purchase. 2.if no unfinished purchase. I use SwiftyStoreKit.purchaseProduct to buy it.
  2. It's all ok for the first time. But when I do a purchase twice.SwiftyStoreKit.verifyReceipt's callback does not invoke.
  3. I try to debug the reason. I found InAppReceiptRefreshRequest's refreshReceiptRequest not call requestDidFinish or didFailWithError, but self.refreshReceiptRequest.start() invoked.
  4. when I run the app again. It still not work. I have to delete the app. Login out the Apple Account. then I can run the code right at one time. here is the sample code
var serviceType = AppleReceiptValidator.VerifyReceiptURLType.production;
#if DEBUG
  serviceType = AppleReceiptValidator.VerifyReceiptURLType.sandbox;
#endif
let appleValidator = AppleReceiptValidator.init(service: serviceType);
// 没有执行的话,这个回调是不会执行的
// https://stackoverflow.com/questions/30114489/skreceiptrefreshrequest-not-working-the-second-time-it-is-called-after-a-cancel
SwiftyStoreKit.verifyReceipt(using: appleValidator, password: IN_APP_PURCHASE_PASSWORD, forceRefresh: true) { (result:VerifyReceiptResult) in
  switch result {
  case .success(let receiptInfo):
    print(receiptInfo);
    if let status = receiptInfo["status"] as? Int {
      if status == 0 {
        if let latest_receipt = receiptInfo["latest_receipt"] as? String {
          
          // have receipt do other things

        } else {
          
          SwiftyStoreKit.purchaseProduct(productID, quantity: 1, atomically: isAutoRenew) { result in
              switch result {
              case .success(let purchase):
                print(purchase)
              case .error(let error):
                print(error);
              }
          }

        }
      } else {
        print(" (CODE:\(status)")
      }
    } else {
      print(" (CODE:NO_STATUS)")
    }
  case .error(let error):
    print(error);
  }
};

What did you expect to happen

  1. code run well.

What happened instead

  1. code only can run one time.

zhihanhe avatar Jul 17 '18 16:07 zhihanhe

I’m wondering if this is a result of the deinit:

deinit {
    refreshReceiptRequest.delegate = nil
}

So, if InAppReceiptRefreshRequest is deallocated, the delegate is set to nil even if the request is still in progress, and thus neither of the delegate methods will be called. (The delegate is weak, so I don’t know why you need to manually set it to nil, anyway. But whether deinit sets it to nil or whether the weak property takes care of it, that’s not really relevant, as the issue is the same, namely that the delegate can be set to nil before the request is done.)

So, I wonder if there’s a path of execution where the last reference to the InAppReceiptRefreshRequest is getting released before the request finishes.


FWIW, https://stackoverflow.com/q/55294986/1271826 is reporting a similar problem, where the completion handlers are not always getting called, and I suspect it’s a related problem.

robertmryan avatar Aug 01 '19 18:08 robertmryan

I am having the same problem here and NO, problem is not solved by disabling the deinit part.

KatkayApps avatar Nov 17 '20 14:11 KatkayApps