Add full screen paywall presentation support#839
Conversation
| /// <summary> | ||
| /// Controls how paywalls are presented on iOS. | ||
| /// </summary> | ||
| public sealed class IOSPaywallPresentationStyle |
There was a problem hiding this comment.
Hmm I guess I'm not sure if we should make these sealed... If it allows to do some sort of switch-case style processing on the styles, I would say it could produce a breaking change, but seems like it shouldn't, so I think we should be ok.
There was a problem hiding this comment.
I actually think enums in C# are not exhaustive. That would work as well right?
There was a problem hiding this comment.
Right, as long as they do not allow for exhaustive handling of all values, we should be ok I think.
There was a problem hiding this comment.
Looked into this and the sealed class approach is safe here. In C#, sealed class with private constructor + static readonly fields is not exhaustively matched by the compiler, unlike enum or Kotlin sealed class. If someone writes:
if (style == IOSPaywallPresentationStyle.FullScreen) { ... }
else if (style == IOSPaywallPresentationStyle.Sheet) { ... }
Adding a new style later won't cause a compile error, they just won't handle it (safe default). With a C# enum, the compiler can warn about unhandled cases in switch, making new values potentially breaking.
Adds `FullScreen` and `Default` static presets for common presentation configurations, simplifying the most common use case. Also updates the Subtester to use the new preset. Made-with: Cursor
46b7e3c to
8342045
Compare
tonidero
left a comment
There was a problem hiding this comment.
Looks great! Thank you!!
| static NSMutableDictionary *RCUICreateOptionsDictionary(NSString *offeringIdentifier, NSString *presentedOfferingContextJson, BOOL displayCloseButton, BOOL useFullScreenPresentation) { | ||
| NSMutableDictionary *options = [NSMutableDictionary new]; | ||
| options[kRCUIOptionDisplayCloseButton] = @(displayCloseButton); | ||
| options[@"useFullScreenPresentation"] = @(useFullScreenPresentation); |
There was a problem hiding this comment.
I wonder if we should pass the presentation mode as a string instead... But I guess since this is internal, we can always change it later. Let's keep it like this!
| /// Configuration for how a paywall should be presented on each platform. | ||
| /// Each platform field is optional; when null, the platform's default presentation style is used. | ||
| /// </summary> | ||
| public class PaywallPresentationConfiguration |
There was a problem hiding this comment.
I wonder if it would be worth adding a small code sample on how to use this in the docs either here or the PaywallOptions... I've found that helps figuring out how to use these APIs... But not a blocker, I think it can always be added later if needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…presentation-style-api-in
**This is an automatic release.** ## RevenueCat SDK ### ✨ New Features * Add PurchaseLogic support for paywall presentation when `PurchasesAreCompletedBy.MyApp` (#842) via Toni Rico (@tonidero) ### 📦 Dependency Updates * [AUTOMATIC BUMP] Updates purchases-hybrid-common to 17.46.1 (#854) via RevenueCat Git Bot (@RCGitBot) * [Android 9.23.1](https://github.com/RevenueCat/purchases-android/releases/tag/9.23.1) * [Android 9.23.0](https://github.com/RevenueCat/purchases-android/releases/tag/9.23.0) * [iOS 5.61.0](https://github.com/RevenueCat/purchases-ios/releases/tag/5.61.0) * [AUTOMATIC BUMP] Updates purchases-hybrid-common to 17.46.0 (#853) via RevenueCat Git Bot (@RCGitBot) * [Android 9.23.1](https://github.com/RevenueCat/purchases-android/releases/tag/9.23.1) * [Android 9.23.0](https://github.com/RevenueCat/purchases-android/releases/tag/9.23.0) * [iOS 5.61.0](https://github.com/RevenueCat/purchases-ios/releases/tag/5.61.0) * [AUTOMATIC BUMP] Updates purchases-hybrid-common to 17.44.0 (#850) via RevenueCat Git Bot (@RCGitBot) * [Android 9.23.1](https://github.com/RevenueCat/purchases-android/releases/tag/9.23.1) * [Android 9.23.0](https://github.com/RevenueCat/purchases-android/releases/tag/9.23.0) * [iOS 5.61.0](https://github.com/RevenueCat/purchases-ios/releases/tag/5.61.0) ## RevenueCatUI SDK ### ✨ New Features * Add full screen paywall presentation support (#839) via Cesar de la Vega (@vegaro) ### 🔄 Other Changes * Redo Subtester app and fix Android emulators support (#855) via Cesar de la Vega (@vegaro) * Support PaywallActivity screenOrientation manifest override (#844) via Toni Rico (@tonidero) * refactor: Use PaywallView instead of PaywallActivity on Android (#841) via Toni Rico (@tonidero) * Add API tests for Paywalls and CustomerCenter presenters (#735) via Facundo Menzella (@facumenzella) * Bump fastlane-plugin-revenuecat_internal from `f5c099b` to `e146447` (#852) via dependabot[bot] (@dependabot[bot]) * Bump fastlane-plugin-revenuecat_internal from `8cd957f` to `f5c099b` (#848) via dependabot[bot] (@dependabot[bot])
…tation style (#1623) ## Summary Fixes landscape white-area issue (PW-148) by adding an explicit opt-in API for controlling paywall presentation style, matching the approach in [purchases-unity PR #839](RevenueCat/purchases-unity#839). - Adds \`PaywallPresentationConfiguration\` with per-platform style types (\`IOSPaywallPresentationStyle\`, \`AndroidPaywallPresentationStyle\`) - Adds optional \`presentationConfiguration\` parameter to \`presentPaywall()\` and \`presentPaywallIfNeeded()\` - iOS plugin passes \`useFullScreenPresentation\` only when explicitly set — default behavior unchanged (sheet on iOS) - No device filtering — if the dev passes \`fullScreen\`, it applies on any device (iPhone or iPad) - Purchase tester shows a \`CupertinoActionSheet\` to choose Sheet or Full Screen before presenting ### Usage ```dart // Full screen on iOS (fixes landscape white-area bug PW-148) final result = await RevenueCatUI.presentPaywall( presentationConfiguration: PaywallPresentationConfiguration( ios: IOSPaywallPresentationStyle.fullScreen, ), ); // Default behavior (sheet on iOS) final result = await RevenueCatUI.presentPaywall(); ``` ### Related - Unity: RevenueCat/purchases-unity#839 - Linear: PW-148, PW-956 ## Test plan - [x] All unit tests pass - [x] API tester (\`flutter analyze\`) clean — no breaking changes - [x] Tests cover \`fullScreen\` and \`sheet\` configurations - [x] Tests verify \`useFullScreenPresentation\` is not sent when no config is passed - [x] Purchase tester builds on iOS - [x] Manual test: present paywall without config → sheet on iOS - [x] Manual test: present paywall with \`ios: fullScreen\` → full screen on iOS <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Adds a new public API knob that changes iOS paywall presentation behavior and updates the iOS plugin call path; incorrect wiring could affect paywall UX on iOS. Changes are scoped and covered by new unit/API tests, reducing regression risk. > > **Overview** > Adds an opt-in `PaywallPresentationConfiguration` API (with `IOSPaywallPresentationStyle`/`AndroidPaywallPresentationStyle`) and exports it from `purchases_ui_flutter`. > > `RevenueCatUI.presentPaywall()` and `presentPaywallIfNeeded()` now accept an optional `presentationConfiguration` and only send the native `useFullScreenPresentation` flag when iOS full-screen is explicitly requested (omitting the key preserves the native default sheet behavior). > > Updates the iOS plugin to accept/pass through `useFullScreenPresentation` instead of always forcing full-screen on iPhone, expands unit tests/API tester coverage for the new argument behavior, and updates the purchase tester example UI to let users choose sheet vs full-screen before presenting a paywall. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 35fb97d. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Cesar de la Vega <664544+vegaro@users.noreply.github.com>
Adds a new PaywallPresentationConfiguration API that allows developers to control how paywalls are presented on each platform independently. Currently, iOS presents paywalls as a modal sheet while Android uses full screen. This PR enables iOS fullscreen presentation with an API that is extensible for future platform-specific modes without breaking changes.
Developers have reported wanting full-screen paywall presentation on iOS to match Android behavior (CC-596 (https://linear.app/revenuecat/issue/CC-596), PW-891 (https://linear.app/revenuecat/issue/PW-891)). The underlying native support already exists in purchases-hybrid-common via
PaywallProxy'suseFullScreenPresentationoption.API Design
Uses sealed classes with private constructors instead of enums, so new presentation styles can be added in the future without breaking existing code.
These types make unsupported combinations a compile error:
IOSPaywallPresentationStyle:FullScreen,SheetAndroidPaywallPresentationStyle:FullScreen(only option for now, since Android doesn't support sheet yet and we don't want to add it yet)Just to be clear, we don't want to add support for modal in Android yet, we haven't got any request for that and it's a bit complex, so we are looking for adding full screen support to iOS.