Search code examples
iosswifttransactionsin-app-purchase

Adding & Removing Transaction Queue Observer - The Correct Way?


With reference to In app Purchases ... I refer to this Technical Note: https://developer.apple.com/library/ios/technotes/tn2387/_index.html

It states that we should add the transaction observer in didFinishLaunchingWithOptions in the AppDelegate file. And that we should remove the transaction observer in the applicationWillTerminate of the AppDelegate.

This is not in keeping with many tutorials that I have read (quite current ones) and also at odds with many threads on the matter (also recent).

I am confused. Apple is obviously 'king of the heap'. So I should adopt the technical note's direction and add the transaction queue observer in didFinishLaunchingWithOptions and remove it at applicationWillTerminate?

Can someone please clarify this a little more?


Solution

  • You ask:

    It states that we should add the transaction observer in didFinishLaunchingWithOptions in the AppDelegate file. And that we should remove the transaction observer in the applicationWillTerminate of the AppDelegate.

    This is not in keeping with many tutorials that I have read ...

    No, there's nothing wrong with adding it this way. As the technical note says, "Adding your app's observer at launch ensures that it will persist during all launches of your app, thus allowing your app to receive all the payment queue notifications."

    If there's some reference that you have that advises against that practice, please edit your question and share the specific reference with us and we can comment specifically on that link.

    In a comment, you later asked:

    I will have to include all the relevant delegate methods in the AppDelegate also?

    There are a few options. For example, you could instantiate a dedicated object for this. Thus:

    let paymentTransactionObserver = PaymentTransactionObserver()
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        SKPaymentQueue.default().add(paymentTransactionObserver)
    
        return true
    }
    
    func applicationWillTerminate(_ application: UIApplication) {
        SKPaymentQueue.default().remove(paymentTransactionObserver)
    }
    

    Where:

    class PaymentTransactionObserver: NSObject, SKPaymentTransactionObserver {
        
        func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { ... }
        
        func paymentQueue(_ queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction]) { ... }
        
        func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) { ... }
        
        func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) { ... }
        
        func paymentQueue(_ queue: SKPaymentQueue, updatedDownloads downloads: [SKDownload]) { ... }
        
    }
    

    Or, alternatively, you could add it directly to your AppDelegate, too, (as outlined in Setting Up the Transaction Observer for the Payment Queue). but if you do so, you might want add protocol conformance with an extension, to keep those relevant methods cleanly grouped together, e.g.:

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        SKPaymentQueue.default().addTransactionObserver(self)
    
        return true
    }
    
    func applicationWillTerminate(_ application: UIApplication) {
        SKPaymentQueue.default().remove(self)
    }
    

    And

    extension AppDelegate: SKPaymentTransactionObserver {
        
        // the `SKPaymentTransactionObserver` methods here
        
    }
    

    See previous revision of this answer for Swift 2 rendition.