From ffa8bad65a35a69b6981cbc39aea6ae4d772eed0 Mon Sep 17 00:00:00 2001 From: NachoSoto Date: Fri, 19 Jan 2024 13:54:47 -0800 Subject: [PATCH] `Paywalls`: add methods for presenting paywalls with an offering identifier Depends on https://github.com/RevenueCat/purchases-ios/pull/3587. --- .../ObjCAPITester/RCPaywallProxyAPITest.m | 18 +++ .../PurchasesHybridCommon/PaywallProxy.swift | 143 ++++++++++++------ 2 files changed, 112 insertions(+), 49 deletions(-) diff --git a/ios/PurchasesHybridCommon/ObjCAPITester/RCPaywallProxyAPITest.m b/ios/PurchasesHybridCommon/ObjCAPITester/RCPaywallProxyAPITest.m index 38f5dba2f..3443b52da 100644 --- a/ios/PurchasesHybridCommon/ObjCAPITester/RCPaywallProxyAPITest.m +++ b/ios/PurchasesHybridCommon/ObjCAPITester/RCPaywallProxyAPITest.m @@ -8,6 +8,8 @@ #import @import PurchasesHybridCommon; +@import RevenueCat; +@import UIKit; NS_ASSUME_NONNULL_BEGIN @@ -19,11 +21,18 @@ @implementation RCPaywallProxyAPITest - (void)testAPI { if (@available(iOS 15.0, *)) { + RCOffering *offering; + PaywallProxy *proxy = [PaywallProxy new]; [proxy presentPaywall]; [proxy presentPaywallWithDisplayCloseButton:true]; [proxy presentPaywallWithPaywallResultHandler:^(NSString *result) {}]; [proxy presentPaywallWithDisplayCloseButton:true paywallResultHandler:^(NSString *result) {}]; + [proxy presentPaywallWithOffering:offering displayCloseButton:true paywallResultHandler:^(NSString *result) {}]; + [proxy presentPaywallWithOfferingIdentifier:@"offering" + displayCloseButton:true + paywallResultHandler:^(NSString *result) {}]; + [proxy presentPaywallIfNeededWithRequiredEntitlementIdentifier:@""]; [proxy presentPaywallIfNeededWithRequiredEntitlementIdentifier:@"" displayCloseButton:YES]; [proxy presentPaywallIfNeededWithRequiredEntitlementIdentifier:@"" @@ -31,6 +40,15 @@ - (void)testAPI { [proxy presentPaywallIfNeededWithRequiredEntitlementIdentifier:@"" displayCloseButton:true paywallResultHandler:^(NSString *result) {}]; + [proxy presentPaywallIfNeededWithRequiredEntitlementIdentifier:@"" + offeringIdentifier:@"offering" + displayCloseButton:true + paywallResultHandler:^(NSString *result) {}]; + + __unused UIViewController *view1 = [proxy createPaywallView]; + __unused UIViewController *view2 = [proxy createPaywallViewWithOfferingIdentifier:@"offering"]; + __unused UIViewController *footer1 = [proxy createFooterPaywallView]; + __unused UIViewController *footer2 = [proxy createFooterPaywallViewWithOfferingIdentifier:@"offering"]; } } diff --git a/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift b/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift index 5880e2154..0428b7590 100644 --- a/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift +++ b/ios/PurchasesHybridCommon/PurchasesHybridCommon/PaywallProxy.swift @@ -25,7 +25,12 @@ import UIKit @objc public func createPaywallView() -> UIViewController { - return UIHostingController(rootView: PaywallView()) + return PaywallViewController() + } + + @objc + public func createPaywallView(offeringIdentifier: String) -> UIViewController { + return PaywallViewController(offeringIdentifier: offeringIdentifier) } @objc @@ -36,46 +41,28 @@ import UIKit return controller } - @available(*, deprecated, message: "Use presentPaywall with paywallResultHandler instead") - @objc - public func presentPaywall() { - self.privatePresentPaywall(displayCloseButton: nil, offering: nil) - } - - @available(*, deprecated, message: "Use presentPaywall with paywallResultHandler instead") - @objc - public func presentPaywall(displayCloseButton: Bool) { - self.privatePresentPaywall(displayCloseButton: displayCloseButton, offering: nil) - } - - @available(*, deprecated, message: "Use presentPaywall with paywallResultHandler instead") @objc - public func presentPaywall(offering: Offering) { - self.privatePresentPaywall(displayCloseButton: nil, offering: offering) - } + public func createFooterPaywallView(offeringIdentifier: String) -> UIViewController { + let controller = PaywallFooterViewController(offeringIdentifier: offeringIdentifier) + controller.delegate = self - @available(*, deprecated, message: "Use presentPaywall with paywallResultHandler instead") - @objc - public func presentPaywall(offering: Offering, displayCloseButton: Bool) { - self.privatePresentPaywall(displayCloseButton: displayCloseButton, offering: offering) + return controller } @objc public func presentPaywall(paywallResultHandler: @escaping (String) -> Void) { - self.privatePresentPaywall(displayCloseButton: nil, offering: nil, paywallResultHandler: paywallResultHandler) + self.privatePresentPaywall(paywallResultHandler: paywallResultHandler) } @objc public func presentPaywall(displayCloseButton: Bool, paywallResultHandler: @escaping (String) -> Void) { self.privatePresentPaywall(displayCloseButton: displayCloseButton, - offering: nil, paywallResultHandler: paywallResultHandler) } @objc public func presentPaywall(offering: Offering, paywallResultHandler: @escaping (String) -> Void) { - self.privatePresentPaywall(displayCloseButton: nil, - offering: offering, + self.privatePresentPaywall(content: .offering(offering), paywallResultHandler: paywallResultHandler) } @@ -84,51 +71,49 @@ import UIKit displayCloseButton: Bool, paywallResultHandler: @escaping (String) -> Void) { self.privatePresentPaywall(displayCloseButton: displayCloseButton, - offering: offering, + content: .offering(offering), paywallResultHandler: paywallResultHandler) } - @available(*, deprecated, message: "Use presentPaywallIfNeeded with paywallResultHandler instead") @objc - public func presentPaywallIfNeeded(requiredEntitlementIdentifier: String) { - self.privatePresentPaywallIfNeeded(requiredEntitlementIdentifier: requiredEntitlementIdentifier, - displayCloseButton: nil, - offering: nil, - paywallResultHandler: nil) + public func presentPaywall(offeringIdentifier: String, + displayCloseButton: Bool, + paywallResultHandler: @escaping (String) -> Void) { + self.privatePresentPaywall(displayCloseButton: displayCloseButton, + content: .offeringIdentifier(offeringIdentifier), + paywallResultHandler: paywallResultHandler) } - @available(*, deprecated, message: "Use presentPaywallIfNeeded with paywallResultHandler instead") @objc - public func presentPaywallIfNeeded(requiredEntitlementIdentifier: String, - displayCloseButton: Bool) { + public func presentPaywallIfNeeded(requiredEntitlementIdentifier: String, + paywallResultHandler: @escaping (String) -> Void) { self.privatePresentPaywallIfNeeded(requiredEntitlementIdentifier: requiredEntitlementIdentifier, - displayCloseButton: displayCloseButton, - offering: nil, - paywallResultHandler: nil) + paywallResultHandler: paywallResultHandler) } @objc public func presentPaywallIfNeeded(requiredEntitlementIdentifier: String, + displayCloseButton: Bool, paywallResultHandler: @escaping (String) -> Void) { self.privatePresentPaywallIfNeeded(requiredEntitlementIdentifier: requiredEntitlementIdentifier, - displayCloseButton: nil, - offering: nil, + displayCloseButton: displayCloseButton, paywallResultHandler: paywallResultHandler) } @objc public func presentPaywallIfNeeded(requiredEntitlementIdentifier: String, + offeringIdentifier: String, displayCloseButton: Bool, paywallResultHandler: @escaping (String) -> Void) { self.privatePresentPaywallIfNeeded(requiredEntitlementIdentifier: requiredEntitlementIdentifier, displayCloseButton: displayCloseButton, - offering: nil, + content: .offeringIdentifier(offeringIdentifier), paywallResultHandler: paywallResultHandler) } private func privatePresentPaywallIfNeeded(requiredEntitlementIdentifier: String, - displayCloseButton: Bool?, - offering: Offering?, + displayCloseButton: Bool = false, + content: Content = .defaultOffering, paywallResultHandler: ((String) -> Void)? = nil) { _ = Task { @MainActor in do { @@ -136,7 +121,7 @@ import UIKit let shouldDisplay = !customerInfo.entitlements.active.keys.contains(requiredEntitlementIdentifier) if shouldDisplay { self.privatePresentPaywall(displayCloseButton: displayCloseButton, - offering: offering, + content: content, paywallResultHandler: paywallResultHandler) } else { paywallResultHandler?(PaywallResult.notPresented.name) @@ -147,8 +132,8 @@ import UIKit } } - private func privatePresentPaywall(displayCloseButton: Bool?, - offering: Offering?, + private func privatePresentPaywall(displayCloseButton: Bool = false, + content: Content = .defaultOffering, paywallResultHandler: ((String) -> Void)? = nil) { guard let rootController = Self.rootViewController else { NSLog("Unable to find root UIViewController") @@ -156,17 +141,22 @@ import UIKit } let controller: PaywallViewController - if let displayCloseButton = displayCloseButton { + switch content { + case let .offering(offering): controller = PaywallViewController(offering: offering, displayCloseButton: displayCloseButton) - } else { - controller = PaywallViewController() + case let .offeringIdentifier(identifier): + controller = PaywallViewController(offeringIdentifier: identifier, displayCloseButton: displayCloseButton) + case .defaultOffering: + controller = PaywallViewController(displayCloseButton: displayCloseButton) } controller.delegate = self controller.modalPresentationStyle = .pageSheet + if let paywallResultHandler { self.resultByVC[controller] = (paywallResultHandler, .cancelled) } + rootController.present(controller, animated: true) } @@ -180,6 +170,14 @@ import UIKit return windowScene.windows.first?.rootViewController } + private enum Content { + + case offering(Offering) + case offeringIdentifier(String) + case defaultOffering + + } + } @available(iOS 15.0, *) @@ -216,4 +214,51 @@ extension PaywallProxy: PaywallViewControllerDelegate { } +// MARK: - Deprecations + +@available(iOS 15.0, *) +extension PaywallProxy { + + @available(*, deprecated, message: "Use presentPaywall with paywallResultHandler instead") + @objc + public func presentPaywall() { + self.privatePresentPaywall() + } + + @available(*, deprecated, message: "Use presentPaywall with paywallResultHandler instead") + @objc + public func presentPaywall(displayCloseButton: Bool) { + self.privatePresentPaywall(displayCloseButton: displayCloseButton) + } + + @available(*, deprecated, message: "Use presentPaywall with paywallResultHandler instead") + @objc + public func presentPaywall(offering: Offering) { + self.privatePresentPaywall(content: .offering(offering)) + } + + @available(*, deprecated, message: "Use presentPaywall with paywallResultHandler instead") + @objc + public func presentPaywall(offering: Offering, displayCloseButton: Bool) { + self.privatePresentPaywall(displayCloseButton: displayCloseButton, content: .offering(offering)) + } + + @available(*, deprecated, message: "Use presentPaywallIfNeeded with paywallResultHandler instead") + @objc + public func presentPaywallIfNeeded(requiredEntitlementIdentifier: String) { + self.privatePresentPaywallIfNeeded(requiredEntitlementIdentifier: requiredEntitlementIdentifier, + paywallResultHandler: nil) + } + + @available(*, deprecated, message: "Use presentPaywallIfNeeded with paywallResultHandler instead") + @objc + public func presentPaywallIfNeeded(requiredEntitlementIdentifier: String, + displayCloseButton: Bool) { + self.privatePresentPaywallIfNeeded(requiredEntitlementIdentifier: requiredEntitlementIdentifier, + displayCloseButton: displayCloseButton, + paywallResultHandler: nil) + } + +} + #endif