Skip to content

Commit

Permalink
Merge pull request #247 from superwall/develop
Browse files Browse the repository at this point in the history
3.10.0
  • Loading branch information
yusuftor authored Oct 4, 2024
2 parents 3db4210 + 1fdf79e commit 1fa4e91
Show file tree
Hide file tree
Showing 28 changed files with 1,029 additions and 313 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@

The changelog for `SuperwallKit`. Also see the [releases](https://github.com/superwall/Superwall-iOS/releases) on GitHub.

## 3.10.0

### Enhancements

- Adds `purchase(_:)` to initiate a purchase of an `SKProduct` via Superwall regardless of whether you are using paywalls or not.
- Adds `restorePurchases()` to restore purchases via Superwall.
- Adds an optional `paywall(_:loadingStateDidChange)` function to the `PaywallViewControllerDelegate`. This is called when the loading state of the presented `PaywallViewController` did change.
- Makes `loadingState` on the `PaywallViewController` a public published property.

### Fixes

- Tweaks AdServices token logic to prevent getting the token twice.

## 3.9.1

### Fixes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"repositoryURL": "https://github.com/RevenueCat/purchases-ios.git",
"state": {
"branch": null,
"revision": "0d2f1fa050acad0de99b9b0ce45d53c741c20629",
"version": "5.2.1"
"revision": "c7058bfd80d7f42ca6aa392bf1fab769d1158bf1",
"version": "5.5.0"
}
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import Foundation
final class AttributionPoster {
private let attributionFetcher = AttributionFetcher()
private let collectAdServicesAttribution: Bool
private var isCollecting = false

private unowned let storage: Storage

private var adServicesTokenToPostIfNeeded: String? {
Expand Down Expand Up @@ -52,6 +54,9 @@ final class AttributionPoster {
guard Superwall.isInitialized else {
return
}
if isCollecting {
return
}
Task(priority: .background) {
if #available(iOS 14.3, macOS 11.1, macCatalyst 14.3, *) {
await getAdServicesTokenIfNeeded()
Expand All @@ -65,7 +70,11 @@ final class AttributionPoster {
@available(tvOS, unavailable)
@available(watchOS, unavailable)
func getAdServicesTokenIfNeeded() async {
defer {
isCollecting = false
}
do {
isCollecting = true
guard collectAdServicesAttribution else {
return
}
Expand Down
5 changes: 4 additions & 1 deletion Sources/SuperwallKit/Config/ConfigManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,10 @@ class ConfigManager {
}
}

func fetchWithTimeout<T>(_ task: @escaping () async throws -> T, timeout: TimeInterval) async throws -> T {
private func fetchWithTimeout<T>(
_ task: @escaping () async throws -> T,
timeout: TimeInterval
) async throws -> T {
try await withThrowingTaskGroup(of: T.self) { group in
group.addTask {
try await task()
Expand Down
2 changes: 2 additions & 0 deletions Sources/SuperwallKit/Config/Options/SuperwallOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ public final class SuperwallOptions: NSObject, Encodable {
case isExternalDataCollectionEnabled
case localeIdentifier
case isGameControllerEnabled
case collectAdServicesAttribution
}

public func encode(to encoder: Encoder) throws {
Expand All @@ -200,6 +201,7 @@ public final class SuperwallOptions: NSObject, Encodable {
try container.encode(isExternalDataCollectionEnabled, forKey: .isExternalDataCollectionEnabled)
try container.encode(localeIdentifier, forKey: .localeIdentifier)
try container.encode(isGameControllerEnabled, forKey: .isGameControllerEnabled)
try container.encode(collectAdServicesAttribution, forKey: .collectAdServicesAttribution)
}

func toDictionary() -> [String: Any] {
Expand Down
15 changes: 11 additions & 4 deletions Sources/SuperwallKit/Dependencies/DependencyContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ final class DependencyContainer {
receiptManager: receiptManager,
sessionEventsManager: sessionEventsManager,
identityManager: identityManager,
storage: storage,
factory: self
)
}
Expand Down Expand Up @@ -468,12 +469,18 @@ extension DependencyContainer: PurchasedTransactionsFactory {
return productPurchaser.coordinator
}

func purchase(product: SKProduct) async -> PurchaseResult {
return await productPurchaser.purchase(product: product)
func purchase(
product: SKProduct,
isExternal: Bool
) async -> PurchaseResult {
return await productPurchaser.purchase(
product: product,
isExternal: isExternal
)
}

func restorePurchases() async -> RestorationResult {
return await productPurchaser.restorePurchases()
func restorePurchases(isExternal: Bool) async -> RestorationResult {
return await productPurchaser.restorePurchases(isExternal: isExternal)
}
}

Expand Down
7 changes: 5 additions & 2 deletions Sources/SuperwallKit/Dependencies/FactoryProtocols.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,11 @@ protocol TriggerFactory: AnyObject {

protocol PurchasedTransactionsFactory {
func makePurchasingCoordinator() -> PurchasingCoordinator
func purchase(product: SKProduct) async -> PurchaseResult
func restorePurchases() async -> RestorationResult
func purchase(
product: SKProduct,
isExternal: Bool
) async -> PurchaseResult
func restorePurchases(isExternal: Bool) async -> RestorationResult
}

protocol UserAttributesEventFactory {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ The ``Superwall`` class is used to access all the features of the SDK. Before us
- ``SuperwallEventObjc``
- ``PaywallSkippedReason``
- ``PaywallSkippedReasonObjc``
- ``PaywallViewController``
- ``PaywallViewControllerDelegate``
- ``PaywallViewControllerDelegateObjc``

### Handling Purchases

- ``purchase(_:)``
- ``purchase(_:completion:)-6oyxm``
- ``purchase(_:completion:)-4rj6r``
- ``restorePurchases()``
- ``restorePurchases(completion:)-4fx45``
- ``restorePurchases(completion:)-4cxt5``

### In-App Previews

Expand Down
2 changes: 2 additions & 0 deletions Sources/SuperwallKit/Logger/LogScope.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public enum LogScope: Int, Encodable, Sendable, CustomStringConvertible {
case receipts
case superwallCore
case paywallPresentation

// TODO: In v4 rename to transactions
case paywallTransactions
case paywallViewController
case cache
Expand Down
2 changes: 1 addition & 1 deletion Sources/SuperwallKit/Misc/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ let sdkVersion = """
*/

let sdkVersion = """
3.9.1
3.10.0
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// PaywallLoadingState.swift
// SuperwallKit
//
// Created by Thomas LE GRAVIER on 03/10/2024.
//

import Foundation

/// Contains the possible loading states of a paywall.
@objc(SWKPaywallLoadingState)
public enum PaywallLoadingState: Int, Sendable {
/// The initial state of the paywall
case unknown

/// When a purchase is loading
case loadingPurchase

/// When the paywall URL is loading
case loadingURL

/// When the user has manually shown the spinner
case manualLoading

/// When everything has loaded.
case ready
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public enum PaywallCloseReason: Int, Codable, Equatable, Sendable, CustomStringC
case .webViewFailedToLoad:
return "webViewFailedToLoad"
case .manualClose:
return "manualClsoe"
return "manualClose"
case .none:
return "none"
}
Expand Down
62 changes: 55 additions & 7 deletions Sources/SuperwallKit/Paywall/Presentation/PaywallInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//
// Created by Yusuf Tör on 28/02/2022.
//
// swiftlint:disable file_length

import Foundation
import StoreKit
Expand Down Expand Up @@ -332,12 +333,12 @@ public final class PaywallInfo: NSObject {
extension PaywallInfo: Stubbable {
static func stub() -> PaywallInfo {
return PaywallInfo(
databaseId: "abc",
identifier: "1",
name: "Test",
cacheKey: "cacheKey",
buildId: "buildId",
url: URL(string: "https://www.google.com")!,
databaseId: "test",
identifier: "test",
name: "test",
cacheKey: "test",
buildId: "test",
url: URL(string: "https://superwall.com")!,
products: [],
productItems: [],
productIds: [],
Expand All @@ -361,7 +362,54 @@ extension PaywallInfo: Stubbable {
computedPropertyRequests: [],
surveys: [],
presentation: .init(
style: .fullscreen,
style: .none,
condition: .checkUserSubscription,
delay: 0
)
)
}

/// Used when purchasing internally.
static func empty() -> PaywallInfo {
return PaywallInfo(
databaseId: "",
identifier: "",
name: "",
cacheKey: "",
buildId: "",
url: URL(string: "https://superwall.com")!,
products: [],
productItems: [],
productIds: [],
fromEventData: nil,
responseLoadStartTime: nil,
responseLoadCompleteTime: nil,
responseLoadFailTime: nil,
webViewLoadStartTime: nil,
webViewLoadCompleteTime: nil,
webViewLoadFailTime: nil,
productsLoadStartTime: nil,
productsLoadFailTime: nil,
productsLoadCompleteTime: nil,
experiment: .init(
id: "0",
groupId: "0",
variant: .init(
id: "0",
type: .holdout,
paywallId: "0"
)
),
paywalljsVersion: nil,
isFreeTrialAvailable: false,
presentationSourceType: "",
featureGatingBehavior: .nonGated,
closeReason: .none,
localNotifications: [],
computedPropertyRequests: [],
surveys: [],
presentation: .init(
style: .none,
condition: .checkUserSubscription,
delay: 0
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,25 @@ public protocol PaywallViewControllerDelegate: AnyObject {
didFinishWith result: PaywallResult,
shouldDismiss: Bool
)

/// Tells the delegate that the loading state of the paywall did change.
///
/// - Parameters:
/// - paywall: The ``PaywallViewController`` that the user is interacting with.
/// - loadingState: A ``PaywallLoadingState`` enum that contains the loading state of
/// the ``PaywallViewController``.
@MainActor
func paywall(
_ paywall: PaywallViewController,
loadingStateDidChange loadingState: PaywallLoadingState
)
}

extension PaywallViewControllerDelegate {
public func paywall(
_ paywall: PaywallViewController,
loadingStateDidChange loadingState: PaywallLoadingState
) {}
}

/// Objective-C-only interface for responding to user interactions with a ``PaywallViewController`` that
Expand All @@ -52,6 +71,25 @@ public protocol PaywallViewControllerDelegateObjc: AnyObject {
didFinishWithResult result: PaywallResultObjc,
shouldDismiss: Bool
)

/// Tells the delegate that the loading state of the paywall did change.
///
/// - Parameters:
/// - paywall: The ``PaywallViewController`` that the user is interacting with.
/// - loadingState: A ``PaywallLoadingState`` enum that contains the loading state of
/// the ``PaywallViewController``.
@MainActor
func paywall(
_ paywall: PaywallViewController,
loadingStateDidChange loadingState: PaywallLoadingState
)
}

extension PaywallViewControllerDelegateObjc {
public func paywall(
_ paywall: PaywallViewController,
loadingStateDidChange loadingState: PaywallLoadingState
) {}
}

protocol PaywallViewControllerEventDelegate: AnyObject {
Expand All @@ -60,20 +98,3 @@ protocol PaywallViewControllerEventDelegate: AnyObject {
on paywallViewController: PaywallViewController
) async
}

enum PaywallLoadingState {
/// The initial state of the paywall
case unknown

/// When a purchase is loading
case loadingPurchase

/// When the paywall URL is loading
case loadingURL

/// When the user has manually shown the spinner
case manualLoading

/// When everything has loaded.
case ready
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ final class PaywallViewControllerDelegateAdapter {
swiftDelegate?.paywall(paywall, didFinishWith: result, shouldDismiss: shouldDismiss)
objcDelegate?.paywall(paywall, didFinishWithResult: result.convertForObjc(), shouldDismiss: shouldDismiss)
}

@MainActor
func loadingStateDidChange(
paywall: PaywallViewController,
loadingState: PaywallLoadingState
) {
swiftDelegate?.paywall(paywall, loadingStateDidChange: loadingState)
objcDelegate?.paywall(paywall, loadingStateDidChange: loadingState)
}
}

// MARK: - Stubbable
Expand Down
Loading

0 comments on commit 1fa4e91

Please sign in to comment.