From 4b803b7d44645854cd1f611da9fa7072254d2ac1 Mon Sep 17 00:00:00 2001 From: Josh Holtz Date: Wed, 23 Aug 2023 23:49:44 -0500 Subject: [PATCH 1/6] PWL-122: Paywalls footer, fonts, and fixes --- .../paywalls/paywalls_5.swift" | 21 ++----- .../paywalls/paywalls_6.swift" | 32 +++------- .../paywalls/paywalls_7.swift" | 16 +++++ .../paywalls/paywalls_8.swift" | 22 +++++++ .../displaying-products/paywalls.md" | 62 +++++++++++++++---- 5 files changed, 103 insertions(+), 50 deletions(-) create mode 100644 "code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_7.swift" create mode 100644 "code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_8.swift" diff --git "a/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_5.swift" "b/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_5.swift" index 83913c17..9a202ae0 100644 --- "a/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_5.swift" +++ "b/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_5.swift" @@ -3,25 +3,12 @@ import SwiftUI import RevenueCat import RevenueCatUI -struct App: View { +struct YourPaywall: View { var body: some View { - VStack { - ScrollView { - VStack { - // Your custom paywall design content - }.frame(maxWidth: .infinity) - } - - Spacer() - - PaywallView(mode: .condensedCard) // or .card - } - .frame(maxWidth: .infinity, maxHeight: .infinity) - .background( - Color(white: 0.8) - .edgesIgnoringSafeArea(.all) - ) + ScrollView { + // Your custom paywall design content + }.paywallFooter() } } diff --git "a/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_6.swift" "b/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_6.swift" index d1e3b02a..cc59204b 100644 --- "a/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_6.swift" +++ "b/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_6.swift" @@ -1,30 +1,18 @@ -import UIKit +import SwiftUI import RevenueCat import RevenueCatUI -class ViewController: UIViewController { - - override func viewDidLoad() { - super.viewDidLoad() - - let paywallView = PaywallView(mode: .condensedCard) // or .card - paywall.delegate = self - - let hostingController = UIHostingController(rootView: paywallView) - - addChild(hostingController) - view.addSubview(hostingController.view) - hostingController.didMove(toParent: self) - } - -} - -extension ViewController: PaywallViewControllerDelegate { - - func paywallViewController(_ controller: PaywallViewController, - didFinishPurchasingWith customerInfo: CustomerInfo) { +struct YourPaywall: View { + + let offering: Offering + var body: some View { + ScrollView { + // Your custom paywall design content + }.paywallFooter(offering: offering, condensed: true) { customerInfo in + // Purchase completed! Thank your user and dismiss your paywall + } } } diff --git "a/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_7.swift" "b/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_7.swift" new file mode 100644 index 00000000..cfd86e2d --- /dev/null +++ "b/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_7.swift" @@ -0,0 +1,16 @@ +import SwiftUI + +import RevenueCat +import RevenueCatUI + +struct App: View { + var body: some View { + ContentView() + .presentPaywallIfNeeded( + fonts: CustomPaywallFontProvider(fontName: "Arial") + ) { customerInfo in + // Returning `true` will present the paywall + return customerInfo.entitlements.active.keys.contains("pro") + } + } +} diff --git "a/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_8.swift" "b/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_8.swift" new file mode 100644 index 00000000..0bd77b07 --- /dev/null +++ "b/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_8.swift" @@ -0,0 +1,22 @@ +import SwiftUI + +import RevenueCat +import RevenueCatUI + +struct App: View { + var body: some View { + ContentView() + .presentPaywallIfNeeded( + fonts: RoundedSystemFontProvider() + ) { customerInfo in + // Returning `true` will present the paywall + return customerInfo.entitlements.active.keys.contains("pro") + } + } +} + +class RoundedSystemFontProvider: PaywallFontProvider { + func font(for textStyle: Font.TextStyle) -> Font { + return Font.system(textStyle, design: .rounded) + } +} diff --git "a/docs_source/\360\237\232\200 Getting Started/displaying-products/paywalls.md" "b/docs_source/\360\237\232\200 Getting Started/displaying-products/paywalls.md" index 82baa6d4..2a456b86 100644 --- "a/docs_source/\360\237\232\200 Getting Started/displaying-products/paywalls.md" +++ "b/docs_source/\360\237\232\200 Getting Started/displaying-products/paywalls.md" @@ -5,6 +5,10 @@ hidden: true --- RevenueCat's Paywalls allow you to to remotely configure your entire paywall view without any code changes or app updates. Whether you’re building a new app, exploring new paywall concepts, or diving into experimentation; RevenueCat’s Paywalls make it easy to get started. +> ❗️ +> +> Paywalls are only available for iOS 15+ but macOS and Android support are coming soon! + ## How Paywalls work ### Overview @@ -173,18 +177,20 @@ RevenueCat Paywalls will, by default, show paywalls fullscreen and there are mul ] [/block] -## How to embed a Paywall into your views +## How to display a footer Paywall on your custom paywall -RevenueCatUI also has smaller paywalls for you to embed or overlay in your app. You could display these as inline banners in your app, overlay your app as a sheet promoting an upgrade, or as a footer in a custom paywall. +RevenueCatUI also has a paywall variation that can be displayed as a footer below your custom paywall. This allows you to design your paywall exactly as you want with native components while still using RevenueCat UI to handle. This is done by adding the `.paywallFooter()` view modifier to your view. -This can all be done by passing `PaywallViewMode` into `PaywallView`. The options are: -- `PaywallViewMode.fullScreen` -- `PaywallViewMode.card` -- `PaywallViewMode.condensedCard` +The footer paywall mainly consists of: +- Purchase button +- Package details text +- Package selection (if there are any multiple packages configured) + +This is all remotely configured and RevenueCatUI handles all the intro offer eligibility and purchase logic. ### SwiftUI -1. Option 1: `PaywallView` in `UIHostingController` +1. Option 1: Footer paywall with current offering [block:file] [ { @@ -195,9 +201,7 @@ This can all be done by passing `PaywallViewMode` into `PaywallView`. The option ] [/block] -### UIKit - -1. Option 1: `PaywallView` in `UIHostingController` +2. Option 2: Footer paywall with specific offering [block:file] [ { @@ -209,10 +213,46 @@ This can all be done by passing `PaywallViewMode` into `PaywallView`. The option [/block] +## How to use custom fonts + +Paywalls can be configured to use the same font as your app using a `PaywallFontProvider`. A `PaywallFontProvider` can be passed as an argument into all methods for displaying paywall. + +By default, paywalls will use the `DefaultPaywallFontProvider`. This uses the system default font which supports dynamic type. + +### Use `CustomPaywallFontProvider` + +We also offer a `CustomPaywallFontProvider` which requires a font name. This could be something like "Arial" or "Papyrus". + +[block:file] +[ + { + "language": "swift", + "name": "", + "file": "code_blocks/🚀 Getting Started/displaying-products/paywalls/paywalls_7.swift" + } +] +[/block] + +### Use your own `PaywallFontProvider` + +If you need more control for your font preferences, you can create your own `PaywallFontProvider`. + +The following example will use a rounded system font in the paywall. + +[block:file] +[ + { + "language": "swift", + "name": "", + "file": "code_blocks/🚀 Getting Started/displaying-products/paywalls/paywalls_8.swift" + } +] +[/block] + ## Limitations #### Platforms (support for more coming) -* ✅ iOS 16.0 and higher +* ✅ iOS 15.0 and higher * ❌ tvOS * ❌ watchOS * ❌ macOS From 62181d387a5d8bac548276bf273f82f11d5f67eb Mon Sep 17 00:00:00 2001 From: Josh Holtz Date: Wed, 23 Aug 2023 23:57:30 -0500 Subject: [PATCH 2/6] Forgot to update a variable --- .../displaying-products/paywalls.md" | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git "a/docs_source/\360\237\232\200 Getting Started/displaying-products/paywalls.md" "b/docs_source/\360\237\232\200 Getting Started/displaying-products/paywalls.md" index 2a456b86..1dab4e09 100644 --- "a/docs_source/\360\237\232\200 Getting Started/displaying-products/paywalls.md" +++ "b/docs_source/\360\237\232\200 Getting Started/displaying-products/paywalls.md" @@ -93,17 +93,17 @@ For example, to show a CTA like “Try 7 Days Free & Subscribe”, you should in We support the following variables: -| Variable | Description | Example Value | -| :------------------------ | :-------------------------------------------------------------------------------------------------------------- | :---------------- | -| product_name | The name of the product from the store (e.g. product localized title from StoreKit) for a given package | CatGPT | -| price | The localized price of a given package | $39.99 | -| price_per_period | The localized price of a given package with its period length if applicable | $39.99/yr | -| total_price_and_per_month | The localized price of a given package with its monthly equivalent price if it is not already a monthly package | $39.99 ($1.67/mo) | -| sub_price_per_month | The localized price of a given package converted to a monthly equivalent price | $3.33 | -| sub_duration | The duration of the subscription; '1 month', '3 months', etc. | 1 month | -| sub_period | The length of each period of the standard offer on a given package | Monthly | -| sub_offer_duration | The period of the introductory offer on a given package | 7 days | -| sub_offer_price | The localized price of the introductory offer of a given package | $4.99 | +| Variable | Description | Example Value | +| :------------------------ | :------------------------------------------------------------------------------------------------------ | :---------------- | +| product_name | The name of the product from the store (e.g. product localized title from StoreKit) for a given package | CatGPT | +| price | The localized price of a given package | $39.99 | +| price_per_period | The localized price of a given package with its period length if applicable | $39.99/yr | +| total_price_and_per_month | The localized price of a given package with its monthly equivalent price if it has one | $39.99 ($1.67/mo) | +| sub_price_per_month | The localized price of a given package converted to a monthly equivalent price | $3.33 | +| sub_duration | The duration of the subscription; '1 month', '3 months', etc. | 1 month | +| sub_period | The length of each period of the standard offer on a given package | Monthly | +| sub_offer_duration | The period of the introductory offer on a given package | 7 days | +| sub_offer_price | The localized price of the introductory offer of a given package | $4.99 | > 📘 > From ba25f5e0b6c8a71729253fa55e05802e27aed5e7 Mon Sep 17 00:00:00 2001 From: Josh Holtz Date: Thu, 24 Aug 2023 00:00:48 -0500 Subject: [PATCH 3/6] Fixed lint issue --- .../displaying-products/paywalls/paywalls_6.swift" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_6.swift" "b/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_6.swift" index cc59204b..b1c4450a 100644 --- "a/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_6.swift" +++ "b/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_6.swift" @@ -4,7 +4,7 @@ import RevenueCat import RevenueCatUI struct YourPaywall: View { - + let offering: Offering var body: some View { From b484942f5532761641b0ec010a7c954e9344f4bf Mon Sep 17 00:00:00 2001 From: Josh Holtz Date: Thu, 24 Aug 2023 13:27:51 -0500 Subject: [PATCH 4/6] =?UTF-8?q?Update=20docs=5Fsource/=F0=9F=9A=80=20Getti?= =?UTF-8?q?ng=20Started/displaying-products/paywalls.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: NachoSoto --- .../displaying-products/paywalls.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/docs_source/\360\237\232\200 Getting Started/displaying-products/paywalls.md" "b/docs_source/\360\237\232\200 Getting Started/displaying-products/paywalls.md" index 1dab4e09..7735774f 100644 --- "a/docs_source/\360\237\232\200 Getting Started/displaying-products/paywalls.md" +++ "b/docs_source/\360\237\232\200 Getting Started/displaying-products/paywalls.md" @@ -7,7 +7,7 @@ RevenueCat's Paywalls allow you to to remotely configure your entire paywall vie > ❗️ > -> Paywalls are only available for iOS 15+ but macOS and Android support are coming soon! +> Paywalls are only available for iOS 15+ but support for macOS, Android, and other platforms is coming soon! ## How Paywalls work From 6924500990332b87fd5b878cd9470df7d6314415 Mon Sep 17 00:00:00 2001 From: Josh Holtz Date: Thu, 24 Aug 2023 13:28:03 -0500 Subject: [PATCH 5/6] =?UTF-8?q?Update=20code=5Fblocks/=F0=9F=9A=80=20Getti?= =?UTF-8?q?ng=20Started/displaying-products/paywalls/paywalls=5F6.swift?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: NachoSoto --- .../displaying-products/paywalls/paywalls_6.swift" | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git "a/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_6.swift" "b/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_6.swift" index b1c4450a..8ce3e7bb 100644 --- "a/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_6.swift" +++ "b/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_6.swift" @@ -10,7 +10,8 @@ struct YourPaywall: View { var body: some View { ScrollView { // Your custom paywall design content - }.paywallFooter(offering: offering, condensed: true) { customerInfo in + } + .paywallFooter(offering: offering, condensed: true) { customerInfo in // Purchase completed! Thank your user and dismiss your paywall } } From b291ba1b6f8a14cc9091db029f9420828dcb53ca Mon Sep 17 00:00:00 2001 From: Josh Holtz Date: Thu, 24 Aug 2023 13:28:10 -0500 Subject: [PATCH 6/6] =?UTF-8?q?Update=20code=5Fblocks/=F0=9F=9A=80=20Getti?= =?UTF-8?q?ng=20Started/displaying-products/paywalls/paywalls=5F5.swift?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: NachoSoto --- .../displaying-products/paywalls/paywalls_5.swift" | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git "a/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_5.swift" "b/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_5.swift" index 9a202ae0..f19f604a 100644 --- "a/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_5.swift" +++ "b/code_blocks/\360\237\232\200 Getting Started/displaying-products/paywalls/paywalls_5.swift" @@ -8,7 +8,8 @@ struct YourPaywall: View { var body: some View { ScrollView { // Your custom paywall design content - }.paywallFooter() + } + .paywallFooter() } }