We're implementing Apple's new "Promoted In-App Purchases" system, allowing users to click a "Buy" button inside Apple's App Store that triggers a purchase of an IAP.
The system calls for the app to implement the SKPaymentTransactionObserver
's paymentQueue:shouldAddStorePayment:forProduct:
delegate method, which returns a boolean. The documentation says,
Return
true
to continue the transaction in your app.Return
false
to defer or cancel the transaction.
If we simply return false
, the user sees our app come to the foreground and then nothing else happens. By default, the OS doesn't pop up a message saying "Purchase canceled" or anything like that; it leaves that decision up to the app developer, I suppose.
The App Store Promoted IAP purchase request can arrive at any time, including when the user is in the middle of a flow that shouldn't be interrupted. It's a perfect case to return false
from this method. When I do that, I'd like to show the user an alert message explaining the problem with UIAlertController
.
The problem is, I have no context view controller to use inside my paymentQueue:shouldAddStorePayment:forProduct:
. Normally, when I want to show an alert from inside a view controller, I'd call [self presentViewController:alert animated:YES completion:nil];
, but self
in this delegate method is a SKPaymentTransactionObserver
, not a view controller, so that won't work.
I'm not even sure that there is a guaranteed active view controller when this delegate method fires. For all I know, the delegate method could fire prior to the applicationDidBecomeActive
event.
What's the best way to show an alert (or any other snippet of UI) when returning false
from paymentQueue:shouldAddStorePayment:forProduct:
?
You can get the application window's root view controller and use that to present the alert.
Objective-C
id *rootController = [[[[UIApplication sharedApplication]delegate] window] rootViewController];
[rootViewController presentViewController:alertController animated:YES completion:nil];
Swift
let appDelegate = UIApplication.sharedApplication().delegate
let viewController = appDelegate.window!.rootViewController
viewController.presentViewController(alertController, animated: true, completion: nil)