Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

App doesn't handle redemption of in-app purchase promo code of consumable products

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.

like image 464
zs2020 Avatar asked Jun 02 '17 20:06

zs2020


People also ask

How do I redeem an in app purchase code?

In the Play store: The user can manually enter the code in the Google Play Store by clicking the Play Store left navigation menu and tapping Redeem Code.

Why does it say my promo code is invalid?

This message means that the code has either expired or has been entered incorrectly.

Does App Store use promo codes?

Accepted Reply. On your phone, open App Store, then tap on the center icon at the bottom named 'Apps'. Scroll down. tap on 'Redeem', then tap on 'You can also redeem your code manually'.

How many promo codes can you give away for each of your in app purchases?

Set Up Offer Codes You can have up to 10 active offers per subscripton, and create a maximum of 150,000 codes per app, per quarter.


1 Answers

Other than what Andrew says (about promo codes only working for production environments) it seems you might have an issue regarding your "App Purchases" Handling mechanisms.

You should have your purchases handling object initialized in the AppDelegate, so that it immediately receives the pending purchases and just created purchases, (or in this case when a code is redeemed)

If you check the examples shown here:

https://developer.apple.com/library/content/technotes/tn2387/_index.html#//apple_ref/doc/uid/DTS40014795-CH1-BEST_PRACTICES-ADD_A_TRANSACTION_QUEUE_OBSERVER_AT_APPLICATION_LAUNCH

You are actually doing what is NOT recommended by apple.

Instead add the StoreKit observer INSIDE your AppDelegate:

class AppDelegate: UIResponder, UIApplicationDelegate {
                           ....
    // Attach an observer to the payment queue.
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Attach an observer to the payment queue.
        SKPaymentQueue.default().add(your_observer)
        return true
    }

    // Called when the application is about to terminate.
    func applicationWillTerminate(_ application: UIApplication) {
       // Remove the observer.
       SKPaymentQueue.default().remove(your_observer)
    }

    // OTHER STUFF...

}

You might actually be missing on the timing your app receives the purchases because of this.

By the way, you already have an "In App Purchases" helper object (IAPHealper). All you need to do is, make your AppDelegate store a variable to it, and instantiate it inside the "didFinishLaunchingWithOptions" method.

Something like:

class AppDelegate: UIResponder, UIApplicationDelegate {

    var store : IAPHealper;
                           ....
    // Attach an observer to the payment queue.
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        store = IAPHelper();

        return true
    }

    // OTHER STUFF...

}

EDIT: (To keep all the info here on stack overflow)

According to an Apple's Employee response: https://forums.developer.apple.com/message/204476#204476

Promo codes can only be tested in the production store.

So, in order to test them:

  1. Submit your app for App Review.
  2. Set the release date of the App sometime in the future so that once App Review approves the app, it's not available to the general user.
  3. Use an app promo code to install the app
  4. Use the in app promo code.

And finally, the developer's post also warns us that, after an App has been approved you have to wait 48 hours before the codes start working.


So if after following the steps described above, your app is not behaving as expected. Then the problem you are facing is your app not being "ready" when apple sends you the "purchase successful" notification. Hence why you should follow the guideline described on the first part of this answer. (About initializing your transaction listener as soon as your app is launched)

like image 53
Pochi Avatar answered Oct 01 '22 22:10

Pochi