Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove presentCodeRedemptionSheet from PaymentQueueWrapper & Use SK2 APIs #4378

Open
wants to merge 16 commits into
base: main
Choose a base branch
from

Conversation

fire-at-will
Copy link
Contributor

@fire-at-will fire-at-will commented Oct 17, 2024

Motivation

As a part of supporting win-back offers with Streamlined Purchasing disabled, we need to ensure that we aren't using both the PurchaseIntents API and the paymentQueue(_:shouldAddStorePayment:for:) functions at the same time to comply with this warning from Apple's PurchaseIntent docs:

Important

To enable promoted in-app purchases, your app must use either PurchaseIntent (starting in iOS 16.4) or paymentQueue(_:shouldAddStorePayment:for:) (starting in iOS 11). Don’t use both at the same time. If necessary, use conditional compilation to identify the OS version the app is running in. For more information, see Running code on a specific platform or OS version.

To meet this requirement, we want to ensure that we're not using the PaymentQueueWrapper class when on iOS >=16.4 (when the PurchaseIntents API was introduced) and the SDK is configured to use StoreKit2.

Description

This PR removes the presentCodeRedemptionSheet function from the PaymentQueueWrapperType and replaces its usages with a new OfferCodeRedemptionSheetPresenter struct.

API Changes

The PR deprecates the existing public Purchases.presentCodeRedemptionSheet() function and replaces it with a new function that more closely matches Apple's new API for presenting offer code redemption sheets:

@available(iOS 14.0, *)
@available(macCatalyst, unavailable)
@available(watchOS, unavailable)
@available(tvOS, unavailable)
@available(macOS, unavailable)
func presentCodeRedemptionSheet(uiWindowScene: UIWindowScene?) async throws

The notable changes for this function signature include:

  • It's async & throwing
  • It accepts an optional UIWindowScene that allows the developer to specify which scene to present the sheet over. If one is not provided, we display the sheet over the currently active scene.

Mac Catalyst & "Designed for iPad" Apps on macOS

According to Apple's presentOfferCodeRedeemSheet docs:

In Mac apps built with Mac Catalyst, this method throws a StoreKitError.unknown error.

In our testing, the StoreKitError.unknown error is also thrown on iOS apps running as "Designed for iPad" on macOS. Due to this error, our new functions:

  • Are unavailable for Mac Catalyst
  • No-op and log a warning for iOS running as "Designed for iPad" on macOS

Implications for the Hybrids

For now, the hybrids should be okay to continue using the deprecated presentCodeRedemptionSheet function. We can update them to use the new presentCodeRedemptionSheet API by doing the following:

  • When async/await isn't available, wrap the call in a Task
  • Passing in nil for the uiWindowScene and just presenting over the currently active window scene

Presenting the Offer Code Redemption Sheet on macOS

Apple introduced a new API for showing the code redemption sheet on native (non-iOS, non-catalyst) macOS apps. To keep the scope of this PR down, that functionality will be added in a follow-up PR.

@fire-at-will fire-at-will self-assigned this Oct 18, 2024
@fire-at-will fire-at-will added feat:Win-Back Offers Supporting iOS 18's Win-Back Offers pr:other labels Oct 18, 2024
@fire-at-will fire-at-will changed the title [WIP] new presentCodeSheet on iOS/macCatalyst Remove presentCodeRedemptionSheet from PaymentQueueWrapper & Use SK2 APIs Oct 18, 2024
}

guard let windowScene else {
Logger.error(Strings.storeKit.error_displaying_offer_code_redemption_sheet_no_window_scene)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be a little awkward that this is possible, but I thought it was important to keep the provided window scene optional for two reasons:

  1. So that developers using SwiftUI can use easily the API
  2. To keep the new Purchases.presentCodeRedemptionSheet API as similar as possible to the deprecated one

@fire-at-will fire-at-will marked this pull request as ready for review October 18, 2024 19:13
@fire-at-will fire-at-will requested review from MarkVillacampa and a team October 18, 2024 19:17
Copy link
Member

@aboedo aboedo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generally looks great! Left one question

* "`This function doesn’t affect Mac apps built with Mac Catalyst.`"
* when, in fact, it crashes when called both from Catalyst and also when running as "Designed for iPad".
* This is why RevenueCat's SDK makes it unavailable in mac catalyst.
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean calling this function of the SDK has been crashing on Catalyst and iOS apps running on macOS?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For Catalyst, nope! Luckily the old version of presentCodeRedemptionSheet() was marked as unavailable on Catalyst (see the definition in the current main branch here.

For "Designed for iPad" on macOS, I haven't tested it myself, but I wouldn't be surprised if the existing SDK function is crashing, since this PR introduces the isiOSAppOnMac check for the first time in the code redemption sheet flow

@@ -679,6 +679,28 @@ public protocol PurchasesType: AnyObject {

#if os(iOS) || VISION_OS
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was the presentCodeRedemptionSheet function moved inside this conditional intentionally? I think this might be a breaking change since it changes where the function is compiled (even if unavailable) so you cannot use runtime availability checks with it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat:Win-Back Offers Supporting iOS 18's Win-Back Offers pr:other
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants