Commit Graph
73 Commits
Author SHA1 Message Date
Josh Holtz fc2138249a [Paywalls V2] Implement V2 variables and functions (#4633)
* This mostly works

* This mostly works

* Better tests and logic

* More tests

* Fixed onemore

* lint

* Fix tests

* Actually use this

* Fix for all quantity translation things

* More minor fixes

* Fix tests
2025-01-08 09:17:34 -06:00
Will Taylor 6a363db8df make PurchaseParams & Win-Back APIs public 2024-11-19 13:18:21 -06:00
Will Taylor d23fa7fae2 support redeeming winbacks offer with developer-built paywalls 2024-11-13 11:48:53 -06:00
Will Taylor 6de169a23e support fetching eligible win-back offers for a product 2024-11-06 15:46:04 -06:00
Toni Rico e73f10244d Round price per period calculations to nearest 2-decimal (#4275)
* Round price per period calculations to nearest 2-decimal

* Fix tests

* Update snapshots commit
2024-09-17 10:31:02 +02:00
dd0ee262ea [Customer Center] Initial implementation (#3967)
Alpha of the Customer Center. In this branch, it's been disabled behind
a compilation flag.

---------

Co-authored-by: Will Taylor <wtaylor151@gmail.com>
Co-authored-by: James Borthwick <109382862+jamesrb1@users.noreply.github.com>
Co-authored-by: RevenueCat Git Bot <72824662+RCGitBot@users.noreply.github.com>
Co-authored-by: JayShortway <29483617+JayShortway@users.noreply.github.com>
Co-authored-by: Toni Rico <toni.rico.diez@revenuecat.com>
Co-authored-by: Toni Rico <antonio.rico.diez@revenuecat.com>
Co-authored-by: Cody Kerns <44073103+codykerns@users.noreply.github.com>
Co-authored-by: Andy Boedo <andresboedo@gmail.com>
2024-08-09 15:26:55 +02:00
NachoSoto 2bcd0ce328 5.0.0 changes: support SK2 by default 2024-07-01 14:37:21 -05:00
Josh Holtz c6e185ff07 Only install swiftlint on Xcode 15 jobs (#3913)
### Motivation

Better implementation of
https://github.com/RevenueCat/purchases-ios/pull/3909 and what was just
commited to `5.0-dev`

### Description

- Only install `swiftlint` on Xcode 15.3 jobs
- Also moved Ruby 3.2.2 install into `install-bundle-dependencies` which
was also done in `5.0-dev`
2024-05-18 08:21:02 -05:00
Andy BoedoandNachoSoto 4cc7d51f70 StoreProduct: add localized price per period strings (#3546)
Added `localizedPricePerWeek`, `localizedPricePerMonth` and
`localizedPricePerYear`.

I started on this before noticing that we already [have an equivalent at
the package
level](https://github.com/RevenueCat/purchases-ios/blob/main/RevenueCatUI/Helpers/Package%2BVariableDataProvider.swift#L107),
still need to unify them.

---------

Co-authored-by: NachoSoto <ignaciosoto90@gmail.com>
2024-01-16 16:00:15 -08:00
32c63cdb46 [SK2] Add support for StoreKit Config files in SK2 (#3365)
When using StoreKit Config file, we do not have access to the
transaction history or subscription status server-side.

To work around this, we introduce a new `StoreKit2Receipt` type that
closely resembles the structure of an SK1 receipt and contains all the
transaction history and subscription status for the customer. It can be
sent in a single request to `/receipt`

---------

Co-authored-by: RevenueCat Git Bot <72824662+RCGitBot@users.noreply.github.com>
Co-authored-by: Distiller <distiller@static.38.39.183.137.cyberlynk.net>
Co-authored-by: Distiller <distiller@static.38.23.40.89.cyberlynk.net>
Co-authored-by: Distiller <distiller@static.38.39.185.65.cyberlynk.net>
Co-authored-by: NachoSoto <NachoSoto@users.noreply.github.com>
2023-12-13 17:00:37 +01:00
NachoSoto 0e39c79bd9 StoreProduct: improve priceFormatter documentation (#3500) 2023-12-10 22:27:52 -08:00
Toni Rico 4f80eda386 Improve pricePerYear price calculation precision (#3492)
### Description
Followup to #3480 

This slightly improves precision when calculating price per year for
weekly subscriptions.
2023-12-05 15:41:30 +01:00
Andy Boedo ad0f9d93ab Improve price per month accuracy for weekly subscriptions (#3480)
We were calculating the price per month for weekly products as price *
4, but there are on average 4.345 weeks in a month, so this updates the
value accordingly.
2023-12-05 14:01:52 +01:00
NachoSoto e31a531ca1 HTTPClient: test all request headers (#3425)
This allows us to verify exactly what headers are included in all
requests.

It also simplifies the implementation for #3424.
2023-11-17 12:19:49 -08:00
Mark Villacampa 679767adf9 Enable explicit_init lint rule and fix issues (#3418)
This rule will warn when calling `init` with the explicit type where it
can be inferred, or where the `.init` part can be omitted.
2023-11-16 00:20:00 +01:00
Josh HoltzandNachoSoto 7d78633fd8 Adds X-Storefront request header for App Store Storefront (#3405)
### Motivation

Allow backend to determine Storefront of customer

### Description

- Adds `X-Storefront` as a default header
- Uses `StoreKit 1` implementation since its not `async`
- `StoreKit 2` implementation is `async` and would require a some
restructuring that we don't need right now

---------

Co-authored-by: NachoSoto <ignaciosoto90@gmail.com>
2023-11-14 14:04:07 -08:00
NachoSoto 725d3fa827 Add StoreProduct.pricePerWeek (#3354)
This will be used to offer a new paywalls variable.
2023-11-01 08:33:44 -07:00
235a7dcdc1 StoreKit 2: Optionally send JWS tokens instead of receipts to the backend (#3227)
- Added a new option `usesStoreKit2JWS` under `DangerousSettings`. If
enabled, the SDK will send a JWS token instead of a receipt to the
applicable backend endpoints.
- The option must be used in conjunction with `usesStoreKit2IfAvailable`
configuration option.

### ToDo

- [x] Send JWS token when making a purchase in SK2 mode
- [x] Send JWS token when calculating promo offer eligibility
- [x] Update `syncTransactions` to send the latest transaction JWS.
- [x] Add tests

---------

Co-authored-by: RevenueCat Git Bot <72824662+RCGitBot@users.noreply.github.com>
Co-authored-by: Distiller <distiller@static.38.39.183.118.cyberlynk.net>
Co-authored-by: Distiller <distiller@static.198.206.135.125.macminivault.com>
Co-authored-by: Distiller <distiller@static.38.23.39.112.cyberlynk.net>
Co-authored-by: Distiller <distiller@static.38.39.183.58.cyberlynk.net>
Co-authored-by: Distiller <distiller@static.38.39.185.87.cyberlynk.net>
2023-10-16 22:45:29 +02:00
NachoSoto 5db3bcb895 SK2StoreProduct.priceFormatter: use locale from StoreKit.Product (#3278)
This only works in iOS 16+ (because it needs
`StoreKit.Product.priceFormatStyle`), but it's a good improvement which
ensures consistent formatting of prices in paywalls, where sometimes
`StoreProduct.localizedPrice` would have a different format compared to
formatting `pricePerMonth` using `StoreProduct.priceFormatter`.
2023-10-05 10:15:37 -07:00
NachoSoto a08b0b3da4 Paywalls: support fuzzy-Locale search in iOS 15 (#3162)
See #2847.

Thanks to @vegaro for pointing this out.

Also removed all checks for Xcode 13 (see #3161 and #3147).
2023-09-14 18:28:11 -07:00
NachoSoto 1f095727d1 TestStoreProduct: new locale parameter (#3134)
This allows overriding the `Locale` to be used for this test product,
which is used to configure the price formatter.
This will be used by #3133.
2023-09-14 18:28:11 -07:00
NachoSoto 2e0feffe6a Xcode 13: removed last Swift 5.7 checks (#3161) 2023-09-08 07:27:11 -07:00
NachoSoto 82435936d9 Xcode 13: remove conditional code (#3147)
Clean up thanks to #2421
2023-09-06 10:59:22 -07:00
NachoSoto 5d3263c8e6 TransactionPoster: don't finish transactions for non-subscriptions if they're not processed (#2841) 2023-08-15 07:05:00 -07:00
NachoSoto 216f1e13c3 PurchasesOrchestrator: disambiguate transactions from the queue (#2890)
This adds tests and a fix for a scenario discovered by @aboedo and
@mcastany.

### Timeline:
- Make a purchase of product_1
- Close app
- Renewals happen in the background
- Subscription expires
- Open app, renewals are in the queue but not processed yet
- Start a purchase of `product_1` (`SKPaymentQueue.add`)
- StoreKit queue shows renewal from step 3 as finished, it's expired
- SDK sees finished transaction in the queue for `product_1`
- SDK sees completion block for `product_1`, considers it a successful
`.purchase`
- SDK posts receipt, `initiation_source: .purchase` 💥
- Backend replies with 422 because StoreKit hasn't processed the
transaction from 6

### Fix:
The fix looks at the date when the completion block was added (the time
`.purchase()` is called).
If the transaction was created _before_ this, we know it didn't come
from the actual purchase, and therefore it should be identified as
`.queue`.
2023-08-07 15:57:10 -07:00
NachoSoto f4fa4d2d29 SK1StoreProduct: changed productType warning to debug (#2957)
See
https://community.revenuecat.com/sdks-51/purchases-purchasepackage-doesn-t-return-1956?postid=10251#post10251
Because hybrids proactively call this method to construct the internal
representation, it gets logged automatically whether they call it or
not,.

It's still useful, but making it a warning makes it seem more of a bug.
2023-08-03 12:05:57 -07:00
NachoSoto 6776347b44 TestStoreProduct: made available on release builds (#2861) 2023-07-25 00:07:27 +02:00
NachoSoto 761ca1209d New TestStoreProduct for creating mock StoreProducts and Offerings (#2711)
Fixes #1563 and #2193.

This introduces **`DEBUG` and `Swift` only** types that allow creating a
whole `Offering` for tests and SwiftUI previews.

Example:
![Screenshot 2023-06-26 at 12 36
40](https://github.com/RevenueCat/purchases-ios/assets/685609/03d83e65-b95b-40ba-80ad-f8be435c6d3e)

By making it available in only `DEBUG` builds we ensure that apps can't
accidentally try to purchase these products, which would be impossible.
If this is attempted in `DEBUG` builds, we return `ErrorCode`.

When trying to compile this API in release builds, you get an error with
a suggestion:

![image](https://github.com/RevenueCat/purchases-ios/assets/685609/f83b8848-dab6-4ae6-a92d-5c07a30be217)
2023-06-29 14:06:24 -07:00
NachoSoto 6d60af2c42 Xcode 15: handle Locale.currencyCode deprecation (#2680) 2023-06-22 06:23:32 -07:00
NachoSoto 01ed2cb2cf StoreTransaction: read Storefront from StoreKit.Transaction (#2611)
This was added in iOS 17, and it's potentially more accurate than
reading `Storefront.currentStorefront` later.
2023-06-12 09:35:04 -07:00
NachoSoto e6444e2cee StoreProductDiscount: added description (#2604) 2023-06-09 07:42:10 -07:00
NachoSoto 6d9594ea06 Xcode 15: fixed all documentation warnings (#2596) 2023-06-08 08:36:28 -07:00
NachoSoto c6de563b68 SK2StoreProduct: fix crash on iOS 12 (#2565) 2023-05-30 13:09:25 -07:00
NachoSoto 43178d89fc StoreTransaction: implemented description (#2556) 2023-05-30 06:49:19 -07:00
NachoSoto c390a66014 SK2StoreProduct: simplify currencyCode extraction (#2485)
I noticed this new property thanks to [this
tweet](https://twitter.com/ariskox/status/1658067009609904129?s=61&t=Zz639sMJdwHISm4AKYXoCw).

This changes the "future" implementation of
`SK2StoreProduct.currencyCode` to use [the new (backdeployed)
property](https://developer.apple.com/documentation/storekit/product/4044347-priceformatstyle).
We still need the existing implementation because `@_backDeploy` won't
work if compiling with `Xcode 13.x`.
2023-05-23 14:33:42 -07:00
NachoSoto 3f08a95c73 Add StoreProduct.pricePerYear (#2462) 2023-05-11 10:15:57 -07:00
NachoSotoandToni Rico 4a74d33f84 Custom Entitlement Computation: disabled unnecessary APIs (#2442)
## Disabled API:

- `getCustomerInfo`
- `logIn`
- `logOut`
- `Purchases.attribution`
- `syncPurchases`
- `restorePurchases`
- Trial eligibility
- Promotional purchases
- `async` counterparts

---------

Co-authored-by: Toni Rico <antonio.rico.diez@revenuecat.com>
2023-04-26 14:51:40 -03:00
NachoSoto 2fff5b0b75 CI: also run tests on watchOS (#2340)
This is a follow up to #717.
In order to be able to reproduce #2338, which seems to be an issue only
on `watchOS`, it's important that we now run tests on `watchOS` as well.
We probably won't be able to fully replicate that issue since we don't
run tests on actual devices, so they'll still run on 64 bits. But this
way we might be able to prevent issues that are only reproducible on
`watchOS` in the future.

## Changes:
- Added CircleCI job
- Added lane
- Simplified `UnitTestsHostApp` definition using `SwiftUI`
- Increased _test only_ `watchOS` deployment target to 7.0 (this was
necessary to be able to have a common `@main` for the host app)
- Increased _test only_ `tvOS` deployment target to `14.0` (same as
above, plus we only run tvOS tests on the latest version anyway. We test
backwards compatibility through iOS already)
- Fixed test compilation on `watchOS`
- Disabled `HTTPClient` tests on `watchOS` (see
https://github.com/AliSoftware/OHHTTPStubs/issues/287)
- `StoreKitConfigTestCase` is only available from `watchOS 7.0` since
that's when `SKTestSession` was introduced
- Added `watchOS` support to `UnitTests` target
- Added `watchOS` support to `ReceiptParserTests` target
- Fixed `isFamilySharable` `watchOS` version checks for version 8.0
- Created new `CI-RevenueCat` Test Plan to only run unit tests and not
StoreKit tests on `watchOS`
2023-03-16 13:11:24 -07:00
Andy Boedo fdfece85b6 clarifies error messages for storekit 1 bugs (#2294)
We have a few error messages for StoreKit 1 bugs that look pretty scary.

However, they really aren't - while they surface genuine bugs in
StoreKit, they require no action on the developer's side, and our
backend won't be affected. So in practice, they're not useful.

This PR updates the copy so that: 
- it doesn't suggest using SK2
- it moves from `warn` to `verbose`, since there's really no action on
the developer's side needed
- it clarifies what's going on under the hood



| Before | After |
| :-: | :-: |
| <img width="1311" alt="Screenshot 2023-02-17 at 3 43 02 PM"
src="https://user-images.githubusercontent.com/3922667/219758984-c9593d12-23fb-4076-ab87-2c5454f7084b.png">
| <img width="1304" alt="Screenshot 2023-02-17 at 3 52 05 PM"
src="https://user-images.githubusercontent.com/3922667/219759107-9abdb01b-f626-41de-b20c-a08bbd6c1c05.png">
|
2023-02-17 15:05:37 -08:00
NachoSoto 32d10a9fbd StoreKit2StorefrontListener: added tests to fix flaky code coverage (#2265)
Similarly to #2262, test execution ordering was leading to [flaky code
coverage
results](https://app.codecov.io/gh/RevenueCat/purchases-ios/pull/2262)
with this.

![Screenshot 2023-02-06 at 10 48
45](https://user-images.githubusercontent.com/685609/217058841-33a07262-7959-4732-9706-7426d8f4efb7.png)

Because we didn't have any test coverage, only if some other test
changed the `Storefront`, this test was calling the delegate code.

This adds explicit test coverage using a `MockAsyncSequence`.

### Other changes:
- Added `StorefrontType` to `StoreKit2StorefrontListenerDelegate` method
- `Storefront` initializers are no longer `Optional` `init?`
- Simplified `StoreKit2StorefrontListenerTests` by moving
`AvailabilityChecks` to `setUp`
2023-02-08 12:45:08 -08:00
NachoSoto cf3090a858 Replaced Any uses for workaround with Box (#2250) 2023-02-07 06:51:29 -08:00
NachoSoto 1b13754ca2 Fixed race condition finishing SK1 transactions (#2148)
Fixes [CSDK-504].

`SKPaymentQueue.finishTransaction` is asynchronous, but we were assuming
it wasn't.
This meant that when performing multiple purchases (like consumables) in
quick succession, before the first transaction was finished, the second
purchase was reusing the first transaction.

Example log:
```
[Purchases] - INFO: 💰 Finishing transaction ‘0’ for product ‘consumable.10_coins’
[Purchases] - INFO: 😻💰 Purchased product - ‘consumable.10_coins’
[Purchases] - INFO: 💰 Purchasing Product ‘consumable.10_coins’ from package in Offering ‘coins’
[Purchases] - DEBUG: ℹ️ StoreKit1Wrapper (0x00006000008a9530) removedTransaction: consumable.10_coins 0 1
```

Notice how the "removed transaction" was notified _after_ we had already
started the second purchase.

See also #2148 for an earlier fix for finishing transactions.

[CSDK-504]:
https://revenuecats.atlassian.net/browse/CSDK-504?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
2022-12-21 08:17:07 -08:00
NachoSoto 8e32400c4e Fixed purchasing with PromotionalOffers using StoreKit 2 (#2020)
Fixes [SDKONCALL-160], [SDKONCALL-182], #2114, and
https://github.com/RevenueCat/react-native-purchases/issues/455.
Depends on #2118 and https://github.com/RevenueCat/khepri/pull/4843 /
https://github.com/RevenueCat/khepri/pull/4852.

## Changes:
- Base64decode `signature`
- Fixed signature on backend for SK2:
https://github.com/RevenueCat/khepri/pull/4843 /
https://github.com/RevenueCat/khepri/pull/4852
- Added tests
- Added specific error if signature can't be decoded:
> [Purchases] - ERROR: 😿‼️ The information associated with this
PromotionalOffer is not valid.
See https://rev.cat/ios-subscription-offers for more info. The signature
generated by RevenueCat could not be decoded: signature 914

[SDKONCALL-160]:
https://revenuecats.atlassian.net/browse/SDKONCALL-160?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

[SDKONCALL-182]:
https://revenuecats.atlassian.net/browse/SDKONCALL-182?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
2022-12-09 15:04:29 -08:00
Bas Broek 70209e58dc Fix documentation typo (#2113)
<!-- Thank you for contributing to Purchases! Before pressing the
"Create Pull Request" button, please provide the following: -->

### Checklist
- [ ] If applicable, unit tests
- [ ] If applicable, create follow-up issues for `purchases-android` and
hybrids

### Motivation
<!-- Why is this change required? What problem does it solve? -->
<!-- Please link to issues following this format: Resolves #999999 -->
Just a documentation header typo :)

### Description
<!-- Describe your changes in detail -->
<!-- Please describe in detail how you tested your changes -->
`ccurrency` -> `currency`
2022-12-02 14:31:57 -03:00
NachoSoto 70365df383 Purchasing: fixed consumable purchases by fixing transaction-finishing (#1965)
Fixes #1964, [TRIAGE-134], [TRIAGE-131], and possibly [TRIAGE-82].

Depends on #1967, #1968.

### Fixes:
- For `SK2` purchases we were never finishing transactions. We are now.
- For `SK1` purchases, transactions were finished _after_ the completion
block was invoked (and tests were very lenient checking that
_eventually_ this happened). This could have lead to race conditions.
- For SK2 only (at least in `SKTestSession`s), this fixes the ability to
purchase multiple consumable purchases.

This is the log from the failing test using SK2:
<details>
  <summary>Open</summary>

```
2022-10-06 15:18:52.286813-0700 BackendIntegrationTestsHostApp[45464:7076968] [Purchases] - DEBUG: ℹ️ API request started: GET /v1/subscribers/$RCAnonymousID:6f630d50b8294288a2d0862629d766fb/offerings
2022-10-06 15:18:52.383594-0700 BackendIntegrationTestsHostApp[45464:7076968] [Purchases] - DEBUG: ℹ️ API request completed: GET /v1/subscribers/$RCAnonymousID:6f630d50b8294288a2d0862629d766fb/offerings 200
2022-10-06 15:18:52.388247-0700 BackendIntegrationTestsHostApp[45464:7076968] [Purchases] - DEBUG: ℹ️ No existing products cached, starting store products request for: ["com.revenuecat.weekly_1.99.3_day_intro", "consumable.10_coins", "com.revenuecat.annual_39.99.2_week_intro", "com.revenuecat.monthly_4.99.1_week_intro"]
2022-10-06 15:18:52.388382-0700 BackendIntegrationTestsHostApp[45464:7076968] [Purchases] - DEBUG: ℹ️ Found an existing request for products: ["com.revenuecat.monthly_4.99.1_week_intro", "com.revenuecat.annual_39.99.2_week_intro", "com.revenuecat.weekly_1.99.3_day_intro", "consumable.10_coins"], appending to completion
2022-10-06 15:18:52.388451-0700 BackendIntegrationTestsHostApp[45464:7076968] [Purchases] - DEBUG: ℹ️ GetOfferingsOperation: Finished
2022-10-06 15:18:52.388560-0700 BackendIntegrationTestsHostApp[45464:7076968] [Purchases] - DEBUG: ℹ️ Serial request done: GET subscribers/$RCAnonymousID%3A6f630d50b8294288a2d0862629d766fb/offerings, 0 requests left in the queue
2022-10-06 15:18:52.420210-0700 BackendIntegrationTestsHostApp[45464:7076968] [Purchases] - DEBUG: 😻 Store products request request received response
2022-10-06 15:18:52.420358-0700 BackendIntegrationTestsHostApp[45464:7076968] [Purchases] - DEBUG: ℹ️ Store products request finished
2022-10-06 15:18:52.421126-0700 BackendIntegrationTestsHostApp[45464:7076978] [Purchases] - DEBUG: ℹ️ Vending Offerings from cache
2022-10-06 15:18:52.421353-0700 BackendIntegrationTestsHostApp[45464:7076968] [Purchases] - INFO: 💰 Purchasing Product 'consumable.10_coins' from package in Offering 'coins'
2022-10-06 15:18:52.496438-0700 BackendIntegrationTestsHostApp[45464:7076968] [Purchases] - DEBUG: ℹ️ Force refreshing the receipt to get latest transactions from Apple.
2022-10-06 15:18:52.510974-0700 BackendIntegrationTestsHostApp[45464:7076903] [Purchases] - DEBUG: ℹ️ Loaded receipt from url file:///Users/nachosoto/Library/Developer/CoreSimulator/Devices/A3576DC2-355E-45BA-B32C-D2C0A3811BB4/data/Containers/Data/Application/BFD385C4-52BC-414B-9C1C-44522ED1222F/StoreKit/receipt
2022-10-06 15:18:52.511072-0700 BackendIntegrationTestsHostApp[45464:7076903] [Purchases] - DEBUG: ℹ️ Skipping products request because products were already cached. products: ["consumable.10_coins"]
2022-10-06 15:18:52.511181-0700 BackendIntegrationTestsHostApp[45464:7076903] [Purchases] - DEBUG: ℹ️ Skipping products request because products were already cached. products: ["consumable.10_coins"]
2022-10-06 15:18:52.511564-0700 BackendIntegrationTestsHostApp[45464:7076903] [Purchases] - DEBUG: ℹ️ Found 0 unsynced attributes for App User ID: $RCAnonymousID:6f630d50b8294288a2d0862629d766fb
2022-10-06 15:18:52.515448-0700 BackendIntegrationTestsHostApp[45464:7076978] [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Started
2022-10-06 15:18:52.516403-0700 BackendIntegrationTestsHostApp[45464:7076978] [Purchases] - INFO: ℹ️ Receipt parsed successfully
2022-10-06 15:18:52.516763-0700 BackendIntegrationTestsHostApp[45464:7076978] [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Posting receipt: {
  "opaque_value" : "oX91ewAAAAA=",
  "sha1_hash" : "GsyNpUKQ89SonYyj\/jpw8\/N5nr8=",
  "bundle_id" : "com.revenuecat.StoreKitTestApp",
  "in_app_purchases" : [
    {
      "quantity" : 1,
      "product_id" : "consumable.10_coins",
      "purchase_date" : "2022-10-06T22:18:52Z",
      "transaction_id" : "0"
    }
  ],
  "application_version" : "1",
  "creation_date" : "2022-10-06T22:18:52Z",
  "expiration_date" : "4001-01-01T00:00:00Z"
}
2022-10-06 15:18:52.516825-0700 BackendIntegrationTestsHostApp[45464:7076978] [Purchases] - DEBUG: ℹ️ There are no requests currently running, starting request POST receipts
2022-10-06 15:18:52.518059-0700 BackendIntegrationTestsHostApp[45464:7076978] [Purchases] - DEBUG: ℹ️ API request started: POST /v1/receipts
2022-10-06 15:18:52.960048-0700 BackendIntegrationTestsHostApp[45464:7076966] [Purchases] - DEBUG: ℹ️ API request completed: POST /v1/receipts 200
2022-10-06 15:18:52.964274-0700 BackendIntegrationTestsHostApp[45464:7076966] [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Finished
2022-10-06 15:18:52.964666-0700 BackendIntegrationTestsHostApp[45464:7076966] [Purchases] - DEBUG: ℹ️ Serial request done: POST receipts, 0 requests left in the queue
2022-10-06 15:18:52.966476-0700 BackendIntegrationTestsHostApp[45464:7076903] [Purchases] - DEBUG: ℹ️ Sending updated CustomerInfo to delegate.
2022-10-06 15:18:52.966697-0700 BackendIntegrationTestsHostApp[45464:7076966] [Purchases] - INFO: 😻💰 Purchased product - 'consumable.10_coins'
2022-10-06 15:18:52.966973-0700 BackendIntegrationTestsHostApp[45464:7076966] [Purchases] - DEBUG: ℹ️ Vending Offerings from cache
2022-10-06 15:18:52.967284-0700 BackendIntegrationTestsHostApp[45464:7076966] [Purchases] - INFO: 💰 Purchasing Product 'consumable.10_coins' from package in Offering 'coins'
2022-10-06 15:18:52.991334-0700 BackendIntegrationTestsHostApp[45464:7076973] [Purchases] - DEBUG: ℹ️ Force refreshing the receipt to get latest transactions from Apple.
2022-10-06 15:18:53.015046-0700 BackendIntegrationTestsHostApp[45464:7076903] [Purchases] - DEBUG: ℹ️ Loaded receipt from url file:///Users/nachosoto/Library/Developer/CoreSimulator/Devices/A3576DC2-355E-45BA-B32C-D2C0A3811BB4/data/Containers/Data/Application/BFD385C4-52BC-414B-9C1C-44522ED1222F/StoreKit/receipt
2022-10-06 15:18:53.015174-0700 BackendIntegrationTestsHostApp[45464:7076903] [Purchases] - DEBUG: ℹ️ Skipping products request because products were already cached. products: ["consumable.10_coins"]
2022-10-06 15:18:53.015262-0700 BackendIntegrationTestsHostApp[45464:7076903] [Purchases] - DEBUG: ℹ️ Skipping products request because products were already cached. products: ["consumable.10_coins"]
2022-10-06 15:18:53.015419-0700 BackendIntegrationTestsHostApp[45464:7076903] [Purchases] - DEBUG: ℹ️ Found 0 unsynced attributes for App User ID: $RCAnonymousID:6f630d50b8294288a2d0862629d766fb
2022-10-06 15:18:53.015927-0700 BackendIntegrationTestsHostApp[45464:7076966] [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Started
2022-10-06 15:18:53.016558-0700 BackendIntegrationTestsHostApp[45464:7076966] [Purchases] - INFO: ℹ️ Receipt parsed successfully
2022-10-06 15:18:53.016727-0700 BackendIntegrationTestsHostApp[45464:7076966] [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Posting receipt: {
  "opaque_value" : "LP9LZQwAAAA=",
  "sha1_hash" : "WdANBTWr7wYWh8RYEgmGebO8DR8=",
  "bundle_id" : "com.revenuecat.StoreKitTestApp",
  "in_app_purchases" : [
    {
      "quantity" : 1,
      "product_id" : "consumable.10_coins",
      "purchase_date" : "2022-10-06T22:18:52Z",
      "transaction_id" : "0"
    }
  ],
  "application_version" : "1",
  "creation_date" : "2022-10-06T22:18:53Z",
  "expiration_date" : "4001-01-01T00:00:00Z"
}
2022-10-06 15:18:53.016783-0700 BackendIntegrationTestsHostApp[45464:7076966] [Purchases] - DEBUG: ℹ️ There are no requests currently running, starting request POST receipts
2022-10-06 15:18:53.017602-0700 BackendIntegrationTestsHostApp[45464:7076966] [Purchases] - DEBUG: ℹ️ API request started: POST /v1/receipts
2022-10-06 15:18:53.411689-0700 BackendIntegrationTestsHostApp[45464:7076978] [Purchases] - DEBUG: ℹ️ API request completed: POST /v1/receipts 200
2022-10-06 15:18:53.413980-0700 BackendIntegrationTestsHostApp[45464:7076978] [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Finished
2022-10-06 15:18:53.414147-0700 BackendIntegrationTestsHostApp[45464:7076978] [Purchases] - DEBUG: ℹ️ Serial request done: POST receipts, 0 requests left in the queue
2022-10-06 15:18:53.414927-0700 BackendIntegrationTestsHostApp[45464:7076978] [Purchases] - INFO: 😻💰 Purchased product - 'consumable.10_coins'
2022-10-06 15:18:53.415505-0700 BackendIntegrationTestsHostApp[45464:7076978] [Purchases] - DEBUG: ℹ️ Vending CustomerInfo from cache.
```
</details>

With the fix, you can see transactions are now finished at the right
time:
<details>
  <summary>Open</summary>

```
2022-10-07 11:08:01.967843-0700 BackendIntegrationTestsHostApp[45714:674592] [Purchases] - INFO: 💰 Purchasing Product 'consumable.10_coins' from package in Offering 'coins'
2022-10-07 11:08:02.123611-0700 BackendIntegrationTestsHostApp[45714:674592] [Purchases] - DEBUG: ℹ️ Force refreshing the receipt to get latest transactions from Apple.
2022-10-07 11:08:02.138918-0700 BackendIntegrationTestsHostApp[45714:674399] [Purchases] - DEBUG: ℹ️ Loaded receipt from url file:///Users/nachosoto/Library/Developer/CoreSimulator/Devices/F02A9A20-949B-4C9D-A01E-AB0CC7544F96/data/Containers/Data/Application/C52A5EFD-733F-46EC-84B7-734B6AF9D28C/StoreKit/receipt
2022-10-07 11:08:02.139013-0700 BackendIntegrationTestsHostApp[45714:674399] [Purchases] - DEBUG: ℹ️ Skipping products request because products were already cached. products: ["consumable.10_coins"]
2022-10-07 11:08:02.139095-0700 BackendIntegrationTestsHostApp[45714:674399] [Purchases] - DEBUG: ℹ️ Skipping products request because products were already cached. products: ["consumable.10_coins"]
2022-10-07 11:08:02.139481-0700 BackendIntegrationTestsHostApp[45714:674399] [Purchases] - DEBUG: ℹ️ Found 0 unsynced attributes for App User ID: $RCAnonymousID:bd74b9d10f2c48eea1d741a32f5acb16
2022-10-07 11:08:02.147220-0700 BackendIntegrationTestsHostApp[45714:674592] [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Started
2022-10-07 11:08:02.148192-0700 BackendIntegrationTestsHostApp[45714:674592] [Purchases] - INFO: ℹ️ Receipt parsed successfully
2022-10-07 11:08:02.148552-0700 BackendIntegrationTestsHostApp[45714:674592] [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Posting receipt: {
  "opaque_value" : "\/3nevQ0AAAA=",
  "sha1_hash" : "\/bAkxLQ6BPgUg3rR9jDR28dEfig=",
  "bundle_id" : "com.revenuecat.StoreKitTestApp",
  "in_app_purchases" : [
    {
      "quantity" : 1,
      "product_id" : "consumable.10_coins",
      "purchase_date" : "2022-10-07T18:08:02Z",
      "transaction_id" : "0"
    }
  ],
  "application_version" : "1",
  "creation_date" : "2022-10-07T18:08:02Z",
  "expiration_date" : "4001-01-01T00:00:00Z"
}
2022-10-07 11:08:02.148604-0700 BackendIntegrationTestsHostApp[45714:674592] [Purchases] - DEBUG: ℹ️ There are no requests currently running, starting request POST receipts
2022-10-07 11:08:02.149748-0700 BackendIntegrationTestsHostApp[45714:674592] [Purchases] - DEBUG: ℹ️ API request started: POST /v1/receipts
2022-10-07 11:08:02.733225-0700 BackendIntegrationTestsHostApp[45714:674602] [Purchases] - DEBUG: ℹ️ API request completed: POST /v1/receipts 200
2022-10-07 11:08:02.734687-0700 BackendIntegrationTestsHostApp[45714:674602] [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Finished
2022-10-07 11:08:02.734802-0700 BackendIntegrationTestsHostApp[45714:674602] [Purchases] - DEBUG: ℹ️ Serial request done: POST receipts, 0 requests left in the queue
2022-10-07 11:08:02.735631-0700 BackendIntegrationTestsHostApp[45714:674399] [Purchases] - DEBUG: ℹ️ Sending updated CustomerInfo to delegate.
2022-10-07 11:08:02.735700-0700 BackendIntegrationTestsHostApp[45714:674399] [Purchases] - INFO: 💰 Finishing transaction '0' for product 'consumable.10_coins'
2022-10-07 11:08:02.760613-0700 BackendIntegrationTestsHostApp[45714:674592] [Purchases] - INFO: 😻💰 Purchased product - 'consumable.10_coins'
2022-10-07 11:08:02.760828-0700 BackendIntegrationTestsHostApp[45714:674590] [Purchases] - DEBUG: ℹ️ Vending Offerings from cache
2022-10-07 11:08:02.761032-0700 BackendIntegrationTestsHostApp[45714:674590] [Purchases] - INFO: 💰 Purchasing Product 'consumable.10_coins' from package in Offering 'coins'
2022-10-07 11:08:02.820835-0700 BackendIntegrationTestsHostApp[45714:674589] [Purchases] - DEBUG: ℹ️ Force refreshing the receipt to get latest transactions from Apple.
2022-10-07 11:08:02.839184-0700 BackendIntegrationTestsHostApp[45714:674399] [Purchases] - DEBUG: ℹ️ Loaded receipt from url file:///Users/nachosoto/Library/Developer/CoreSimulator/Devices/F02A9A20-949B-4C9D-A01E-AB0CC7544F96/data/Containers/Data/Application/C52A5EFD-733F-46EC-84B7-734B6AF9D28C/StoreKit/receipt
2022-10-07 11:08:02.839275-0700 BackendIntegrationTestsHostApp[45714:674399] [Purchases] - DEBUG: ℹ️ Skipping products request because products were already cached. products: ["consumable.10_coins"]
2022-10-07 11:08:02.839348-0700 BackendIntegrationTestsHostApp[45714:674399] [Purchases] - DEBUG: ℹ️ Skipping products request because products were already cached. products: ["consumable.10_coins"]
2022-10-07 11:08:02.839476-0700 BackendIntegrationTestsHostApp[45714:674399] [Purchases] - DEBUG: ℹ️ Found 0 unsynced attributes for App User ID: $RCAnonymousID:bd74b9d10f2c48eea1d741a32f5acb16
2022-10-07 11:08:02.839911-0700 BackendIntegrationTestsHostApp[45714:674589] [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Started
2022-10-07 11:08:02.840457-0700 BackendIntegrationTestsHostApp[45714:674589] [Purchases] - INFO: ℹ️ Receipt parsed successfully
2022-10-07 11:08:02.840603-0700 BackendIntegrationTestsHostApp[45714:674589] [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Posting receipt: {
  "opaque_value" : "fXr9\/QYAAAA=",
  "sha1_hash" : "zreYwGKGSaOEww1bsTRu8MylAas=",
  "bundle_id" : "com.revenuecat.StoreKitTestApp",
  "in_app_purchases" : [
    {
      "quantity" : 1,
      "product_id" : "consumable.10_coins",
      "purchase_date" : "2022-10-07T18:08:02Z",
      "transaction_id" : "1"
    }
  ],
  "application_version" : "1",
  "creation_date" : "2022-10-07T18:08:02Z",
  "expiration_date" : "4001-01-01T00:00:00Z"
}
2022-10-07 11:08:02.840662-0700 BackendIntegrationTestsHostApp[45714:674589] [Purchases] - DEBUG: ℹ️ There are no requests currently running, starting request POST receipts
2022-10-07 11:08:02.841268-0700 BackendIntegrationTestsHostApp[45714:674589] [Purchases] - DEBUG: ℹ️ API request started: POST /v1/receipts
2022-10-07 11:08:03.313116-0700 BackendIntegrationTestsHostApp[45714:674589] [Purchases] - DEBUG: ℹ️ API request completed: POST /v1/receipts 200
2022-10-07 11:08:03.316115-0700 BackendIntegrationTestsHostApp[45714:674589] [Purchases] - DEBUG: ℹ️ PostReceiptDataOperation: Finished
2022-10-07 11:08:03.316342-0700 BackendIntegrationTestsHostApp[45714:674589] [Purchases] - DEBUG: ℹ️ Serial request done: POST receipts, 0 requests left in the queue
2022-10-07 11:08:03.317444-0700 BackendIntegrationTestsHostApp[45714:674399] [Purchases] - DEBUG: ℹ️ Sending updated CustomerInfo to delegate.
2022-10-07 11:08:03.317527-0700 BackendIntegrationTestsHostApp[45714:674399] [Purchases] - INFO: 💰 Finishing transaction '1' for product 'consumable.10_coins'
2022-10-07 11:08:03.342767-0700 BackendIntegrationTestsHostApp[45714:674602] [Purchases] - INFO: 😻💰 Purchased product - 'consumable.10_coins'
```

</details>

[TRIAGE-134]:
https://revenuecats.atlassian.net/browse/TRIAGE-134?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
[TRIAGE-131]:
https://revenuecats.atlassian.net/browse/TRIAGE-131?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
[TRIAGE-82]:
https://revenuecats.atlassian.net/browse/TRIAGE-82?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
2022-10-11 13:38:54 -07:00
NachoSoto b746f5f205 PaymentQueueWrapper: improved abstraction for active SKPaymentQueue 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.
2022-10-11 12:55:42 -07:00
NachoSoto 9e4b329f99 Moved SKPaymentQueue.presentCodeRedemptionSheet to StoreKitWorkarounds (#1967)
NFC.

I'll be using this method from 2 different places, and it belongs here
with the other workarounds.
2022-10-10 08:38:59 -07:00
Andy Boedo cc81b3fa86 fix typo in comment (#1956)
Super high risk, dangerous PR with complicated changes, do not merge
2022-09-29 11:33:51 -03:00
NachoSoto 72a9f57103 PaymentQueueWrapper: handle promotional purchase requests from App Store when SK1 is disabled (#1901)
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`
2022-09-21 12:03:05 -07:00
NachoSoto 7934faf4a6 Renamed StoreKitWrapper to StoreKit1Wrapper (#1886)
Follow up to #1882. Now that `StoreKit1Wrapper` is not initialized for SK2, it makes sense to clarify that this class is only for SK1.
This is just a simple find-replace.
2022-09-06 17:15:54 -05:00