My app has in-app purchase built in (I followed this tutorial), the purchase functionality works. However, when I redeem the promo code in App Store for one of the in-app purchase products, my app doesn't response to it. Even the App Store says the product has been successfully redeemed, my app doesn't response to it.
Has anyone who has in-app purchase tested if your app can process the promo code? Would you mind share the solution?
I started with this:
override func viewDidLoad() {
NotificationCenter.default.addObserver(self,
selector: #selector(applicationDidBecomeActive(notification:)),
name: NSNotification.Name.UIApplicationDidBecomeActive,
object: nil
)
}
func applicationDidBecomeActive(notification: NSNotification){
let store = IAPHealper()
//what needs to be put here?
}
extension IAPHelper: SKPaymentTransactionObserver {
public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch (transaction.transactionState) {
case .purchased:
completeTransaction(transaction)
break
case .failed:
failedTransaction(transaction)
break
case .restored:
restoreTransaction(transaction)
break
case .deferred:
break
case .purchasing:
break
}
}
}
fileprivate func completeTransaction(_ transaction: SKPaymentTransaction) {
print("completeTransaction...")
deliverPurchaseNotificatioForIdentifier(transaction.payment.productIdentifier)
defaultQueue.finishTransaction(transaction)
purchaseCompletionHandler?(true, transaction)
}
fileprivate func restoreTransaction(_ transaction: SKPaymentTransaction) {
guard let productIdentifier = transaction.original?.payment.productIdentifier else { return }
print("restoreTransaction... \(productIdentifier)")
deliverPurchaseNotificatioForIdentifier(productIdentifier)
defaultQueue.finishTransaction(transaction)
}
fileprivate func failedTransaction(_ transaction: SKPaymentTransaction) {
print("failedTransaction...")
if transaction.error!._code != SKError.paymentCancelled.rawValue {
print("Transaction Error: \(String(describing: transaction.error?.localizedDescription))")
purchaseCompletionHandler?(false, transaction)
}
defaultQueue.finishTransaction(transaction)
}
fileprivate func deliverPurchaseNotificatioForIdentifier(_ identifier: String?) {
guard let identifier = identifier else { return }
purchasedProductIdentifiers.insert(identifier)
//NSNotificationCenter.defaultCenter().postNotificationName(IAPHelper.IAPHelperPurchaseNotification, object: identifier)
}
public func paymentQueue(_ queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction]){
print("Removed from queue.")
print(transactions)
}
}
Thanks.
@Eatton provided very helpful information on the other thread. I just want to summarize the solution to handling redemption of Promo Code for consumable products.
I. You should use SwiftyStoreKit, and put this code in AppDelegate:
SwiftyStoreKit.completeTransactions(atomically: true) { purchases in
for purchase in purchases {
switch purchase.transaction.transactionState {
case .purchased, .restored:
if purchase.needsFinishTransaction {
SwiftyStoreKit.finishTransaction(purchase.transaction)
}
// Unlock content
self.unlockIAPContent(productID: purchase.productId)
case .failed, .purchasing, .deferred:
break // do nothing
}
}
}
II. If you want to call the logic in the any ViewController, please consider to use NotificationCenter, put the code under //Unlock content
III. How to test it?
In iOS 11 release, Apple introduced a new feature for promoting your in-app purchase directly in App Store.
First add the handler:
#if DEBUG
SwiftyStoreKit.shouldAddStorePaymentHandler = { payment, product in
return true
}
#endif
Then compose the following URL on your Mac and AirDrop it over to your iOS device and open it in Safari.
itms-services://?action=purchaseIntent&bundleId=com.example.app&productIdentifier=product_name
Then the completion block of SwiftyStoreKit.completeTransactions()
in your AppDelegate
will be triggered.
This can also be used for testing Promo Code redemption since the URL request creates a pending transaction and adds it to the queue. Make sure you remove this code for your prod release.
Hope this helps!