I have two auto-renewing subscriptions, monthly and yearly (iOS). I can make a purchase when I use a new fresh sandbox user. Although I have to enter my password three times. Here's the flow:
- Tap on a subscription
- Enter Password
- Promted to enter password again
- get "cannot connect to iTunes Store" error
- try again and enter password
- purchase succeeds.
Moving on, so once it succeeds, I'm now subscribed and my UI is updated via a listener in appDelegate which posts a notification that I subscribe to. But when I try to switch subscriptions, from monthly to yearly, or vice versa, it always gives me the "Cannot connect to iTunes Store" error. No UI updates. Here's the flow:
- Tap on the other subscription
- Prompted to enter iTunes password
- Receive the "confirm purchase" dialog which states I'm modifying my subscription
- Tap continue
- Receive the "You're all set" success alert.
- Dismiss alert
- Receive "Cannot connect to iTunes Store" error
- My listener wasn't called, UI wasn't updated, etc.
But then if I dismiss the error and tap the subscription again, I get an alert that says I'm already subscribed to that plan, even though the error was thrown and my listener didn't pick up the change.
I'm using firebase. I followed the quickstart and the Firebase specific instructions in the RevenueCat docs. All of my debug logs seem to be fine, no non-200 statuses, no invalid product Ids. Here are some code snippets:
AppDelegate:
Purchases.debugLogsEnabled = true
Purchases.configure(withAPIKey: Constants.revenueCatKey)
Purchases.shared.delegate = self
FirebaseApp.configure()
authHandle = Auth.auth().addStateDidChangeListener() { (auth, user) in
if let uid = user?.uid {
Purchases.shared.identify(uid, { (info, error) in
if let e = error {
print("sign in error: \(e.localizedDescription)")
} else {
print("User \(uid) signed in")
}
})
}
...
}
}
extension AppDelegate: PurchasesDelegate {
func purchases(_ purchases: Purchases, didReceiveUpdated purchaserInfo: PurchaserInfo) {
if self.currentUser != nil {
if purchaserInfo.activeSubscriptions.contains(Constants.audiomeshSubscriptions.monthly) {
guard let myRef = DataService.instance.REF_PRIVATE else { return }
myRef.updateData(["plan" : "paidMonthly"]) { err in
if let err = err {
print("error updating user-private with new subscription: \(err)")
} else {
NotificationCenter.default.post(name: Notification.Name(rawValue: "purchaserInfoUpdated"), object: nil)
}
}
}
else if purchaserInfo.activeSubscriptions.contains(Constants.audiomeshSubscriptions.yearly) {
//do the same for yearly subscription
}
else {
//handle non-paying users here
}
}
}
}
UpgradeController (the purchasing UI):
@objc func purchaseButtonSelected(sender: AudiomeshButton) {
let buttonTag = sender.tag
guard let option = options?[buttonTag] else { return }
let product:SKProduct = option.product
Purchases.shared.makePurchase(product, { (transaction, purchaserInfo, error) in
if let error = error {
print("error making purchase: \(error)")
} else {
print("Purchase Successful")
}
})
}