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

Offline Entitlements: get SK2 purchase information #2352

Closed

Conversation

aboedo
Copy link
Member

@aboedo aboedo commented Mar 17, 2023

Just started work on this. Early draft getting purchase information from StoreKit 2 so we can create entitlements from it.

@aboedo aboedo self-assigned this Mar 17, 2023
@RevenueCat-Danger-Bot
Copy link

1 Error
🚫 Label the PR using one of the change type labels
Label Description
breaking Changes that are breaking
build Changes that affect the build system
ci Changes to our CI configuration files and scripts
docs Documentation only changes
feat A new feature
fix A bug fix
perf A code change that improves performance
refactor A code change that neither fixes a bug nor adds a feature
style Changes that don't affect the meaning of the code (white-space, formatting, missing semi-colons, etc
test Adding missing tests or correcting existing tests
next_release Preparing a new release
dependencies Updating a dependency
phc_dependencies Updating purchases-hybrid-common dependency

Generated by 🚫 Danger

@available(iOS 15.0, tvOS 15.0, watchOS 8.0, macOS 12.0, *)
struct PurchasedProductsManager {

func fetchPurchasedProducts() async throws -> [PurchasedSK2Product] {
Copy link
Contributor

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?

Copy link
Member Author

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

Copy link
Contributor

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.

Copy link
Member Author

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.

Copy link
Contributor

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.

Copy link
Contributor

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
Copy link
Contributor

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)

Copy link
Member Author

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?
Copy link
Contributor

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 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 👍🏻

@@ -246,6 +246,14 @@ extension PeriodType: DefaultValueProvider {
self.rawData = entitlement.rawData
}

init(contents: EntitlementInfo.Contents,
Copy link
Contributor

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
Copy link
Contributor

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:

Suggested change
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)
Copy link
Contributor

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:

Suggested change
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):
Copy link
Contributor

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:

Suggested change
case .found_unverified_transactions_in_sk2(let transaction, let error):
case let .found_unverified_transactions_in_sk2(transaction, error):

One let instead of multiple?

@NachoSoto
Copy link
Contributor

This is a great start 💪🏻 about to branch off to work on exposing the CustomerInfo too.

Comment on lines +28 to +36
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)
"""
Copy link
Member Author

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?

Copy link
Contributor

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 {
Copy link
Contributor

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.

Copy link
Contributor

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

}

Copy link
Contributor

Choose a reason for hiding this comment

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

@NachoSoto
Copy link
Contributor

Continued on #2358

@NachoSoto NachoSoto closed this Mar 23, 2023
@NachoSoto NachoSoto deleted the andy/sdk-2978-write-code-to-list-purchases-made-by-the branch March 23, 2023 16:42
NachoSoto added a commit that referenced this pull request Mar 24, 2023
…ts (#2358)

Based on #2352.
Depends on #2351 and #2365.

---------

Co-authored-by: Andy Boedo <andresboedo@gmail.com>
Co-authored-by: Toni Rico <antonio.rico.diez@revenuecat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants