[Billing Plans] Support fetching products with billing plans#6758
Conversation
|
|
||
| let installmentsInfo: InstallmentsInfo? | ||
|
|
||
| let billingPlanIdentifier: String? |
There was a problem hiding this comment.
Should we make our own typed billing plan instead of exposing a string? 🤔
EDIT: I see now we're exposing the string version here and we have an internal billingPlanType in InstallmentsInfo. Maybe we could remove this one and find a way to expose the typed one inside InstallmentsInfo? reason: both should be null or non-null at the same time, so conflating all the instalments fields inside InstallmentsInfo seems cleaner?
|
@tonidero @MarkVillacampa Okay, we've gone through another iteration here, and I think we're getting pretty close. I've added a new non-enum type to @objc(RCBillingPlanType)
public final class BillingPlanType: NSObject, Sendable {
@objc(RCUpFront) public static let upFront = BillingPlanType()
@objc(RCMonthly) public static let monthly = BillingPlanType()
private override init() {}
}I used a To make sure that we don't somehow have inconsistent state where a value is present on StoreProduct.installmentsInfo.billingPlanType and not on Unless y'all see any issues that should be addressed in this PR, I propose that we merge this into the dev branch and immediately follow up with two PRs since this one is getting pretty large:
Let me know what y'all think! |
|
One thing to consider, is how we're going to map this new API in the hybrids... If we want to reuse the subscription options, I think in PHC + KMP, we would need to bring back some of the logic we previously had to map to those subscription options, and keep the same style we have in android (I think in hybrid, ideally it behaves the same way). Having said that, I do think this API makes more sense for iOS, so it's probably better to do this here, and do the required mappings in the PHC + KMP |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7626aef. Configure here.
|
@tonidero I think that the plan was to not adopt the For the hybrids, I think that they would distinguish the different between a "regular" product and a product with billing plans at purchase time would be the presence of an |

Motivation
Populates a new
InstallmentInfosobject for iOS products with commitments.Description
Here's what's new:
New APIs
InstallmentsInfo: New class representing the installments that a subscriber commits to when they subscribe to a subscription.
InstallmentsInfois then exposed onStoreProduct. It is populated when a product has installments on it, and is nil otherwise.Product Fetching Changes
When fetching products, you can now provide what I'm calling "compound" product identifiers: product identifiers where there's a colon and a string after the base product ID, like how products are represented in BC5, like
com.revenuecat.sub:monthly. The portion after the colon represents a product's billing plan. You can fetch them withawait Purchases.shared.products([productID]). Here's what can happen when you request the products:com.revenuecat.sub: Returns the product with the default billing plan. Today, that always defaults toupFront, so you'll receive one product back with noInstallmentsInfo.com.revenuecat.sub:upFront: Returns the product with theupFrontbilling plan. Since the upFront billing plan has no installments, you'll receive one product back with noInstallmentsInfo.com.revenuecat.sub:monthly: Returns the product with themonthlybilling plan. Since the monthly billing plan has installments, you'll receive one product back withInstallmentsInfopopulated.Note that the billing plan lookup is case sensitive, and if the billing plan isn't found, or the user isn't eligible for it, no products will be returned.
Purchase Tester
Added a new screen to the purchase tester to test the
Purchases.shared.products([productID])function directly.Testing
CompoundProductIdentifierparsing and theInstallmentsInfoFactory.Purchases.shared.products([productID])through the purchase testerWe have not yet tested fetching of products with compound product identifiers through the Offerings system. That will come later this week :)
Note
Medium Risk
Changes product fetching and SK2 product identity/equality to support billing-plan-specific variants and new
InstallmentsInfo, which could affect product caching/selection and StoreKit 2 results across platforms.Overview
Adds support for fetching billing-plan-specific StoreKit 2 products using compound product identifiers (e.g.
productId:monthly), while transparently requesting only base StoreKit product IDs and warning when invalid identifiers are provided.Introduces new public APIs
BillingPlanTypeandInstallmentsInfo(exposed viaStoreProduct.installmentsInfoon iOS/tvOS/watchOS/macOS/visionOS 26.4+), plus anInstallmentsInfoFactoryto derive installment commitment details from StoreKit 2 pricing terms.Updates
SK2StoreProductto carry aCompoundProductIdentifier, adjusts hashing/equality accordingly, adds extensive unit tests and API tester coverage, and adds a PurchaseTester UI screen to manually fetch/display products and installment info.Reviewed by Cursor Bugbot for commit 99f2856. Bugbot is set up for automated code reviews on this repo. Configure here.