Commit Graph
57 Commits
Author SHA1 Message Date
Facundo Menzella 6b5c430082 chore: Enable force_unwrapping for SwiftLint (#4820)
* enable force_unwrapping

* avoid force unwrap

* fixed all errors

* remove extra disable
2025-02-26 12:40:49 +01:00
Will Taylor 6de169a23e support fetching eligible win-back offers for a product 2024-11-06 15:46:04 -06:00
Will Taylor df33158600 only treat deferred StoreKit messages as shown when they are shown 2024-10-07 10:18:37 -05:00
Will Taylor c814d0e3ac support deferring win-back storekit messages 2024-10-07 09:18:44 -05:00
NachoSoto 2bcd0ce328 5.0.0 changes: support SK2 by default 2024-07-01 14:37:21 -05:00
Josh HoltzandRevenueCat Git Bot a9737aa7fc Add targeting to PresentedOfferingContext (#3730)
### Motivation

Get more context with targeting information 

### Description

- Parse targeting information into `Offerings`
- Add targeting context into `Offerings.current`
- Add targeting context into `getCurrentOffering(forPlacement: String)`
- Post targeting context in post receipts

---------

Co-authored-by: RevenueCat Git Bot <72824662+RCGitBot@users.noreply.github.com>
2024-02-28 16:10:52 -06:00
61d66bbc32 Add currentOffering(forPlacement: String) to Offerings (#3707)
### Motivation

New function to get `Offering` by a placement identifier

### Description

New `currentOffering(forPlacement: String): Offering?` method on
`Offerings`
- Added demo button for this in purchase tester app

```swift
// Example usage
if let offering = offerings.currentOffering(forPlacement: "onboarding") {
  showPaywall(offering)
}
```

#### Logic flow

- If a placement identifier explicitly exists within the
`placements.offeringIdsByPlacement` dictionary, the method attempts to
fetch the corresponding `Offering` without resorting to a fallback
- Example: when there is a `nil` / null value for a placement, we don't
want to use the fallback
- If the placement identifier does not exist, the method then attempts
to fetch a fallback offering defined by `placements.fallbackOfferingId`

#### New placements object in offerings response

```js
{
    // other offerings stuff
    "placements": {
        "fallback_offering_id": "offering_a", // can be null
        "offering_ids_by_placement": {
            "onboarding_start": null,
            "onboarding_end": "offering_b",
        }
  }
}
```

---------

Co-authored-by: Guido Torres <guido@revenuecat.com>
Co-authored-by: Josh Holtz <me@joshholtz.com>
Co-authored-by: RevenueCat Git Bot <72824662+RCGitBot@users.noreply.github.com>
2024-02-28 15:11:48 -06:00
Josh Holtz 67d57a1942 New Package.presentedOfferingContext (#3712)
This was already approved and merged into `5.0-dev` but bringing this
into `4.x` (see #3690)

### Motivation

Allow for storing of other presented offering context on a `Package`

### Description

- Replaced `offeringIdentifier: String` on `Package` with new
`presentedOfferingContext: PresentedOfferingContext`
  - Currently it only has a `offeringIdentifier: String`
- Eventually this will add new optional properties for targeting and
placements
2024-02-28 13:53:42 -06:00
NachoSoto 15df832fea Xcode 15.3 beta 2: remove nonisolated workaround (#3640)
See #3599.

This is listed in the [release
notes](https://developer.apple.com/documentation/xcode-release-notes/xcode-15_3-release-notes)
as fixed.
2024-02-06 14:11:16 -08:00
NachoSoto 53fe9cd7bd Xcode 15.3 beta 1: fix compilation errors (#3599)
### Changes:
- `InternalAPI` is now `Sendable` to deal with new compilation error
- `PaywallEventStoreType` is now `Sendable`
- Extracted `SK2BeginRefundRequestHelperType` to make
`SK2BeginRefundRequestHelper` `Sendable`
- Updated `MockSK2BeginRefundRequestHelper` to be thread-safe and
`Sendable`
- Fixed compilation error in `DebugContentViews`
- Fixed compilation error in `DebugViewModel`
- Fixed compilation error in `StoreMessagesHelper`
2024-01-25 15:29:31 -08:00
NachoSoto 67b421e2b1 .debugRevenueCatOverlay: added Locale (#3539)
This adds the `Locale.identifier` and the currency code.
It can help debug issues with paywalls, currencies, localization, etc.

![Simulator Screenshot - iPhone 15 Pro Max - 2023-12-21 at 11 05
36](https://github.com/RevenueCat/purchases-ios/assets/685609/c0b5db10-8ab8-4119-9992-522065979612)
2023-12-21 12:19:54 -08:00
NachoSoto 4bca13f90d Debug View: display receipt status (#3303) 2023-10-16 07:34:34 -07:00
Toni RicoandNachoSoto f06740f87c Remove ObjC showStoreMessages API (#3269)
### Description
This removes the extra APIs that were added to support showing store
messages in ObjC. We will add these in PHC. If there is a demand for it
we can always add it later.

---------

Co-authored-by: NachoSoto <NachoSoto@users.noreply.github.com>
2023-10-03 18:41:50 +02:00
Toni RicoandNachoSoto 773fd84a65 StoreKit In App messages support (#3252)
### Description
StoreKit displays different types of in-app messages on app launch, but
it provides an API to disable that and show these messages at a
different time. This PR wraps those APIs to make them easier to use
through our SDK.

#### New APIs
- Add new configuration parameter to defer StoreKit's automatic in-app
messages
- Add new method in `Purchases` to display a list of specific message
types
- New `StoreKitMessageType` enum mapping to the types used by StoreKit

---------

Co-authored-by: NachoSoto <NachoSoto@users.noreply.github.com>
2023-10-03 16:58:53 +02:00
NachoSoto efb8239133 debugRevenueCatOverlay: added list of active entitlements (#3247)
![Screenshot 2023-09-22 at 14 51
15](https://github.com/RevenueCat/purchases-ios/assets/685609/1d799147-16b6-4add-ada0-d4fbe9b2bd78)
2023-10-02 09:30:13 -07:00
NachoSoto 43030b16f3 Debug: add Offering metadata to debug screen (#3137) 2023-09-14 18:28:11 -07:00
NachoSoto 483e03c1fa Paywalls: added JSON debug screen to debugRevenueCatOverlay (#2972) 2023-09-14 18:28:11 -07:00
NachoSoto 39a35bd02a Paywalls: pre-warm intro eligibility in background thread (#2925)
Follow-up to #2860.
Thanks to integration tests for catching this (#2123).

![image](https://github.com/RevenueCat/purchases-ios/assets/685609/cf1e8e32-5d5e-47ba-b900-394aa780d865)
2023-09-14 18:28:11 -07:00
NachoSoto 0608e97577 DebugViewModel: fixed runtime crash on iOS < 16 (#3139)
Fixes https://github.com/RevenueCat/purchases-capacitor/issues/100 and
https://app.circleci.com/pipelines/github/RevenueCat/purchases-ios/14093/workflows/b3f8d001-6f39-40db-a5c5-00fc37d0211e/jobs/105838

```
Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   ???                           	               0x0 ???
1   libswiftCore.dylib            	       0x18f9b8cf8 swift_getSingletonMetadata + 956
2   RevenueCat                    	       0x107f42de4 type metadata accessor for DebugViewModel + 64
3   libobjc.A.dylib               	       0x18017d938 realizeClassMaybeSwiftMaybeRelock(objc_class*, mutex_tt<false>&, bool) + 116
4   libobjc.A.dylib               	       0x180184eb0 realizeAllClasses() + 168
5   libobjc.A.dylib               	       0x180187b3c objc_copyClassList + 36
6   XCTestCore                    	       0x10532fcb0 +[XCTestCase(RuntimeUtilities) _allSubclasses] + 36
7   XCTestCore                    	       0x10532fdb8 +[XCTestCase(RuntimeUtilities) allSubclasses] + 16
```

Both `XCTest` (to load tests at runtime) and `Capacitor` use
`objc_getClassList`. That's broken before iOS 16 and will try to load
the metadata for `DebugViewModel` even though it's not `@available`.
A similar issue has been reported before:
https://openradar.appspot.com/radar?id=4970535809187840 /
https://github.com/apple/swift/issues/58099

This adds a layer of indirection so loading `DebugViewModel` at runtime
doesn't require the metadata for `NavigationPath`.
2023-09-05 10:12:12 -07:00
NachoSoto 93b09a27a3 StoreKit 2: added warning to paywall constructors (#3045)
This became a requirement with #3032.
2023-08-22 15:38:30 -07:00
NachoSoto 1350189e90 StoreKit 2: only listen to StoreKit.Transaction.updates when SK2 is enabled (#3032) 2023-08-16 16:04:42 -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 dab5035a19 visionOS: support for Xcode 15 beta 6 (#2989)
### 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)
2023-08-09 11:19:40 -07:00
Josh HoltzandNachoSoto 31a44f86a6 xrOS: fixed SubscriptionStoreView for visionOS beta 2 (#2884)
### Motivation

visionOS beta 2 had compile errors in `SubscriptionStoreView`

### Description

Replaced `DefaultSubscriptionStoreMarketingContent` with
`AutomaticSubscriptionStoreMarketingContent`

---------

Co-authored-by: NachoSoto <ignaciosoto90@gmail.com>
2023-07-26 09:07:32 +02:00
NachoSoto 8392161545 PurchasesDiagnostics: don't test signature verification if it's disabled (#2757)
Signature verification is not working due to changing signature (see
#2744), but the debug screen shouldn't show an error if verification
isn't enabled.
2023-07-06 13:19:29 -07:00
NachoSoto c7db551bc4 xrOS: add support for debugRevenueCatOverlay (#2702) 2023-06-26 13:06:13 -07:00
NachoSoto 76c440b204 xrOS: fixed compilation by disabling debug overlay (#2681)
We can look into making them work in the future, but for now this helps
compile the SDK for `xrOS`.
2023-06-22 08:42:04 -07:00
NachoSoto 4ab9d7334f xrOS: added support for new purchase(confirmIn:options:) method (#2683) 2023-06-22 07:31:03 -07:00
NachoSoto 44608c33bb PaywallExtensions: post purchases with Offering identifier (#2645)
### Changes:

- Exposed `internal`-only `Purchases.cachePresentedOfferingIdentifier`
- Changed `SwiftUI` extensions to `static` methods: this is required to
be able to call an instance method on them
- Added integration test to verify this offering identifier is used

Technically this is an API change, but these APIs are implicitly beta
because they're only available in Xcode 15 beta.
2023-06-15 17:16:31 -07:00
NachoSoto 6ba378ba5e debugRevenueCatOverlay: display receiptURL (#2652)
Useful when debugging issues like #2558.

![Screenshot 2023-06-14 at 11 58
28](https://github.com/RevenueCat/purchases-ios/assets/685609/3fcb55bc-107e-46fd-aced-0d12d0667cba)
2023-06-15 08:37:58 -07:00
NachoSoto 1637db2180 debugRevenueCatOverlay: ability to close on macOS/Catalyst (#2649)
![Screenshot 2023-06-14 at 11 53
37](https://github.com/RevenueCat/purchases-ios/assets/685609/206242bc-4887-495b-a894-2bda064bd8a3)
2023-06-15 08:10:35 -07:00
NachoSoto 7958e91dff debugRevenueCatOverlay: added support for macOS (#2648)
I wanted to support it to be able to look into #2558.


![image](https://github.com/RevenueCat/purchases-ios/assets/685609/cdba0488-965e-4887-bef0-ae151430889a)
2023-06-15 08:10:03 -07:00
NachoSoto 0d448c1265 debugRevenueCatOverlay: simplified title (#2641) 2023-06-14 07:46:58 -07:00
NachoSoto 5ec9d36e22 New DebugViewController: UIKit counterpart for SwiftUI's debugRevenueCatOverlay (#2631)
Built on top of `DebugSwiftUIRootView`. This can be presented either
manually, or using `UIViewController.presentDebugRevenueCatOverlay`.

This looks exactly the same as the `SwiftUI` version:

![image](https://github.com/RevenueCat/purchases-ios/assets/685609/2ef22db4-0030-457e-a721-8daf2dcc1a49)
2023-06-13 09:37:52 -07:00
NachoSoto 551cb2d8d2 DebugView: added snapshot tests (#2630)
UI tests for #2567.
2023-06-13 08:54:36 -07:00
NachoSoto 2036f9bb84 PaywallExtensions: fixed compilation (#2613)
Not sure why I didn't notice this when compiling through Xcode, but just
noticed this on CI in #2591.
Fixes:
```
❌ /Users/distiller/purchases-ios/Sources/Support/PaywallExtensions.swift:106:27: 'some' return types are only available in application extensions for iOS 13.0.0 or newer
    private var products: some Sequence<StoreProduct> {
```
2023-06-12 09:36:12 +02:00
NachoSoto 51865954cb debugRevenueCatOverlay: added ability to display new SubscriptionStoreView (#2595)
See #2593

![Simulator Screenshot - iPhone 14 Pro Max - 2023-06-07 at 13 07
58](https://github.com/RevenueCat/purchases-ios/assets/685609/551dd3e0-80f8-4b68-b79f-abcf078fb56f)
2023-06-09 10:55:31 -07:00
NachoSoto 3032007fef Created PaywallExtensions: StoreView and SubscriptionStoreView overloads for Offering (#2593)
### Description
This adds overloads, but there's still a few things pending for the SDK
to fully support these:
- Set `presentedOfferingIdentifier` when displaying StoreKit2 paywalls:
SDK-3176
- Fix `preventPurchasePopupCallFromTriggeringCacheRefresh`: SDK-3172
- Always initialize `StoreKit2TransactionListener` even on SK1 mode:
SDK-3170

### Example:
```swift
struct App: View {

    var offering: Offering

    var body: some View {
        Content()
            .sheet(isPresented: self.$showingSubscriptionSheet) {
                SubscriptionStoreView(offering: self.offering)
            }
    }

}
```
2023-06-09 10:18:41 -07:00
NachoSoto ce470442cf debugRevenueCatOverlay improvements (#2594) 2023-06-08 08:37:22 -07:00
NachoSoto 3b53f2426c Introduced debugRevenueCatOverlay(): new SwiftUI debug overlay (#2567)
![simulator_screenshot_DBF551B9-3BA8-440D-9B3F-16DB1D47A0A7](https://github.com/RevenueCat/purchases-ios/assets/685609/af1ddee9-6ae7-4766-9b12-4875416477c6)
2023-06-07 09:16:45 -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 64c8638425 Create separate SPM library to enable custom entitlement computation (#2440)
Fixes SDK-3084

![screenshot_2023-04-25_at_10 02
44_480](https://user-images.githubusercontent.com/685609/234360670-bd2628a1-0684-490d-a9eb-33846a60f72a.png)

## Changes:

- Added new `ENABLE_CUSTOM_ENTITLEMENT_COMPUTATION` compile time flag
- Hidden `configureInCustomEntitlementsModeWithApiKey` behind
`ENABLE_CUSTOM_ENTITLEMENT_COMPUTATION`
- Added new `RevenueCat_CustomEntitlementComputation` SPM target and
library
- Added CircleCI job for `swift build --target
RevenueCat_CustomEntitlementComputation`
- Added new `SPMCustomEntitlementComputationInstallation` using the new
`configureInCustomEntitlementsComputationMode`
- Added CircleCI job for `SPMCustomEntitlementComputationInstallation`
- Added `FrameworkDisambiguation.swift` to avoid using `RevenueCat.`
disambiguation for files that
- Changed API testers to only use the new methods if
`ENABLE_CUSTOM_ENTITLEMENT_COMPUTATION` is defined
- Updated `DangerousSettings` to not expose
`customEntitlementComputation` publicly. The only way to use that now
with `public` API is through
`Purchases.configureInCustomEntitlementsModeWithApiKey`
- Updated sample app to use new library
2023-04-25 15:11:58 -07:00
NachoSoto d71772c0e9 Updated requirements to drop Xcode 13.x support (#2419)
Starting April 2023 it's no longer possible to submit apps with Xcode
13.x. This technically doesn't drop _support_, but we might won't be
testing on the oldest supported version of Xcode 13, since it's not
necessary.

### Changes:
_See
[`UpdatingRequirements.md`](https://github.com/RevenueCat/purchases-ios/blob/f8e07f07e8e842c25755f3dbca3a3f35961258a0/Contributing/UpdatingRequirements.md)_

- Removed `CircleCI` Xcode 13.2.1 job (_this saves ~11 minutes of build
time on every commit_)
- Updated `README`
- Updated message in `SwiftVersionCheck.swift`

Note that a lot of CI tests still run on Xcode 13.x for now because
installing old simulators on Xcode 14.x was failing. We'll need to fix
this when `CircleCI` drops support for `Xcode 13.x`.
Once we do that, we can refactor a lot of code like
```swift
#if swift(>=5.7)
extension CustomerInfo: Sendable {}
#else
// `@unchecked` because:
// - `Date` is not `Sendable` until Swift 5.7
// - `URL` is not `Sendable` until Swift 5.7
extension CustomerInfo: @unchecked Sendable {}
#endif
```
2023-04-20 08:31:11 -07:00
NachoSoto dbe93dbbf4 PurchasesDiagnostics: added step to verify signature verification (#2267)
⚠️ 🎉 This also changes integration tests to use
`EntitlementVerificationLevel.enforced` so that integration tests fail
if signatures are invalid.

#### Depends on:
- https://github.com/RevenueCat/khepri/pull/5191
- https://github.com/RevenueCat/khepri/pull/5204
- #2214
- #2215 
- #2216
- #2272

_Marking this as `feat`ure because it contains a new error in
`PurchasesDiagnostics.Error`_
2023-02-16 10:27:04 -07:00
NachoSoto 61501ddc72 Signing: updated to use production public key (#2274)
Depends on #2272 and #2278.
Depends on https://github.com/RevenueCat/khepri/pull/5232.
2023-02-16 03:25:52 -08:00
NachoSoto 76dbf0037b Configuration: added (internal for now) API to load public key (#2215)
Fixes [CSDK-632].

### Changes:
- Created `Signing` to encapsulate new signing logic and types
- Added abstractions like `Signing.Certificate` and `Signing.PublicKey`
over `Security` C types
- Created `Configuration.EntitlementVerificationLevel` and
`Signing.ResponseVerificationLevel` (the logic for the name difference
is that publicly this is used to validate entitlements, but the internal
implementation works for any response).
- Created `Signing.loadPublicKey`
- Added tests for loading public key embedded in SDK
- Added `internal` (for now)
`Configuration.with(entitlementVerificationLevel:)`
- Added `SystemInfo.responseVerificationLevel` with the loaded key, if
enabled

### For a future PR:
- Make the `Configuration.with(entitlementVerificationLevel:)` `public`
- Make `Configuration.EntitlementVerificationLevel` `public`
- Add those 2 to `APITesters`
- Improve documentation by adding a link to the docs
- Verify certificate issuer in test

[CSDK-632]:
https://revenuecats.atlassian.net/browse/CSDK-632?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
2023-02-08 08:53:43 -08:00
NachoSoto f8e07f07e8 Produce a compilation error when using an old Xcode version (#2222)
This will make it easier to figure out that the version is no longer
compatible.
Aditionally, I've added `UpdatingRequirements.md` so we have a single
place to reference when changing these requirements.
2023-01-18 08:16:06 -08:00
NachoSoto faf51e3d99 Introduced PurchasesDiagnostics to help diagnose SDK configuration errors (#1977)
Finishes [CSDK-451].

This new small public API allows users to quickly figure out if
everything in the SDK is correctly configured in a simple way:
```swift
let diagnostics = PurchasesDiagnostics.default
do {
    try await diagnostics.testSDKHealth()
} catch {
    print(error)
}
```

The specific underlying errors will provide information about what
failed.

We can continue growing this to check for more specific things, but for
now it does 4 things:
- Verify API connectivity: networking issues, firewalling, etc.
- Verify API key is correct
- Verify `Offerings` are configured correctly
- Verify that all products in `Offerings` are configured correctly and
found in `StoreKit`

This new API is covered by:
- API testers
- Unit tests
- Integration tests (both on `SK1` and `SK2`)

_I've taken the "shortcut" of making this `async` only (while still
compatible with Objective-C), which means it's not compatible with iOS
12.x. But that made the implementation a lot simpler, which I think is a
useful tradeoff._

### Depends on:
- #1970
- #1971
- #1973
- #1974
- #1975
- #1976

[CSDK-451]:
https://revenuecats.atlassian.net/browse/CSDK-451?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
2022-10-27 12:00:53 -07:00
NachoSoto b93b082690 Fixed Xcode 13.2.x / Swift 5.5 compatibility (#1994)
Fixes [SDKONCALL-156].

This will be covered by #1990.

[SDKONCALL-156]:
https://revenuecats.atlassian.net/browse/SDKONCALL-156?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
2022-10-24 14:36:05 -07:00
NachoSoto 46ac7598fc Abstracted conversion from async to completion-block APIs (#1943)
Created `Async` with some shared methods that make this conversion
simpler in a type-safe way.

Helps turn this:
```swift
_ = Task<Void, Never> {
    do {
        completion(.success(try await f()))
    } catch {
        completion(.failure(ErrorUtils.error())
    }
}
```

Into this:
```swift
Async.call(with: completion) {
    try await f()
}
```
2022-09-28 08:40:59 -07:00