-
Notifications
You must be signed in to change notification settings - Fork 307
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
Add currentOffering(forPlacement: String)
to Offerings
#3707
Changes from all commits
b19a9af
ed8895a
2ba6ba7
93ffbde
0c95edf
422cbc2
64b9802
687d4b3
5a208a9
4d1f107
afd340b
fbebf2b
89ddaac
5ccb6b9
cf36d01
cf30753
7e2f47b
e7828ca
cda6a23
2d6262c
c282c1c
f9ee234
cfd5da7
fd3427c
a2a3406
589a7b0
dbeef9e
8bc381f
6e80a44
bc77744
3eb9898
24d2c01
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,19 @@ import Foundation | |
*/ | ||
@objc(RCOfferings) public final class Offerings: NSObject { | ||
|
||
internal final class Placements: NSObject { | ||
let fallbackOfferingId: String? | ||
let offeringIdsByPlacement: [String: String?] | ||
|
||
init( | ||
fallbackOfferingId: String?, | ||
offeringIdsByPlacement: [String: String?] | ||
) { | ||
self.fallbackOfferingId = fallbackOfferingId | ||
self.offeringIdsByPlacement = offeringIdsByPlacement | ||
} | ||
} | ||
|
||
/** | ||
Dictionary of all Offerings (``Offering``) objects keyed by their identifier. This dictionary can also be accessed | ||
by using an index subscript on ``Offerings``, e.g. `offerings["offering_id"]`. To access the current offering use | ||
|
@@ -48,19 +61,23 @@ import Foundation | |
internal let response: OfferingsResponse | ||
|
||
private let currentOfferingID: String? | ||
private let placements: Placements? | ||
|
||
init( | ||
offerings: [String: Offering], | ||
currentOfferingID: String?, | ||
placements: Placements?, | ||
response: OfferingsResponse | ||
) { | ||
self.all = offerings | ||
self.currentOfferingID = currentOfferingID | ||
self.response = response | ||
self.placements = placements | ||
} | ||
|
||
} | ||
|
||
extension Offerings.Placements: Sendable {} | ||
extension Offerings: Sendable {} | ||
|
||
public extension Offerings { | ||
|
@@ -93,4 +110,50 @@ public extension Offerings { | |
return description | ||
} | ||
|
||
/** | ||
Retrieves a current offering for a placement identifier, use this to access offerings defined by targeting | ||
placements configured in the RevenueCat dashboard, | ||
e.g. `offerings.currentOffering(forPlacement: "placement_id")`. | ||
*/ | ||
@objc(currentOfferingForPlacement:) | ||
func currentOffering(forPlacement placementIdentifier: String) -> Offering? { | ||
guard let placements = self.placements else { | ||
return nil | ||
} | ||
|
||
let returnOffering: Offering? | ||
if let explicitOfferingId: String? = placements.offeringIdsByPlacement[placementIdentifier] { | ||
// Don't use fallback since placement id was explicity set in the dictionary | ||
returnOffering = explicitOfferingId.flatMap { self.all[$0] } | ||
} else { | ||
// Use fallback since the placement didn't exist | ||
returnOffering = placements.fallbackOfferingId.flatMap { self.all[$0]} | ||
} | ||
|
||
return returnOffering?.copyWith(placementIdentifier: placementIdentifier) | ||
} | ||
} | ||
|
||
private extension Offering { | ||
func copyWith(placementIdentifier: String?) -> Offering { | ||
let updatedPackages = self.availablePackages.map { pkg in | ||
let newContext = PresentedOfferingContext( | ||
offeringIdentifier: pkg.presentedOfferingContext.offeringIdentifier, | ||
placementIdentifier: placementIdentifier | ||
) | ||
|
||
return Package(identifier: pkg.identifier, | ||
packageType: pkg.packageType, | ||
storeProduct: pkg.storeProduct, | ||
presentedOfferingContext: newContext | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick but should we have an internal copy constructor from package so we can create a new package with a new context without having to pass all the parameters again? |
||
) | ||
} | ||
|
||
return Offering(identifier: self.identifier, | ||
serverDescription: self.serverDescription, | ||
metadata: self.metadata, | ||
paywall: self.paywall, | ||
availablePackages: updatedPackages | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,18 +19,31 @@ import Foundation | |
/// | ||
@objc(RCPresentedOfferingContext) public final class PresentedOfferingContext: NSObject { | ||
|
||
/// The identifier of the ``Offering`` containing this Package. | ||
/// The identifier of the ``Offering`` containing this ``Package``. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm late to the game here, but... what do I do with this class as a developer? Is it so I can use it for analytics? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @aboedo Oops, missed this comment from yesterday! This is mainly for internal usage. Instead of passing |
||
@objc public let offeringIdentifier: String | ||
|
||
/// The placement identifier this ``Package`` was obtained from. | ||
@objc public let placementIdentifier: String? | ||
|
||
/// Initialize a ``PresentedOfferingContext``. | ||
@objc | ||
public init( | ||
offeringIdentifier: String | ||
offeringIdentifier: String, | ||
placementIdentifier: String? | ||
) { | ||
self.offeringIdentifier = offeringIdentifier | ||
self.placementIdentifier = placementIdentifier | ||
super.init() | ||
} | ||
|
||
/// Initialize a ``PresentedOfferingContext``. | ||
@objc | ||
public convenience init( | ||
offeringIdentifier: String | ||
) { | ||
self.init(offeringIdentifier: offeringIdentifier, placementIdentifier: nil) | ||
} | ||
|
||
public override func isEqual(_ object: Any?) -> Bool { | ||
guard let other = object as? PresentedOfferingContext else { return false } | ||
|
||
|
@@ -91,7 +104,8 @@ import Foundation | |
identifier: identifier, | ||
packageType: packageType, | ||
storeProduct: storeProduct, | ||
presentedOfferingContext: PresentedOfferingContext(offeringIdentifier: offeringIdentifier) | ||
presentedOfferingContext: PresentedOfferingContext(offeringIdentifier: offeringIdentifier, | ||
placementIdentifier: nil) | ||
) | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
placements.offeringIdsByPlacement[placementIdentifier]
returns atOffering??
becauseplacements.offeringIdsByPlacement
is a[String: String?]
The result of could be an explicit
nil
value. In that case, we don't want to use the fallback offering.If
placements.offeringIdsByPlacement[placementIdentifier]
is not found and goes into theelse
, it means no key was found and we should use the fallback offering.