SwiftyStoreKit
SwiftyStoreKit copied to clipboard
Closure inside SwiftyStoreKit.completeTransactions(atomically: true) { ... } never gets reached
Platform
iOS 13.1 and 13.2
In app purchase type
- [ ] Consumable
Environment
- [ ] Sandbox
Version
SwiftyStoreKit (0.15.0) // installation: pod 'SwiftyStoreKit'
Related issues
https://github.com/bizz84/SwiftyStoreKit/issues/432
https://stackoverflow.com/a/53162058/4833705
https://stackoverflow.com/q/53841379/4833705
Issue summary
the closure
inside SwiftyStoreKit.completeTransactions(atomically: true) { ... }
never gets reached
What did you expect to happen
I expected the closure to get entered
What happened instead
the closure was ever entered
Report
My app uses a tip jar for IAP so I only use Consumable.
I submitted my app to the App Store this morning and got a rejection saying they couldn't make an IAP when trying to make a Consumable purchase (a tip).
While testing as a sandbox tester when I checked the purchase I kept getting an error: "Unknown error. Please contact support":
SwiftyStoreKit.purchaseProduct(product, quantity: 1, atomically: true) { result in
switch result {
case .success(let product):
// fetch content from your server, then:
if product.needsFinishTransaction {
SwiftyStoreKit.finishTransaction(product.transaction)
}
print("Purchase Success: \(product.productId)")
case .error(let error):
switch error.code {
case .unknown:
print("Unknown error. Please contact support")
// failed cases ...
}
}
Upon further inspection even though I had this code below in AppDelegate
the closure never gets called.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Doesn't enter closure
SwiftyStoreKit.completeTransactions(atomically: true) {
// *** it never reaches this point ***
(purchases) in
for purchase in purchases {
switch purchase.transaction.transactionState {
case .purchased, .restored:
if purchase.needsFinishTransaction {
// Deliver content from server, then:
let downloads = purchase.transaction.downloads
SKPaymentQueue.default().start(downloads)
SwiftyStoreKit.finishTransaction(purchase.transaction)
}
// Unlock content
case .failed, .purchasing, .deferred:
break // do nothing
}
}
}
return true
}
My sandbox tester email is confirmed, I signed out of the device as my real self, I logged in on the device as the sandbox tester, I'm logged into iCloud as the sandbox tester.
What could be the reason for the closure not being entered in AppDelegate?
Here's the code from the vc that I use to make the Consumable purchase:
var dataSource = [Tip]()
var sharedSecret = appStoreConnectSecretKey
let inAppProductIds = ["com.myCo.myAppName.firstTip", // 0.99
"com.myCo.myAppName.secondTip", // 9.99 ]
override func viewDidLoad() {
super.viewDidLoad()
getInAppPurchaseAmounts()
}
func getInAppPurchaseAmounts() {
// show spinner
let dispatchGroup = DispatchGroup()
for productId in inAppProductIds {
dispatchGroup.enter()
SwiftyStoreKit.retrieveProductsInfo([productId]) { [weak self](result) in
if let product = result.retrievedProducts.first {
let priceString = product.localizedPrice!
print("Product: \(product.localizedDescription), price: \(priceString)")
let tip = Tip(displayName: product.description,
description: product.localizedDescription,
productId: productId
price: priceString)
self?.addTipToDataSource(tip)
if let sharedSecret = self?.sharedSecret {
self?.verifyPurchase(with: productId, sharedSecret: sharedSecret)
}
dispatchGroup.leave()
} else if let invalidProductId = result.invalidProductIDs.first {
print("Invalid product identifier: \(invalidProductId)")
dispatchGroup.leave()
} else {
print("Error: \(String(describing: result.error))")
dispatchGroup.leave()
}
}
}
dispatchGroup.notify(queue: .global(qos: .background)) { [weak self] in
DispatchQueue.main.async { [weak self] in
// removeSpinnerAndReloadData()
}
}
}
func verifyPurchase(with productId: String, sharedSecret: String) {
let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: sharedSecret)
SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in
switch result {
case .success(let receipt):
let productId = productId
// Verify the purchase of Consumable or NonConsumable
let purchaseResult = SwiftyStoreKit.verifyPurchase(
productId: productId,
inReceipt: receipt)
switch purchaseResult {
case .purchased(let receiptItem):
print("\(productId) is purchased: \(receiptItem)")
case .notPurchased:
print("The user has never purchased \(productId)")
}
case .error(let error):
print("Receipt verification failed: \(error)")
}
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) as? TipCell else { return }
guard let indexPath = collectionView.indexPath(for: cell) else { return }
let tip = dataSource[indexPath.item]
purchaseProduct(with: tip.productId)
}
func purchaseProduct(with productId: String) {
SwiftyStoreKit.retrieveProductsInfo([productId]) { result in
if let product = result.retrievedProducts.first {
SwiftyStoreKit.purchaseProduct(product, quantity: 1, atomically: true) { result in
switch result {
case .success(let product):
// fetch content from your server, then:
if product.needsFinishTransaction {
SwiftyStoreKit.finishTransaction(product.transaction)
}
print("Purchase Success: \(product.productId)")
case .error(let error):
switch error.code {
case .unknown:
print("Unknown error. Please contact support")
case .clientInvalid:
print("Not allowed to make the payment")
case .paymentCancelled:
print("Payment cancelled")
case .paymentInvalid:
print("The purchase identifier was invalid")
case .paymentNotAllowed:
print("The device is not allowed to make the payment")
case .storeProductNotAvailable:
print("The product is not available in the current storefront")
case .cloudServicePermissionDenied:
print("Access to cloud service information is not allowed")
case .cloudServiceNetworkConnectionFailed:
print("Could not connect to the network")
case .cloudServiceRevoked:
print("User has revoked permission to use this cloud service")
default:
print((error as NSError).localizedDescription)
}
}
}
}
}
}
Did you solve this issue?
I resolved the unknown error issue (another issue was causing it) but til this day the closure in app delegate still never gets reached. I just tried 5 minutes ago and nothing.
I resolved the unknown error issue (another issue was causing it) but til this day the closure in app delegate still never gets reached. I just tried 5 minutes ago and nothing.
What was the other issue causing the unknown error message?
I resolved the unknown error issue (another issue was causing it) but til this day the closure in app delegate still never gets reached. I just tried 5 minutes ago and nothing.
Can you please explain how did you solve unknown error issue?
@sureshdistill It was so long ago I dont remember but from what I can tell by the comment that I made the unknown error issue was caused by something else