* feat: disable postAttributionData requests when in UI preview mode
* tests: add unit test to check `AttributionPoster`'s new `clearPostponedAttributionData` method
* tests: add unit tests to check that `AttributionData` is never posted in UI preview mode
* refactor: simplify implementation of avoiding `AttributionPoster` requests in UI preview mode
We had a report of a developer that is seeing that users (who are using
iOS 18 beta) are reporting app crashes on launch with 55 unique devices
so far. They are using using iOS SDK 4.17.7.
The line that is crashing is:
```
client = clientClass.perform(#selector(FakeAfficheClient.sharedClient)).takeUnretainedValue()
```
We just couldn’t have a single variable named `adClient` without an app
getting rejected, even if it wasn’t using it at all. We built the
`AfficheClient` so prevent app rejections.
It turns out Apple has removed documentation for `AdClient`, and by
looking into
https://developer.apple.com/documentation/iad/setting-up-apple-search-ads-attribution#overview
> After February 7, 2023, all requests made to the Apple Search Ads iAd
Attribution API will return with a value of "iad-attribution" = false,
or errors. See ADClient/requestAttributionDetails(_:). Use the
AdServices framework for current attribution integration with the Apple
Search Ads Campaign Management API for devices using iOS 14.3 and later.
Attribution isn't available for downloads and redownloads from devices
using iOS 14.2 or earlier.
So this wasn't even working anyways. I removed everything related but
left the public API in place to not break anyone.
Fixes#3280.
Turns out that `AAAttribution.attributionToken()` is asynchronous, and
Apple will happily allow you to make a blocking network request on the
main thread. This avoids that.
I've refactored `AttributionFetcher.adServicesToken` to be `async` and
added `RCTestAssertNotMainThread` to ensure this doesn't break again.
The rest of the changes were necessary to accommodate the new `async`
API.
### Context:
`#if os(iOS)` no longer evaluates to `true` when compiling for
`visionOS`
Which means we need `|| os(xrOS)`.
But to support older Xcode we need `#if swift(>=5.9) && os(xrOS)`.
But, fun fact, short-circuiting doesn’t work in `Xcode 13`.
And we still need that to run iOS <15 tests (`FB12223404` /
`FB12805891`)
💩
This works around that by defining our own `VISION_OS` flag.
### Changes:
- Added `VISION_OS` compile time flag to determine SDK
- Replaced `#if os(xrOS)` with `#if VISION_OS`
- Added flag to `Package.swift` (thanks @neonichu for helping with this)
### Motivation
It was not clear what `postAdServicesTokenIfNeeded()` was doing for
anybody unfamiliar with our codebase or AdServices. This method is in
`applicationWillEnterForeground` and without digging into any of the
implementation, it looks like it could send the attribution token every
time the app enters the foreground.
The behavior was actually only sending it once per install (as it
should) so the method rename reflects that.
### Description
Renames `postAdServicesTokenIfNeeded()` to
`postAdServicesTokenOncePerInstallIfNeeded()`
Cherry-picked #2549 post refactors (#2540 and #2542). This becomes a lot
simpler since #2542, thanks to the fact that we can put this new
parameter in `PurchasedTransactionData`.
### Changes:
- Added `aadAttributionToken` to `PurchasedTransactionData`
- Exposed `AttributionPoster.adServicesTokenToPostIfNeeded`
- Added snapshot test to verify it's sent
- Added `PurchasesOrchestrator` tests (SK1/SK2) for sending the
attribution token
- Added missing `PurchasesOrchestrator` tests for sending attributes
- Added log when marking `AdServices` token as synced
- Exposed `Purchases.attribution` for custom entitlement computation
framework (and added to API tester)
- Exposed `Purchases.enableAdServicesAttributionTokenCollection` for
custom entitlement computation framework (and added to API tester)
Because `AAAttribution.attributionToken()` isn't available on
simulators, we currently had no coverage for this entire part of the
codebase.
By mocking the token (on simulator + debug + integration tests only), we
can verify posting to the server works correctly.
As a follow-up, we can also verify that posting it as part of the
receipt with #2549 works correctly as well.
* [CF-106] Fetch AdServices Token (#1519)
Co-authored-by: NachoSoto <NachoSoto@users.noreply.github.com>
Co-authored-by: Josh Holtz <me@joshholtz.com>
* [CF-553] Post AdServices token (#1534)
Co-authored-by: NachoSoto <NachoSoto@users.noreply.github.com>
Co-authored-by: Josh Holtz <me@joshholtz.com>
* Update ios 14 snapshots tets
* Reworked adservices to use new Purchases.shared.attribution API
* Updated with some comments from PR
* Add iAd code back (#1739)
Co-authored-by: NachoSoto <NachoSoto@users.noreply.github.com>
* use new mapKeys dictionary extension for device cache
* update for some pr comments
* remove purchasestests
* generate missing snapshots
* fix deprecation messages to clarify method now called on shared instance
* Fix for inserting nonstring into userdefaults
* Add tests for bug
* fix lint
* Added availablility checks for tests and removed unused varialbes
* Whoops... wrong class
Co-authored-by: beylmk <maddie@revenuecat.com>
Co-authored-by: NachoSoto <NachoSoto@users.noreply.github.com>
A lot of our classes depended on the mutable `IdentityManager`, when in reality they only needed a read-only `currentAppUserID`.
This PR changes the requirement, with the following advantages:
- Ensure all these classes (`AttributionPoster`, `PurchasesOrchestrator`, `TrialOrIntroPriceEligibiltyChecker`, `BeginRefundRequestHelper`, `ManageSubscriptionsHelper`) cannot logIn / logOut, only read the current user
- Simplify tests by only requiring a smaller type
- Simplifying instantiation of these types outside the normal `Purchases` initialization.
I've also created `MockCurrentUserProvider`, but changed the existing `MockIdentityManager` so that calls to `logIn`/`logOut` just fail. These aren't mocked, and they wouldn't have an impact on the mocked readable values, so calling them is most likely unexpected and should make the test fail.