Skip to content

Commit

Permalink
[SK2] Add Configuration.with(storeKitVersion:) to select the versio…
Browse files Browse the repository at this point in the history
…n of StoreKit to use (#3487)

This PR introduces a new configuration option to select the StoreKit
version to use.

It supersedes the deprecated `.with(usesStoreKit2IfAvailable: true)` and
the internal `usesStoreKit2JWS` configuration options.

Uses JWS tokens instead of SK1 receipts when in StoreKit 2 mode where
applicable.

Example usage:
```swift
Purchases.configure(
            with: .builder(withAPIKey: apiKey)
                .with(storeKitVersion: .storeKit2)
                .build()
```
  • Loading branch information
MarkVillacampa committed Jan 11, 2024
1 parent 65028b8 commit 68265ba
Show file tree
Hide file tree
Showing 624 changed files with 1,041 additions and 432 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {

Purchases.configure(
with: Configuration.Builder(withAPIKey: Constants.apiKey)
.with(usesStoreKit2IfAvailable: true)
.with(storeKitVersion: .storeKit2)
.build()
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ struct MagicWeatherApp: App {

Purchases.configure(
with: Configuration.Builder(withAPIKey: Constants.apiKey)
.with(usesStoreKit2IfAvailable: true)
.with(storeKitVersion: .storeKit2)
.build()
)

Expand Down
12 changes: 4 additions & 8 deletions RevenueCat.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@
4D72E8622B221EA600BF9EFE /* StoreEnvironmentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D24EF3F2B04EA6000E586D2 /* StoreEnvironmentTests.swift */; };
4DBF1F362B4D572400D52354 /* LocalReceiptFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DBF1F352B4D572400D52354 /* LocalReceiptFetcher.swift */; };
4DBF1F372B4D572400D52354 /* LocalReceiptFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DBF1F352B4D572400D52354 /* LocalReceiptFetcher.swift */; };
4DBC30962B1DFA97001D33C7 /* StoreKitVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DBC30952B1DFA97001D33C7 /* StoreKitVersion.swift */; };
4DC546272AD44BBE005CDB35 /* EncodedAppleReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DC546262AD44BBE005CDB35 /* EncodedAppleReceipt.swift */; };
4F0201C42A13C85500091612 /* Assertions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F0201C32A13C85500091612 /* Assertions.swift */; };
4F05876F2A5DE03F00E9A834 /* PaywallDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F05876E2A5DE03F00E9A834 /* PaywallDataTests.swift */; };
Expand Down Expand Up @@ -347,7 +348,6 @@
4FFFE6C82AA9467800B2955C /* PaywallEventsManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FFFE6C72AA9467800B2955C /* PaywallEventsManagerTests.swift */; };
4FFFE6CA2AA946A700B2955C /* MockInternalAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FFFE6C92AA946A700B2955C /* MockInternalAPI.swift */; };
4FFFE6E72AA948A600B2955C /* PaywallEventsIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FFFE6E62AA948A600B2955C /* PaywallEventsIntegrationTests.swift */; };
57032ABF28C13CE4004FF47A /* StoreKit2SettingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57032ABE28C13CE4004FF47A /* StoreKit2SettingTests.swift */; };
57045B3829C514A8001A5417 /* ProductEntitlementMappingDecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57045B3729C514A8001A5417 /* ProductEntitlementMappingDecodingTests.swift */; };
57045B3A29C51751001A5417 /* GetProductEntitlementMappingOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57045B3929C51751001A5417 /* GetProductEntitlementMappingOperation.swift */; };
57045B3C29C51AF7001A5417 /* ProductEntitlementMappingCallback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57045B3B29C51AF7001A5417 /* ProductEntitlementMappingCallback.swift */; };
Expand Down Expand Up @@ -530,7 +530,6 @@
57CD86E6291C344000768DE1 /* UserDefaultsDefaultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57CD86E5291C344000768DE1 /* UserDefaultsDefaultTests.swift */; };
57CFB96C27FE0E79002A6730 /* MockCurrentUserProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57CFB96B27FE0E79002A6730 /* MockCurrentUserProvider.swift */; };
57CFB96D27FE0E79002A6730 /* MockCurrentUserProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57CFB96B27FE0E79002A6730 /* MockCurrentUserProvider.swift */; };
57CFB98427FE2258002A6730 /* StoreKit2Setting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57CFB98327FE2258002A6730 /* StoreKit2Setting.swift */; };
57D04BB827D947C6006DAC06 /* HTTPResponseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57D04BB727D947C6006DAC06 /* HTTPResponseTests.swift */; };
57D5412E27F6311C004CC35C /* OfferingsResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57D5412D27F6311C004CC35C /* OfferingsResponse.swift */; };
57D5414227F656D9004CC35C /* NetworkError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57D5414127F656D9004CC35C /* NetworkError.swift */; };
Expand Down Expand Up @@ -1003,6 +1002,7 @@
4D6ABB0D2AF13FB100BB2A08 /* StoreEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoreEnvironment.swift; sourceTree = "<group>"; };
4D6ABB0F2AF13FBD00BB2A08 /* SK2AppTransaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SK2AppTransaction.swift; sourceTree = "<group>"; };
4DBF1F352B4D572400D52354 /* LocalReceiptFetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalReceiptFetcher.swift; sourceTree = "<group>"; };
4DBC30952B1DFA97001D33C7 /* StoreKitVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreKitVersion.swift; sourceTree = "<group>"; };
4DC546262AD44BBE005CDB35 /* EncodedAppleReceipt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EncodedAppleReceipt.swift; sourceTree = "<group>"; };
4F0201C32A13C85500091612 /* Assertions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Assertions.swift; sourceTree = "<group>"; };
4F05876E2A5DE03F00E9A834 /* PaywallDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaywallDataTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1109,7 +1109,6 @@
4FFFE6C72AA9467800B2955C /* PaywallEventsManagerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaywallEventsManagerTests.swift; sourceTree = "<group>"; };
4FFFE6C92AA946A700B2955C /* MockInternalAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockInternalAPI.swift; sourceTree = "<group>"; };
4FFFE6E62AA948A600B2955C /* PaywallEventsIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaywallEventsIntegrationTests.swift; sourceTree = "<group>"; };
57032ABE28C13CE4004FF47A /* StoreKit2SettingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreKit2SettingTests.swift; sourceTree = "<group>"; };
57045B3729C514A8001A5417 /* ProductEntitlementMappingDecodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductEntitlementMappingDecodingTests.swift; sourceTree = "<group>"; };
57045B3929C51751001A5417 /* GetProductEntitlementMappingOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetProductEntitlementMappingOperation.swift; sourceTree = "<group>"; };
57045B3B29C51AF7001A5417 /* ProductEntitlementMappingCallback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductEntitlementMappingCallback.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1284,7 +1283,6 @@
57CD86D9291C1E2300768DE1 /* UserDefaults+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Extensions.swift"; sourceTree = "<group>"; };
57CD86E5291C344000768DE1 /* UserDefaultsDefaultTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsDefaultTests.swift; sourceTree = "<group>"; };
57CFB96B27FE0E79002A6730 /* MockCurrentUserProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCurrentUserProvider.swift; sourceTree = "<group>"; };
57CFB98327FE2258002A6730 /* StoreKit2Setting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreKit2Setting.swift; sourceTree = "<group>"; };
57D04BB727D947C6006DAC06 /* HTTPResponseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPResponseTests.swift; sourceTree = "<group>"; };
57D5412D27F6311C004CC35C /* OfferingsResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferingsResponse.swift; sourceTree = "<group>"; };
57D5414127F656D9004CC35C /* NetworkError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkError.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1801,10 +1799,10 @@
57ABA76C28F08DDA003D9181 /* Either.swift */,
F530E4FE275646EF001AF6BD /* MacDevice.swift */,
57EAE52A274332830060EB74 /* Obsoletions.swift */,
4DBC30952B1DFA97001D33C7 /* StoreKitVersion.swift */,
2CB8CF9227BF538F00C34DE3 /* PlatformInfo.swift */,
F5FCD3E927DA0D0B003BDC04 /* PriceFormatterProvider.swift */,
57FDAAB9284937A0009A48F1 /* SandboxEnvironmentDetector.swift */,
57CFB98327FE2258002A6730 /* StoreKit2Setting.swift */,
B3AA6237268B926F00894871 /* SystemInfo.swift */,
4FEF41AA2B4F2F3400CD699F /* MapAppStoreDetector.swift */,
);
Expand Down Expand Up @@ -2052,7 +2050,6 @@
57ACB12328174B9F000DCC9F /* CustomerInfo+TestExtensions.swift */,
57FDAABD28493A29009A48F1 /* SandboxEnvironmentDetectorTests.swift */,
579189E828F47E8D00BF4963 /* PurchasesDiagnosticsTests.swift */,
57032ABE28C13CE4004FF47A /* StoreKit2SettingTests.swift */,
5712BE9129241F7900A83F15 /* TimingUtilTests.swift */,
4F8DDB682AAA9189000188F2 /* OperationDispatcherTests.swift */,
4FEF41AC2B4F301800CD699F /* MacAppStoreDetectorTests.swift */,
Expand Down Expand Up @@ -3404,7 +3401,6 @@
4F6BEDE22A26B69500CD9322 /* DebugContentViews.swift in Sources */,
B3B5FBBC269D121B00104A0C /* Offerings.swift in Sources */,
9A65E03B25918B0900DE00B0 /* CustomerInfoStrings.swift in Sources */,
57CFB98427FE2258002A6730 /* StoreKit2Setting.swift in Sources */,
5721360F28B4602C006C46BE /* Purchases+nonasync.swift in Sources */,
57DE806D28074976008D6C6F /* Storefront.swift in Sources */,
B3B5FBB6269CED6400104A0C /* ErrorDetails.swift in Sources */,
Expand Down Expand Up @@ -3642,6 +3638,7 @@
57C2931528BFEF4F0054EDFC /* PurchasesError.swift in Sources */,
57FD7B1528DA4037009CA4E4 /* PurchasesType.swift in Sources */,
57C381DA2796153D009E3940 /* SK1StoreProductDiscount.swift in Sources */,
4DBC30962B1DFA97001D33C7 /* StoreKitVersion.swift in Sources */,
57DE807328074C76008D6C6F /* SK2Storefront.swift in Sources */,
57A17727276A721D0052D3A8 /* Set+Extensions.swift in Sources */,
4DC546272AD44BBE005CDB35 /* EncodedAppleReceipt.swift in Sources */,
Expand Down Expand Up @@ -3823,7 +3820,6 @@
57CFB96C27FE0E79002A6730 /* MockCurrentUserProvider.swift in Sources */,
57ACB13728184CF1000DCC9F /* DecoderExtensionTests.swift in Sources */,
351B516126D44BEB00BD2BD7 /* IdentityManagerTests.swift in Sources */,
57032ABF28C13CE4004FF47A /* StoreKit2SettingTests.swift in Sources */,
579D2E3A28F0BF5A0094B36F /* BackendInternalTests.swift in Sources */,
351B51C126D450E800BD2BD7 /* OfferingsManagerTests.swift in Sources */,
5796A39927D6C1E000653165 /* BackendPostSubscriberAttributesTests.swift in Sources */,
Expand Down
5 changes: 2 additions & 3 deletions Sources/Error Handling/ErrorCode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,8 @@ extension ErrorCode: DescribableError {
return "The receipt is in use by other subscriber."
case .invalidAppleSubscriptionKeyError:
return """
Apple Subscription Key is invalid or not present. In order to provide subscription offers, you must
first generate a subscription key.
Please see https://docs.revenuecat.com/docs/ios-subscription-offers for more info.
Apple In-App Purchase Key is invalid or not present. You must configure an In-App Purchase Key.
Please see https://rev.cat/in-app-purchase-key-configuration for more info.
"""
case .ineligibleError:
return "The User is ineligible for that action."
Expand Down
10 changes: 5 additions & 5 deletions Sources/Logging/Strings/ConfigureStrings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ enum ConfigureStrings {

case debug_enabled

case store_kit_2_enabled

case observer_mode_enabled

case observer_mode_with_storekit2

case response_verification_mode(Signing.ResponseVerificationMode)

case storekit_version(StoreKitVersion)

case delegate_set

case purchase_instance_already_set
Expand Down Expand Up @@ -96,8 +96,6 @@ extension ConfigureStrings: LogMessage {
"with URL: \(url)"
case .debug_enabled:
return "Debug logging enabled"
case .store_kit_2_enabled:
return "StoreKit 2 support enabled"
case .observer_mode_enabled:
return "Purchases is configured in observer mode"
case .observer_mode_with_storekit2:
Expand All @@ -111,6 +109,8 @@ extension ConfigureStrings: LogMessage {
case .enforced:
return "Purchases is configured with enforced response verification"
}
case let .storekit_version(version):
return "Purchases is configured with StoreKit version \(version)"
case .delegate_set:
return "Delegate set"
case .purchase_instance_already_set:
Expand Down Expand Up @@ -185,7 +185,7 @@ extension ConfigureStrings: LogMessage {

case .sk2_required_for_swiftui_paywalls:
return "Purchases is not configured with StoreKit 2 enabled. This is required in order to detect " +
"transactions coming from SwiftUI paywalls. You must use `.with(usesStoreKit2IfAvailable: true)` " +
"transactions coming from SwiftUI paywalls. You must use `.with(storeKitVersion: .storeKit2)` " +
"when configuring the SDK."
}
}
Expand Down
13 changes: 1 addition & 12 deletions Sources/Misc/DangerousSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import Foundation
internal struct Internal: InternalDangerousSettingsType {

let enableReceiptFetchRetry: Bool
let usesStoreKit2JWS: Bool

#if DEBUG
let forceServerErrors: Bool
Expand All @@ -26,26 +25,22 @@ import Foundation

init(
enableReceiptFetchRetry: Bool = false,
usesStoreKit2JWS: Bool = false,
forceServerErrors: Bool = false,
forceSignatureFailures: Bool = false,
disableHeaderSignatureVerification: Bool = false,
testReceiptIdentifier: String? = nil
) {
self.enableReceiptFetchRetry = enableReceiptFetchRetry
self.usesStoreKit2JWS = usesStoreKit2JWS
self.forceServerErrors = forceServerErrors
self.forceSignatureFailures = forceSignatureFailures
self.disableHeaderSignatureVerification = disableHeaderSignatureVerification
self.testReceiptIdentifier = testReceiptIdentifier
}
#else
init(
enableReceiptFetchRetry: Bool = false,
usesStoreKit2JWS: Bool = false
enableReceiptFetchRetry: Bool = false
) {
self.enableReceiptFetchRetry = enableReceiptFetchRetry
self.usesStoreKit2JWS = usesStoreKit2JWS
}

#endif
Expand Down Expand Up @@ -125,12 +120,6 @@ internal protocol InternalDangerousSettingsType: Sendable {
/// Whether `ReceiptFetcher` can retry fetching receipts.
var enableReceiptFetchRetry: Bool { get }

/**
* Controls whether StoreKit 2 JWS tokens are sent to RevenueCat instead of StoreKit 1 receipts.
* Must be used in conjunction with the `usesStoreKit2IfAvailable configuration` option.
*/
var usesStoreKit2JWS: Bool { get }

#if DEBUG
/// Whether `HTTPClient` will fake server errors
var forceServerErrors: Bool { get }
Expand Down
23 changes: 4 additions & 19 deletions Sources/Misc/Deprecations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public extension Purchases {
appUserID: appUserID,
observerMode: observerMode,
userDefaults: userDefaults,
useStoreKit2IfAvailable: StoreKit2Setting.default.usesStoreKit2IfAvailable
useStoreKit2IfAvailable: StoreKitVersion.default == .storeKit2
)
}

Expand Down Expand Up @@ -118,7 +118,7 @@ public extension Purchases {
userDefaults: userDefaults,
platformInfo: nil,
responseVerificationMode: .default,
storeKit2Setting: .init(useStoreKit2IfAvailable: useStoreKit2IfAvailable),
storeKitVersion: useStoreKit2IfAvailable ? .storeKit2 : .storeKit1,
storeKitTimeout: Configuration.storeKitRequestTimeoutDefault,
networkTimeout: Configuration.networkTimeoutDefault,
dangerousSettings: dangerousSettings,
Expand Down Expand Up @@ -403,24 +403,9 @@ extension CustomerInfo {

public extension Configuration.Builder {

/// Set `storeKit2Setting`. If `true`, the SDK will use StoreKit 2 APIs internally. If disabled, it will use StoreKit 1 APIs instead.
/// - Parameter usesStoreKit2IfAvailable: enable StoreKit 2 on devices that support it.
/// Defaults to `false`.
/// - Important: This configuration flag has been deprecated, and will be replaced by automatic remote configuration in the future.
/// However, apps using it should work correctly.
///
@available(*, deprecated, message: """
RevenueCat currently uses StoreKit 1 for purchases, as its stability in production scenarios has
proven to be more performant than StoreKit 2.
We're collecting more data on the best approach, but StoreKit 1 vs StoreKit 2 is an implementation detail
that you shouldn't need to care about.
Simply remove this method call to let RevenueCat decide for you which StoreKit implementation to use.
""")
@available(*, deprecated, message: "Use .with(storeKitVersion:) to enable StoreKit 2")
@objc func with(usesStoreKit2IfAvailable: Bool) -> Configuration.Builder {
self.storeKit2Setting = .init(useStoreKit2IfAvailable: usesStoreKit2IfAvailable)
return self
return self.with(storeKitVersion: usesStoreKit2IfAvailable ? .storeKit2 : .default)
}

}
Expand Down
86 changes: 0 additions & 86 deletions Sources/Misc/StoreKit2Setting.swift

This file was deleted.

Loading

0 comments on commit 68265ba

Please sign in to comment.