0

I have a RevenueCat implementation that is working but I don't like the flow and am struggling with improving it. I know there has to be a more refined way to do this, so any help would be appreciated:

@IBAction func btnMnthlyPressed(_ sender: Any) {
    Purchases.shared.offerings { (offerings, error) in
        if let e = error {
            print(e.localizedDescription)
        }
        
        guard let offering = offerings?.current else {
            print("No current offering configured")
            return
        }
        
        for package in offering.availablePackages {
            print(package.identifier)
            if package.identifier == "$rc_monthly" {
                Purchases.shared.purchasePackage(package) { (transaction, info, error, cancelled) in
                    if cancelled {
                        print("User cancelled purchase")
                        return
                    }
                    // Optionally handle specific purchase errors
                     if info?.entitlements.all["FullAccess"]?.isActive == true {
                        print("Unlocked Pro Cats ")
                    }
                }
            }
            print("Product: \(package.product.localizedDescription), price: \(package.localizedPriceString)")
        }
    }
}

Maybe I'm trying to do too much in the func...

Douglas W. Palme
  • 390
  • 1
  • 4
  • 10

1 Answers1

1

Taking the first monthly package is probably better than a for loop since you don't want to ever initiate two purchase calls on the same button press.

@IBAction func btnMnthlyPressed(_ sender: Any) {
    Purchases.shared.offerings { (offerings, error) in
        if let e = error {
            print(e.localizedDescription)
        }
        
        guard let offering = offerings?.current else {
            print("No current offering configured")
            return
        }
        
        guard let package = offering.availablePackages.first(where: { $0.packageType == .monthly }) else {
            print("No monthly package type")
            return
        }
        
        Purchases.shared.purchasePackage(package) { (transaction, info, error, cancelled) in
            if cancelled {
                print("User cancelled purchase")
                return
            }
            // Optionally handle specific purchase errors
             if info?.entitlements.all["FullAccess"]?.isActive == true {
                print("Unlocked Pro Cats ")
            }
        }
    }
}

That said, you may want to get all the packages when the view is loaded to make sure they exist before the user tries to tap the buy button.

enc_life
  • 4,973
  • 1
  • 15
  • 27
  • +1 on getting all of the packages before the button is pressed. You should try to make the purchase button as quick to respond as possible by minimizing the number of async requests made. If you had already requested offerings at this point, they'll be in cache, but the other reason that getting all packages beforehand will be an improvement is that it'll clean up potentially duplicated code in your buttons - just get all packages beforehand, store them somewhere and your button action code will be something like ```Purchases.shared.purchasePackage(monthlyPackage) { ...``` – aboedo Aug 04 '20 at 13:25
  • I thought of that, but haven't been able to figure out a way to get them store and accessible. – Douglas W. Palme Aug 04 '20 at 14:08
  • Thanks enc_life for the help, that does make it much simpler. – Douglas W. Palme Aug 04 '20 at 14:09