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

PaymentQueueWrapper: handle promotional purchase requests from App Store when SK1 is disabled #1901

Merged
merged 7 commits into from
Sep 21, 2022

Conversation

NachoSoto
Copy link
Contributor

@NachoSoto NachoSoto commented Sep 10, 2022

Follow up to #1882. After that PR, StoreKit1Wrapper was no longer listening to SKPaymentQueueDelegate.paymentQueue(:shouldAddStorePayment:for:), which means that purchases initiated from the App Store were being ignored by the SDK if SK2 is enabled.

To fix this, PaymentQueueWrapper now becomes the SKPaymentQueueDelegate only when StoreKit1Wrapper is not initialized, and PurchasesOrchestrator initiates an SK2 purchase instead.

Other changes:

  • PurchasesOrchestrator purchase methods no longer need the whole PromotionalOffer, only the SignedData. This allows the new implementation to create that data from only the SKPaymentDiscount provided from the SKPayment.
  • Added tests for PromotionalOffer.SignedData

TODO:

  • Log warning if fetching product failed.
  • Handle discounts
  • Test that StoreKit1Wrapper is the delegate if SK1 is enabled
  • Test that PaymentQueueWrapper is the delegate otherwise
  • Test PromotionalOffer.SignedData initialization from SK1

@NachoSoto NachoSoto added the pr:fix A bug fix label Sep 10, 2022
@NachoSoto NachoSoto requested review from joshdholtz, aboedo and a team September 10, 2022 18:35
@NachoSoto NachoSoto force-pushed the promotional-app-store-purchase-sk1 branch from 3e896bb to e5119ec Compare September 10, 2022 18:38
// when `StoreKit1Wrapper` is not initialized, which means that promoted purchases
// need to be handled as a SK2 purchase.
// This method converts the `SKPayment` into an SK2 purchase by fetching the product again.
assert(self.storeKit1Wrapper == nil, "This method should not be invoked if SK1 is enabled")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is not a precondition so it will be ignored in release builds. Still useful to catch potential misconfigurations in tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

Should we also log an error if this gets called for any reason with SK1 in release builds?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah that's a good idea.

@NachoSoto
Copy link
Contributor Author

I'll finish this today.

@NachoSoto NachoSoto force-pushed the promotional-app-store-purchase-sk1 branch from 87d8b60 to 1d9cfc3 Compare September 13, 2022 00:14
@NachoSoto NachoSoto marked this pull request as ready for review September 13, 2022 00:14
@NachoSoto NachoSoto force-pushed the promotional-app-store-purchase-sk1 branch 2 times, most recently from 5bec134 to 0cae177 Compare September 13, 2022 00:22
Copy link
Contributor

@tonidero tonidero left a comment

Choose a reason for hiding this comment

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

LGTM but will leave to people more familiar with this to do another review.

// when `StoreKit1Wrapper` is not initialized, which means that promoted purchases
// need to be handled as a SK2 purchase.
// This method converts the `SKPayment` into an SK2 purchase by fetching the product again.
assert(self.storeKit1Wrapper == nil, "This method should not be invoked if SK1 is enabled")
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we also log an error if this gets called for any reason with SK1 in release builds?

@NachoSoto NachoSoto force-pushed the promotional-app-store-purchase-sk1 branch 2 times, most recently from b9623f8 to 4e2f0d9 Compare September 15, 2022 18:01
…Store when SK1 is disabled

Follow up to #1882. After that PR, `StoreKit1Wrapper` was no longer listening to `SKPaymentQueueDelegate.paymentQueue(:shouldAddStorePayment:for:)`, which means that purchases initiated from the App Store were being ignored by the SDK if SK2 is enabled.

To fix this, `PaymentQueueWrapper` now becomes the `SKPaymentQueueDelegate` only when `StoreKit1Wrapper` is not initialized, and `PurchasesOrchestrator` initiates an SK2 purchase instead.

- `PurchasesOrchestrator` purchase methods no longer need the whole `PromotionalOffer`, only the `SignedData`. This allows the new implementation to create that data from only the `SKPaymentDiscount` provided from the `SKPayment`.

- [ ] Test that `StoreKit1Wrapper` is the delegate if SK1 is enabled
- [ ] Test that `PaymentQueueWrapper` is the delegate otherwise
- [ ] Test `PromotionalOffer.SignedData` initialization from SK1
- [ ] Test conversion of SK1 product to SK2.
@NachoSoto NachoSoto force-pushed the promotional-app-store-purchase-sk1 branch from 4e2f0d9 to 804f0ac Compare September 19, 2022 18:03
@NachoSoto NachoSoto merged commit 72a9f57 into main Sep 21, 2022
@NachoSoto NachoSoto deleted the promotional-app-store-purchase-sk1 branch September 21, 2022 19:03
NachoSoto added a commit that referenced this pull request Sep 27, 2022
**This is an automatic release.**

### New Features
* 🚨 `StoreKit 2` is now enabled by default 🚨 (#1922) via NachoSoto
(@NachoSoto)
* Extracted `PurchasesType` and `PurchasesSwiftType` (#1912) via
NachoSoto (@NachoSoto)
### Bugfixes
* `StoreKit 1`: changed result of cancelled purchases to be consistent
with `StoreKit 2` (#1910) via NachoSoto (@NachoSoto)
* `PaymentQueueWrapper`: handle promotional purchase requests from App
Store when SK1 is disabled (#1901) via NachoSoto (@NachoSoto)
### Other Changes
* Fixed iOS 12 tests (#1936) via NachoSoto (@NachoSoto)
* `CacheableNetworkOperation`: fixed race condition in new test (#1932)
via NachoSoto (@NachoSoto)
* `BasePurchasesTests`: changed default back to SK1 (#1935) via
NachoSoto (@NachoSoto)
* `Logger`: refactored default `LogLevel` definition (#1934) via
NachoSoto (@NachoSoto)
* `AppleReceipt`: refactored declarations into nested types (#1933) via
NachoSoto (@NachoSoto)
* `Integration Tests`: relaunch tests when retrying failures (#1925) via
NachoSoto (@NachoSoto)
* `CircleCI`: downgraded release jobs to Xcode 13.x (#1927) via
NachoSoto (@NachoSoto)
* `ErrorUtils`: added test to verify that `PublicError`s can be
`catch`'d as `ErrorCode` (#1924) via NachoSoto (@NachoSoto)
* `StoreKitIntegrationTests`: print `AppleReceipt` data whenever
`verifyEntitlementWentThrough` fails (#1929) via NachoSoto (@NachoSoto)
* `OperationQueue`: log debug message when requests are found in cache
and skipped (#1926) via NachoSoto (@NachoSoto)
* `GetCustomerInfoAPI`: avoid making a request if there's any
`PostReceiptDataOperation` in progress (#1911) via NachoSoto
(@NachoSoto)
* `PurchaseTester`: allow HTTP requests and enable setting `ProxyURL`
(#1917) via NachoSoto (@NachoSoto)
NachoSoto added a commit that referenced this pull request Sep 30, 2022
…aymentQueueDelegate` implementations

This way it's more clear which methods belong to which protocol.
This confusion is what lead to #1901 being wrong.
NachoSoto added a commit that referenced this pull request Sep 30, 2022
… to fix promoted purchases

Follow up to #1901. That fix was incomplete. I missed it because the protocols were mixed up (fixed in #1961).
Now `PaymentQueueWrapper`, when set up as the delegate (only when SK2 is enabled and SK1 is disabled) will be added as a transaction observer.
NachoSoto added a commit that referenced this pull request Oct 7, 2022
…aymentQueueDelegate` implementations (#1961)

This way it's more clear which methods belong to which protocol.
This confusion is what lead to #1901 being wrong (will fix in a separate
PR).
NachoSoto added a commit that referenced this pull request Oct 7, 2022
… to fix promoted purchases

Follow up to #1901. That fix was incomplete. I missed it because the protocols were mixed up (fixed in #1961).
Now `PaymentQueueWrapper`, when set up as the delegate (only when SK2 is enabled and SK1 is disabled) will be added as a transaction observer.
NachoSoto added a commit that referenced this pull request Oct 7, 2022
… to fix promoted purchases (#1962)

Follow up to #1901. That fix was incomplete. I missed it because the
protocols were mixed up (fixed in #1961). Now `PaymentQueueWrapper`,
when set up as the delegate (only when SK2 is enabled and SK1 is
disabled) will be added as a transaction observer.
NachoSoto added a commit that referenced this pull request Oct 7, 2022
…e` wrapper

This is a follow up to #1901 and #1882.
Essentially before this change, `Purchases` had both `StoreKit1Wrapper?` and a `PaymentQueueWrapper`. The later wasn't actually needed when the first was not-nil, so it was essentially storing `(a?, b?)`. What we really wanted to express is that it could have one OR the other.

This introduces `Either` to express this requirement in the type system, as well as `PaymentQueueWrapperType` that will be used to fix #1964.
NachoSoto added a commit that referenced this pull request Oct 10, 2022
…e` wrapper

This is a follow up to #1901 and #1882.
Essentially before this change, `Purchases` had both `StoreKit1Wrapper?` and a `PaymentQueueWrapper`. The later wasn't actually needed when the first was not-nil, so it was essentially storing `(a?, b?)`. What we really wanted to express is that it could have one OR the other.

This introduces `Either` to express this requirement in the type system, as well as `PaymentQueueWrapperType` that will be used to fix #1964.
NachoSoto added a commit that referenced this pull request Oct 11, 2022
…e` wrapper (#1968)

This is a follow up to #1901 and #1882. Depends on #1967.
Essentially before this change, `Purchases` had both `StoreKit1Wrapper?`
and a `PaymentQueueWrapper`. The later wasn't actually needed when the
first was not-nil, so it was essentially storing `(a?, b?)`. What we
really wanted to express is that it could have one OR the other.

This introduces `Either` to express this requirement in the type system,
as well as `PaymentQueueWrapperType` that will be used to fix #1964.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr:fix A bug fix
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants