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.
This would probably be static, right?
There was a problem hiding this comment.
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.
Oh wait, this is a "manager" ignore my comment. I was thinking this was a product type.
There was a problem hiding this comment.
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.
Yeah this makes sense 👍🏻
Both are the same thing TBH, but this makes mocking a bit easier.
There was a problem hiding this comment.
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.
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.
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.
Yeah ideally this matches the same format as our normal EntitlementInfos, 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 👍🏻
| self.rawData = entitlement.rawData | ||
| } | ||
|
|
||
| init(contents: EntitlementInfo.Contents, |
There was a problem hiding this comment.
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.
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.
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.
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.
@NachoSoto I also updated this to multi-line string, I figured it's much easier to read now. WDTY?
| } | ||
|
|
||
| @available(iOS 15.0, tvOS 15.0, watchOS 8.0, macOS 12.0, *) | ||
| extension PurchasedSK2Product { |
There was a problem hiding this comment.
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.
My new suggested type:
struct PurchasedSK2Product {
let subscription: CustomerInfoResponse.Subscription
let transaction: CustomerInfoResponse.Transaction
let entitlement: CustomerInfoResponse.Entitlement
}|
Continued on #2358 |
Just started work on this. Early draft getting purchase information from StoreKit 2 so we can create entitlements from it.