Skip to content

Prepare the codebase to listen to the Storefront changes (1/4)#1557

Merged
taquitos merged 15 commits into
RevenueCat:mainfrom
Juanpe:respond_to_Storefront_changes
May 16, 2022
Merged

Prepare the codebase to listen to the Storefront changes (1/4)#1557
taquitos merged 15 commits into
RevenueCat:mainfrom
Juanpe:respond_to_Storefront_changes

Conversation

@Juanpe

@Juanpe Juanpe commented May 9, 2022

Copy link
Copy Markdown
Contributor

Subtask of #1382

Description

This PR is the first step to preparing the codebase to respond to Storefront changes to update some stuff that is in the cache.

Changes:

  • Listen to Storefront changes for SK1 via SKPaymentTransactionObserver protocol using the paymentQueueDidChangeStorefront method.
  • Listen to Storefront changes for SK2, creating a new listener (StoreKit2TransactionListener ).
  • Update PurchasesOrchestrator, adding the new delegate methods.
  • Fix failing tests related to these changes and add new ones.


@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
lazy var storeKit2Listener = StoreKit2TransactionListener(delegate: self)
lazy var storeKit2TransactionListener = StoreKit2TransactionListener(delegate: self)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

In the future, we could create a single listener that would be composed of other "sublisteners"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can this be private(set)?

@Juanpe Juanpe May 10, 2022

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yep 🙂 let me change it Finally, it's not possible, we are setting this listener in the tests, so we need the set method as public 😕 Admittedly it is only needed for testing, but I would leave it there for now.
WDYT? 🤔

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That's fine then!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That's fine then!

import XCTest

@available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *)
class StoreKit2StorefrontListenerTests: XCTestCase {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I tried to add a test case to cover when the Storefront changes, but I couldn’t. Is there is a way? 🤔

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah I don't think we can change the storefront mid-way through a test run unfortunately.

@available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *)
class StoreKit2StorefrontListener {

private(set) var taskHandle: Task<Void, Never>?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would implement didSet here like so:

didSet {
  if self.taskHandle !== oldValue {
    oldValue?.cancel()
  }
}

Then you only need to set it to nil or the new value.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

much better 👍🏼 Thanks :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Just a question, why do you have to check if they are identical, checking if they are not equal wouldn't be enough? 🤔

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done! ✅ cee546e

@NachoSoto NachoSoto left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Awesome!


@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
lazy var storeKit2Listener = StoreKit2TransactionListener(delegate: self)
lazy var storeKit2TransactionListener = StoreKit2TransactionListener(delegate: self)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can this be private(set)?

lazy var storeKit2TransactionListener = StoreKit2TransactionListener(delegate: self)

@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
lazy var storeKit2StorefrontListener = StoreKit2StorefrontListener(delegate: self)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ditto private(set)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

same here 🙂

Comment on lines +48 to +49
taskHandle?.cancel()
taskHandle = nil

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is duplicated, you can just do self.taskHandle = nil now :)
The advantage of what I suggested is that now it's impossible to have a reference to a cancelled task :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah! good catch! I forgot to update this line 🤦🏼‍♂️

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done! ✅ (171db44)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've reverted the change because when the listener is released, the didSet observer is not called 😅 so the task is not cancelled. I've cancelled the task when the listener is released and modified the test cases to cover this scenario.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oooh that's a great catch I forgot!!

Comment thread Sources/Purchasing/StoreKit2/StoreKit2StorefrontListener.swift Outdated
taskHandle = Task { [weak self] in
for await _ in StoreKit.Storefront.updates {
guard let self = self else { break }
self.delegate?.storefrontDidUpdate()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe put this inside of MainActor.run {}?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good point 👍🏼

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done! ✅ (ad5e799)

import XCTest

@available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *)
class StoreKit2StorefrontListenerTests: XCTestCase {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah I don't think we can change the storefront mid-way through a test run unfortunately.

Comment thread Tests/StoreKitUnitTests/StoreKit2StorefrontListenerTests.swift Outdated
Comment thread Tests/StoreKitUnitTests/StoreKit2StorefrontListenerTests.swift Outdated
Comment on lines +39 to +43
expect(handle).toNot(beNil())
expect(handle?.isCancelled) == false

self.listener = nil
expect(handle?.isCancelled) == true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is nice.

Comment thread Sources/Purchasing/StoreKit2/StoreKit2StorefrontListener.swift
Juanpe and others added 6 commits May 10, 2022 21:51
Co-authored-by: NachoSoto <NachoSoto@users.noreply.github.com>
Co-authored-by: NachoSoto <NachoSoto@users.noreply.github.com>
Co-authored-by: NachoSoto <NachoSoto@users.noreply.github.com>
@Juanpe

Juanpe commented May 10, 2022

Copy link
Copy Markdown
Contributor Author

@NachoSoto Thanks for the review and feedback! ❤️

@NachoSoto

Copy link
Copy Markdown
Contributor

I'll wait to see if @aboedo has any feedback before merging this.

@Juanpe

Juanpe commented May 16, 2022

Copy link
Copy Markdown
Contributor Author

Hi guys! 👋🏼 Did you have a chance to take a look at this PR? 🙂 The second PR is ready to be opened but I can't because I'm working on a fork and I can't select this branch as the base of the other PR. So, I have to wait for this PR to be merged to open the other one, otherwise, you would see the same changes 😅

@taquitos taquitos left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎈🐐

@taquitos taquitos merged commit 3a4093d into RevenueCat:main May 16, 2022
@joshdholtz joshdholtz mentioned this pull request May 26, 2022
NachoSoto pushed a commit that referenced this pull request Jun 16, 2022
Follow up to #1557. Subtask of #1382 

### Description

This PR aims to clear the stuff in the cache when the Storefront changes.

Changes:
- Add `clearCachedOfferings` method to `DeviceCache`.
- Add `clearCache` method to `ProductFetcherSK1`.
- Make `internal` the `clearCache` method in `ProductsFetcherSK2`.
- Handle the **Storefront** changes in the `PurchasesOrchestator`.
- Add tests to cover some scenarios.
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.

3 participants