-
Notifications
You must be signed in to change notification settings - Fork 291
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
Offline Entitlements: get SK2 purchase information #2352
Offline Entitlements: get SK2 purchase information #2352
Conversation
addresses sdk-2978
Generated by 🚫 Danger |
@available(iOS 15.0, tvOS 15.0, watchOS 8.0, macOS 12.0, *) | ||
struct PurchasedProductsManager { | ||
|
||
func fetchPurchasedProducts() async throws -> [PurchasedSK2Product] { |
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.
This would probably be static
, right?
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.
I went with instance out of sheer habit. Based on the env detector there, though, it looks like current style is protocol + static + initializer with default param? Happy to go with that instead
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.
Oh wait, this is a "manager" ignore my comment. I was thinking this was a product type.
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.
so... to be clear, do you like this style better than the other one? I'm happy to go with either.
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.
Yeah this makes sense 👍🏻
Both are the same thing TBH, but this makes mocking a bit easier.
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.
Actually this is a struct
, so it can't be mocked. So might as well make this static
. But this is fine for now, let's see how we need to use this and/or mock it and then we can change it.
/// a Factory pattern to store the logic in one place | ||
@available(iOS 15.0, tvOS 15.0, watchOS 8.0, macOS 12.0, *) | ||
struct PurchasedSK2Product { | ||
let productIdentifier: String |
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.
Nit: line break inside types (it took me a while to get used to this but now it's hard not to hehe)
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.
I like it 💪🏻 thanks! FWIW, expect to see some of the ugliest code ever while this is in draft
billingIssueDetectedAt: purchasedSK2Product.billingIssueDetectedAt, | ||
ownershipType: purchasedSK2Product.ownershipType, | ||
verification: purchasedSK2Product.verification), | ||
rawData: [:]) // todo: should we just have the data be the transaction's raw data? |
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.
Yeah ideally this matches the same format as our normal EntitlementInfo
s, but that's going to be hard to guarantee. Given that we don't document it, I think it would be safe to have something else, like the transaction's raw data as you said 👍🏻
@@ -246,6 +246,14 @@ extension PeriodType: DefaultValueProvider { | |||
self.rawData = entitlement.rawData | |||
} | |||
|
|||
init(contents: EntitlementInfo.Contents, |
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.
I'm surprised this compiles. Can you make the other constructor convenience
and delegate it to this one now?
self.periodType = .normal | ||
} | ||
|
||
self.isActive = expirationDate == nil || expirationDate! > Date() // todo: check what we usually do for non-subs |
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.
To avoid the force unwrap maybe:
self.isActive = expirationDate == nil || expirationDate! > Date() // todo: check what we usually do for non-subs | |
self.isActive = expirationDate.map { $0 > Date() } ?? false // todo: check what we usually do for non-subs |
@available(iOS 15.0, tvOS 15.0, watchOS 8.0, macOS 12.0, *) | ||
enum OfflineEntitlementsStrings { | ||
|
||
case found_unverified_transactions_in_sk2(transaction: StoreKit.Transaction, error: Error) |
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.
Nit: I think these parameter names don't add anything useful that's not already encoded in the types:
case found_unverified_transactions_in_sk2(transaction: StoreKit.Transaction, error: Error) | |
case found_unverified_transactions_in_sk2(StoreKit.Transaction, Error) |
|
||
var description: String { | ||
switch self { | ||
case .found_unverified_transactions_in_sk2(let transaction, let error): |
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.
We don't have anything in the style guide, but if you agree with this maybe we should:
case .found_unverified_transactions_in_sk2(let transaction, let error): | |
case let .found_unverified_transactions_in_sk2(transaction, error): |
One let
instead of multiple?
This is a great start 💪🏻 about to branch off to work on exposing the |
var description: String { | ||
switch self { | ||
case let .found_unverified_transactions_in_sk2(transaction, error): | ||
return """ | ||
Found an unverified transaction. It will be ignored and will not be a part of CustomerInfo. | ||
Details: | ||
Error: \(error.localizedDescription) | ||
Transaction: \(transaction.debugDescription) | ||
""" |
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.
@NachoSoto I also updated this to multi-line string, I figured it's much easier to read now. WDTY?
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.
Love it
} | ||
|
||
@available(iOS 15.0, tvOS 15.0, watchOS 8.0, macOS 12.0, *) | ||
extension PurchasedSK2Product { |
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.
I think we need a different representation here, so we can use the same code that constructs EntitlementInfos
from the response data. This is useful for creating an individual EntitlementInfo
, but we'd have to change a bunch more code. Instead, we can use the types in CustomerInfoResponse
so that at the top level we can construct a CustomerInfo
the same way.
Might not make a lot of sense, but I'll have a PR ready to show what I mean.
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.
My new suggested type:
struct PurchasedSK2Product {
let subscription: CustomerInfoResponse.Subscription
let transaction: CustomerInfoResponse.Transaction
let entitlement: CustomerInfoResponse.Entitlement
}
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.
Continued on #2358 |
Just started work on this. Early draft getting purchase information from StoreKit 2 so we can create entitlements from it.