From 2fbd822096b3c7bfec66ef57a8623cfd7f6eb26a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20To=CC=88r?= Date: Wed, 1 Mar 2023 18:33:29 +0000 Subject: [PATCH 1/7] Update AdvancedConfiguration.md --- .../SuperwallKit/Documentation.docc/AdvancedConfiguration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SuperwallKit/Documentation.docc/AdvancedConfiguration.md b/Sources/SuperwallKit/Documentation.docc/AdvancedConfiguration.md index bf2707ae8..b538bc39f 100644 --- a/Sources/SuperwallKit/Documentation.docc/AdvancedConfiguration.md +++ b/Sources/SuperwallKit/Documentation.docc/AdvancedConfiguration.md @@ -7,7 +7,7 @@ Use options and custom subscription-related logic for more control over the SDK. By default, Superwall handles all subscription-related logic. However, if you're using RevenueCat, or you just want more control, you can return a ``PurchaseController`` when configuring the SDK via ``Superwall/configure(apiKey:purchaseController:options:completion:)-52tke``. In addition, you can customise aspects of the SDK by passing in a ``SuperwallOptions`` object on configure. -## Creating a Subscription Controller +## Creating a Purchase Controller A purchase controller handles purchasing and restoring via protocol methods that you implement. You pass in your purchase controller when configuring the SDK: From 312ce449d9ce38ec0510e861c247557680516695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20To=CC=88r?= Date: Fri, 3 Mar 2023 17:24:04 +0000 Subject: [PATCH 2/7] Changes getTrackInfo to getTrackResult - Updates to beta 7. - Makes NetworkEnvironment objc compatible. --- CHANGELOG.md | 11 ++ .../xcshareddata/swiftpm/Package.resolved | 33 ++---- .../xcshareddata/swiftpm/Package.resolved | 16 --- .../Services/SSASuperwallService.m | 2 +- .../TrackEventViewController.swift | 7 +- README.md | 2 +- .../Config/Options/SuperwallOptions.swift | 2 +- .../Delegate/SuperwallDelegateObjc.swift | 2 +- .../Extensions/SuperwallExtension.md | 8 +- .../Identity/PublicIdentity.swift | 2 +- Sources/SuperwallKit/Misc/Constants.swift | 2 +- .../Models/Triggers/TriggerResult.swift | 5 - .../GetTrackResultLogic.swift | 25 ++++ ...ult.swift => InternalGetTrackResult.swift} | 24 +--- .../ConvertToTrackResultOperator.swift | 19 +++ .../PublicGetTrackResult.swift | 108 ++++++++++++++++++ .../Get Track Result/TrackResult.swift | 47 ++++++++ ...ackInfoObjc.swift => TrackValueObjc.swift} | 49 ++++---- .../Presentation/PublicPresentation.swift | 105 +---------------- Sources/SuperwallKit/Superwall.swift | 4 +- SuperwallKit.podspec | 2 +- 21 files changed, 273 insertions(+), 202 deletions(-) delete mode 100644 Examples/UIKit-ObjC/Superwall-UIKit-ObjC.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved create mode 100644 Sources/SuperwallKit/Paywall/Presentation/Get Track Result/GetTrackResultLogic.swift rename Sources/SuperwallKit/Paywall/Presentation/Get Track Result/{GetTrackResult.swift => InternalGetTrackResult.swift} (70%) create mode 100644 Sources/SuperwallKit/Paywall/Presentation/Get Track Result/Operators/ConvertToTrackResultOperator.swift create mode 100644 Sources/SuperwallKit/Paywall/Presentation/Get Track Result/PublicGetTrackResult.swift create mode 100644 Sources/SuperwallKit/Paywall/Presentation/Get Track Result/TrackResult.swift rename Sources/SuperwallKit/Paywall/Presentation/Get Track Result/{TrackInfoObjc.swift => TrackValueObjc.swift} (58%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50f41f8a1..5a8a85b6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ The changelog for `SuperwallKit`. Also see the [releases](https://github.com/superwall-me/Superwall-iOS/releases) on GitHub. +## 3.0.0-beta.7 + +### Breaking Changes + +- Changes Objective-C method `getTrackInfo` to `getTrackResult` to be in line with the Swift API. +- Removes the error case from the `TrackResult` and adds in `userIsSubscribed` and `paywallNotAvailable` cases. + +### Fixes + +- Makes `NetworkEnvironment` Objective-C compatible. + ## 3.0.0-beta.6 ### Breaking Changes diff --git a/Examples/UIKit+RevenueCat/Superwall-UIKit+RevenueCat.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Examples/UIKit+RevenueCat/Superwall-UIKit+RevenueCat.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 75e1345dd..68f3b545e 100644 --- a/Examples/UIKit+RevenueCat/Superwall-UIKit+RevenueCat.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Examples/UIKit+RevenueCat/Superwall-UIKit+RevenueCat.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,25 +1,14 @@ { - "object": { - "pins": [ - { - "package": "ASN1Swift", - "repositoryURL": "https://github.com/tikhop/ASN1Swift", - "state": { - "branch": null, - "revision": "b53bee03a942623db25afc5bfb80227b2cb3b425", - "version": "1.2.4" - } - }, - { - "package": "RevenueCat", - "repositoryURL": "https://github.com/RevenueCat/purchases-ios.git", - "state": { - "branch": null, - "revision": "390073e0dec72f2a4aabb1888ceda46a059808e5", - "version": "4.17.3" - } + "pins" : [ + { + "identity" : "purchases-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/RevenueCat/purchases-ios.git", + "state" : { + "revision" : "390073e0dec72f2a4aabb1888ceda46a059808e5", + "version" : "4.17.3" } - ] - }, - "version": 1 + } + ], + "version" : 2 } diff --git a/Examples/UIKit-ObjC/Superwall-UIKit-ObjC.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Examples/UIKit-ObjC/Superwall-UIKit-ObjC.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index d3548dd36..000000000 --- a/Examples/UIKit-ObjC/Superwall-UIKit-ObjC.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,16 +0,0 @@ -{ - "object": { - "pins": [ - { - "package": "ASN1Swift", - "repositoryURL": "https://github.com/tikhop/ASN1Swift", - "state": { - "branch": null, - "revision": "b53bee03a942623db25afc5bfb80227b2cb3b425", - "version": "1.2.4" - } - } - ] - }, - "version": 1 -} diff --git a/Examples/UIKit-ObjC/Superwall-UIKit-ObjC/Services/SSASuperwallService.m b/Examples/UIKit-ObjC/Superwall-UIKit-ObjC/Services/SSASuperwallService.m index a0ddcbea5..6cb12bba8 100644 --- a/Examples/UIKit-ObjC/Superwall-UIKit-ObjC/Services/SSASuperwallService.m +++ b/Examples/UIKit-ObjC/Superwall-UIKit-ObjC/Services/SSASuperwallService.m @@ -139,7 +139,7 @@ - (void)restorePurchasesWithCompletion:(void (^ _Nonnull)(BOOL))completion { - (void)didTrackSuperwallEventInfo:(SWKSuperwallEventInfo *)info { NSLog(@"Analytics event called %@", @(info.event)); - + // Uncomment the following if you want to track the different analytics events received from the paywall: // switch (info.event) { diff --git a/Examples/UIKit-Swift/Superwall-UIKit-Swift/TrackEventViewController.swift b/Examples/UIKit-Swift/Superwall-UIKit-Swift/TrackEventViewController.swift index 41ceba779..c1bb472c5 100644 --- a/Examples/UIKit-Swift/Superwall-UIKit-Swift/TrackEventViewController.swift +++ b/Examples/UIKit-Swift/Superwall-UIKit-Swift/TrackEventViewController.swift @@ -90,7 +90,7 @@ final class TrackEventViewController: UIViewController { // The below function gives an example of how to track an event using Combine publishers: /* func trackEventUsingCombine() { - cancellable = Superwall + cancellable = Superwall.shared .publisher(forEvent: "MyEvent") .sink { paywallState in switch paywallState { @@ -113,10 +113,13 @@ final class TrackEventViewController: UIViewController { print("The user is in a holdout group, with experiment id: \(experiment.id), group id: \(experiment.groupId), paywall id: \(experiment.variant.paywallId ?? "")") case .eventNotFound: print("The event wasn't found in a campaign on the dashboard.") + case .userIsSubscribed: + print("The user is subscribed.") case .error(let error): print("Failed to present paywall. Consider a native paywall fallback", error) } } } - }*/ + } + */ } diff --git a/README.md b/README.md index 7dd1d6899..394b26e2a 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ The preferred installation method is with [Swift Package Manager](https://swift. To include the *Superwall* SDK in your app, add the following to your Podfile: ``` -pod 'SuperwallKit', '3.0.0-beta.6' +pod 'SuperwallKit', '3.0.0-beta.7' ``` If you don't want to use the v3 beta, you'll need to add this instead: diff --git a/Sources/SuperwallKit/Config/Options/SuperwallOptions.swift b/Sources/SuperwallKit/Config/Options/SuperwallOptions.swift index a2d1f1cf4..40b535fc3 100644 --- a/Sources/SuperwallKit/Config/Options/SuperwallOptions.swift +++ b/Sources/SuperwallKit/Config/Options/SuperwallOptions.swift @@ -20,7 +20,7 @@ public final class SuperwallOptions: NSObject { /// **WARNING**: The different network environments that the SDK should use. /// Only use this enum to set ``SuperwallOptions/networkEnvironment-swift.property`` /// if told so explicitly by the Superwall team. - public enum NetworkEnvironment { + public enum NetworkEnvironment: Int { /// Default: Uses the standard latest environment. case release /// **WARNING**: Uses a release candidate environment. This is not meant for a production environment. diff --git a/Sources/SuperwallKit/Delegate/SuperwallDelegateObjc.swift b/Sources/SuperwallKit/Delegate/SuperwallDelegateObjc.swift index 0c7461481..a8f43af8c 100644 --- a/Sources/SuperwallKit/Delegate/SuperwallDelegateObjc.swift +++ b/Sources/SuperwallKit/Delegate/SuperwallDelegateObjc.swift @@ -7,7 +7,7 @@ import Foundation -/// The objective-c only delegate protocol that handles Superwall lifecycle events. +/// Objective-C-only delegate protocol that handles Superwall lifecycle events. /// /// The delegate methods receive callbacks from the SDK in response to certain events that happen on the paywall. /// diff --git a/Sources/SuperwallKit/Documentation.docc/Extensions/SuperwallExtension.md b/Sources/SuperwallKit/Documentation.docc/Extensions/SuperwallExtension.md index 44dee3183..e8db7bbfc 100644 --- a/Sources/SuperwallKit/Documentation.docc/Extensions/SuperwallExtension.md +++ b/Sources/SuperwallKit/Documentation.docc/Extensions/SuperwallExtension.md @@ -37,13 +37,15 @@ The ``Superwall`` class is used to access all the features of the SDK. Before us - ``track(event:params:)`` - ``track(event:onSkip:onPresent:onDismiss:)`` - ``track(event:params:onSkip:onPresent:onDismiss:)`` -- ``getTrackResult(forEvent:params:)`` -- ``getTrackResult(forEvent:params:completion:)`` -- ``getTrackInfo(forEvent:params:)`` - ``publisher(forEvent:params:paywallOverrides:)`` +- ``getTrackResult(forEvent:params:)-1qexk`` +- ``getTrackResult(forEvent:params:completion:)`` +- ``getTrackResult(forEvent:params:)-2j7qn`` - ``dismiss()-844a9`` - ``dismiss()-4objm`` - ``dismiss(completion:)`` +- ``TrackResult`` +- ``TrackResultObjc`` - ``PaywallInfo`` - ``SuperwallEvent`` - ``SuperwallEventObjc`` diff --git a/Sources/SuperwallKit/Identity/PublicIdentity.swift b/Sources/SuperwallKit/Identity/PublicIdentity.swift index aca374203..ef0d11283 100644 --- a/Sources/SuperwallKit/Identity/PublicIdentity.swift +++ b/Sources/SuperwallKit/Identity/PublicIdentity.swift @@ -31,7 +31,7 @@ extension Superwall { ) } - /// Objective-C only method. Creates an account with Superwall. This links a `userId` to Superwall's automatically generated alias. + /// Objective-C-only method. Creates an account with Superwall. This links a `userId` to Superwall's automatically generated alias. /// /// Call this as soon as you have a `userId`. /// diff --git a/Sources/SuperwallKit/Misc/Constants.swift b/Sources/SuperwallKit/Misc/Constants.swift index 3a1e1cdf1..cc97291aa 100644 --- a/Sources/SuperwallKit/Misc/Constants.swift +++ b/Sources/SuperwallKit/Misc/Constants.swift @@ -18,5 +18,5 @@ let sdkVersion = """ */ let sdkVersion = """ -3.0.0-beta.6 +3.0.0-beta.7 """ diff --git a/Sources/SuperwallKit/Models/Triggers/TriggerResult.swift b/Sources/SuperwallKit/Models/Triggers/TriggerResult.swift index 4b9d711af..e34a2afc6 100644 --- a/Sources/SuperwallKit/Models/Triggers/TriggerResult.swift +++ b/Sources/SuperwallKit/Models/Triggers/TriggerResult.swift @@ -7,11 +7,6 @@ import Foundation -/// The result of a tracking an event. -/// -/// Contains the possible cases resulting from tracking an event. -public typealias TrackResult = TriggerResult - /// The result of a paywall trigger. /// /// Triggers can conditionally show paywalls. Contains the possible cases resulting from the trigger. diff --git a/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/GetTrackResultLogic.swift b/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/GetTrackResultLogic.swift new file mode 100644 index 000000000..ad43ba6b8 --- /dev/null +++ b/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/GetTrackResultLogic.swift @@ -0,0 +1,25 @@ +// +// File.swift +// +// +// Created by Yusuf Tör on 03/03/2023. +// + +import Foundation + +enum GetTrackResultLogic { + static func convertTriggerResult(_ triggerResult: TriggerResult) -> TrackResult { + switch triggerResult { + case .eventNotFound: + return .eventNotFound + case .holdout(let experiment): + return .holdout(experiment) + case .error: + return .paywallNotAvailable + case .noRuleMatch: + return .noRuleMatch + case .paywall(let paywall): + return .paywall(paywall) + } + } +} diff --git a/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/GetTrackResult.swift b/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/InternalGetTrackResult.swift similarity index 70% rename from Sources/SuperwallKit/Paywall/Presentation/Get Track Result/GetTrackResult.swift rename to Sources/SuperwallKit/Paywall/Presentation/Get Track Result/InternalGetTrackResult.swift index 2bec0225b..e7d334d10 100644 --- a/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/GetTrackResult.swift +++ b/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/InternalGetTrackResult.swift @@ -37,6 +37,7 @@ extension Superwall { .checkForPaywallResult() .getPaywallViewControllerNoChecks() .checkPaywallIsPresentable() + .convertToTrackResult() .async() } } @@ -58,27 +59,12 @@ extension Publisher where Output == TrackResult { case let error as GetTrackResultError: switch error { case .willNotPresent(let result): - continuation.resume(with: .success(result)) + let trackResult = GetTrackResultLogic.convertTriggerResult(result) + continuation.resume(with: .success(trackResult)) case .userIsSubscribed: - let userInfo: [String: Any] = [ - "Already Subscribed": "The user has an active subscription so the paywall won't show." - ] - let error = NSError( - domain: "com.superwall", - code: 404, - userInfo: userInfo - ) - continuation.resume(with: .success(.error(error))) + continuation.resume(with: .success(.userIsSubscribed)) case .paywallNotAvailable: - let userInfo: [String: Any] = [ - "Paywall View Controller Error": "There was an issue retrieving the Paywall View Controller." - ] - let error = NSError( - domain: "com.superwall", - code: 404, - userInfo: userInfo - ) - continuation.resume(with: .success(.error(error))) + continuation.resume(with: .success(.paywallNotAvailable)) } default: break diff --git a/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/Operators/ConvertToTrackResultOperator.swift b/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/Operators/ConvertToTrackResultOperator.swift new file mode 100644 index 000000000..7126b3b1a --- /dev/null +++ b/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/Operators/ConvertToTrackResultOperator.swift @@ -0,0 +1,19 @@ +// +// File.swift +// +// +// Created by Yusuf Tör on 03/03/2023. +// + +import Foundation +import Combine + +extension AnyPublisher where Output == TriggerResult, Failure == Error { + /// Checks whether the trigger result indicates that a paywall should show. + func convertToTrackResult() -> AnyPublisher { + map { input in + return GetTrackResultLogic.convertTriggerResult(input) + } + .eraseToAnyPublisher() + } +} diff --git a/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/PublicGetTrackResult.swift b/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/PublicGetTrackResult.swift new file mode 100644 index 000000000..fc64e81ee --- /dev/null +++ b/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/PublicGetTrackResult.swift @@ -0,0 +1,108 @@ +// +// File.swift +// +// +// Created by Yusuf Tör on 03/03/2023. +// + +import Foundation + +extension Superwall { + /// Preemptively get the result of tracking an event. + /// + /// Use this function if you want to preemptively get the result of tracking + /// an event. + /// + /// This is useful for when you want to know whether a particular event will + /// present a paywall in the future. + /// + /// Note that this method does not present a paywall. To do that, use + /// ``track(event:params:paywallOverrides:paywallHandler:)``. + /// + /// - Parameters: + /// - event: The name of the event you want to track. + /// - params: Optional parameters you'd like to pass with your event. + /// + /// - Returns: A ``TrackResult`` that indicates the result of tracking an event. + public func getTrackResult( + forEvent event: String, + params: [String: Any]? = nil + ) async -> TrackResult { + let eventCreatedAt = Date() + + let trackableEvent = UserInitiatedEvent.Track( + rawName: event, + canImplicitlyTriggerPaywall: false, + customParameters: params ?? [:] + ) + + let parameters = await TrackingLogic.processParameters( + fromTrackableEvent: trackableEvent, + eventCreatedAt: eventCreatedAt, + appSessionId: dependencyContainer.appSessionManager.appSession.id + ) + + let eventData = EventData( + name: event, + parameters: JSON(parameters.eventParams), + createdAt: eventCreatedAt + ) + + let presentationRequest = dependencyContainer.makePresentationRequest( + .explicitTrigger(eventData), + isDebuggerLaunched: false, + isPaywallPresented: false + ) + + return await getTrackResult(for: presentationRequest) + } + + /// Preemptively get the result of tracking an event. + /// + /// Use this function if you want to preemptively get the result of tracking + /// an event. + /// + /// This is useful for when you want to know whether a particular event will + /// present a paywall in the future. + /// + /// Note that this method does not present a paywall. To do that, use + /// ``track(event:params:paywallOverrides:paywallHandler:)``. + /// + /// - Parameters: + /// - event: The name of the event you want to track. + /// - params: Optional parameters you'd like to pass with your event. + /// - completion: A completion block that accepts a ``TrackResult`` indicating + /// the result of tracking an event. + public func getTrackResult( + forEvent event: String, + params: [String: Any]? = nil, + completion: @escaping (TrackResult) -> Void + ) { + Task { + let result = await getTrackResult(forEvent: event, params: params) + completion(result) + } + } + + /// Objective-C-only function to preemptively get the result of tracking an event. + /// + /// This is useful for when you want to know whether a particular event will + /// present a paywall in the future. + /// + /// Note that this method does not present a paywall. To do that, use + /// ``track(event:params:products:ignoreSubscriptionStatus:presentationStyleOverride:onSkip:onPresent:onDismiss:)``. + /// + /// - Parameters: + /// - event: The name of the event you want to track. + /// - params: Optional parameters you'd like to pass with your event. + /// + /// - Returns: A ``TrackResultObjc`` object that contains information about the result of tracking an event. + @available(swift, obsoleted: 1.0) + @objc public func getTrackResult( + forEvent event: String, + params: [String: Any]? = nil + ) async -> TrackResultObjc { + let result = await getTrackResult(forEvent: event, params: params) + return TrackResultObjc(trackResult: result) + } +} diff --git a/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/TrackResult.swift b/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/TrackResult.swift new file mode 100644 index 000000000..03fd9fee2 --- /dev/null +++ b/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/TrackResult.swift @@ -0,0 +1,47 @@ +// +// File.swift +// +// +// Created by Yusuf Tör on 03/03/2023. +// + +import Foundation + +/// The result of a tracking an event. +/// +/// Contains the possible cases resulting from tracking an event. +public enum TrackResult: Sendable, Equatable { + /// This event was not found on the dashboard. + /// + /// Please make sure you have added the event to a campaign on the dashboard and + /// double check its spelling. + case eventNotFound + + /// No matching rule was found for this trigger so no paywall will be shown. + case noRuleMatch + + /// A matching rule was found and this user will be shown a paywall. + /// + /// - Parameters: + /// - experiment: The experiment associated with the trigger. + case paywall(Experiment) + + /// A matching rule was found and this user was assigned to a holdout group so will not be shown a paywall. + /// + /// - Parameters: + /// - experiment: The experiment associated with the trigger. + case holdout(Experiment) + + /// The user is subscribed. + /// + /// This means ``Superwall/subscriptionStatus`` is set to `.active`. If you're + /// letting Superwall handle subscription-related logic, it will be based on the on-device + /// receipts. Otherwise it'll be based on the value you've set. + /// + /// By default, paywalls do not show to users who are already subscribed. You can override this + /// behavior in the paywall editor. + case userIsSubscribed + + /// No view controller could be found to present on. + case paywallNotAvailable +} diff --git a/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/TrackInfoObjc.swift b/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/TrackValueObjc.swift similarity index 58% rename from Sources/SuperwallKit/Paywall/Presentation/Get Track Result/TrackInfoObjc.swift rename to Sources/SuperwallKit/Paywall/Presentation/Get Track Result/TrackValueObjc.swift index 4f65ba0ce..2677b4193 100644 --- a/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/TrackInfoObjc.swift +++ b/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/TrackValueObjc.swift @@ -10,8 +10,8 @@ import Foundation /// The result of tracking an event. /// /// Contains the possible cases resulting from tracking an event. -@objc(SWKTrackResult) -public enum TrackResultObjc: Int, Sendable, Equatable { +@objc(SWKTrackValue) +public enum TrackValueObjc: Int, Sendable, Equatable { /// This event was not found on the dashboard. /// /// Please make sure you have added the event to a campaign on the dashboard and @@ -27,16 +27,26 @@ public enum TrackResultObjc: Int, Sendable, Equatable { /// A matching rule was found and this user was assigned to a holdout group so will not be shown a paywall. case holdout - /// An error occurred and the user will not be shown a paywall. - case error + /// No view controller could be found to present on. + case paywallNotAvailable + + /// The user is subscribed. + /// + /// This means ``Superwall/subscriptionStatus`` is set to `.active`. If you're + /// letting Superwall handle subscription-related logic, it will be based on the on-device + /// receipts. Otherwise it'll be based on the value you've set. + /// + /// By default, paywalls do not show to users who are already subscribed. You can override this + /// behavior in the paywall editor. + case userIsSubscribed } /// Information about the result of tracking an event. -@objc(SWKTrackInfo) +@objc(SWKTrackResult) @objcMembers -public final class TrackInfoObjc: NSObject, Sendable { +public final class TrackResultObjc: NSObject, Sendable { /// The result of tracking an event. - public let result: TrackResultObjc + public let value: TrackValueObjc /// A campaign experiment that was assigned to a user. /// @@ -44,31 +54,26 @@ public final class TrackInfoObjc: NSObject, Sendable { /// a `paywall`. public let experiment: Experiment? - /// The error returned when the `result` is an `error`. - public let error: NSError? - init(trackResult: TrackResult) { switch trackResult { case .paywall(let experiment): - self.result = .paywall + self.value = .paywall self.experiment = experiment - self.error = nil - case .error(let error): - self.result = .error - self.experiment = nil - self.error = error case .eventNotFound: - self.result = .eventNotFound + self.value = .eventNotFound self.experiment = nil - self.error = nil case .holdout(let experiment): - self.result = .holdout + self.value = .holdout self.experiment = experiment - self.error = nil case .noRuleMatch: - self.result = .noRuleMatch + self.value = .noRuleMatch + self.experiment = nil + case .userIsSubscribed: + self.value = .userIsSubscribed + self.experiment = nil + case .paywallNotAvailable: + self.value = .paywallNotAvailable self.experiment = nil - self.error = nil } } } diff --git a/Sources/SuperwallKit/Paywall/Presentation/PublicPresentation.swift b/Sources/SuperwallKit/Paywall/Presentation/PublicPresentation.swift index d1f95a390..bfe1cb9bb 100644 --- a/Sources/SuperwallKit/Paywall/Presentation/PublicPresentation.swift +++ b/Sources/SuperwallKit/Paywall/Presentation/PublicPresentation.swift @@ -27,7 +27,7 @@ extension Superwall { } } - /// Objective-C only method. Dismisses the presented paywall. + /// Objective-C-only method. Dismisses the presented paywall. @available(swift, obsoleted: 1.0) @objc public func dismiss() { Task { @@ -429,109 +429,6 @@ extension Superwall { .eraseToAnyPublisher() } - // MARK: - Get Track Result - - /// Preemptively get the result of tracking an event. - /// - /// Use this function if you want to preemptively get the result of tracking - /// an event. - /// - /// This is useful for when you want to know whether a particular event will - /// present a paywall in the future. - /// - /// Note that this method does not present a paywall. To do that, use - /// ``track(event:params:paywallOverrides:paywallHandler:)``. - /// - /// - Parameters: - /// - event: The name of the event you want to track. - /// - params: Optional parameters you'd like to pass with your event. - /// - /// - Returns: A ``TrackResult`` that indicates the result of tracking an event. - public func getTrackResult( - forEvent event: String, - params: [String: Any]? = nil - ) async -> TrackResult { - let eventCreatedAt = Date() - - let trackableEvent = UserInitiatedEvent.Track( - rawName: event, - canImplicitlyTriggerPaywall: false, - customParameters: params ?? [:] - ) - - let parameters = await TrackingLogic.processParameters( - fromTrackableEvent: trackableEvent, - eventCreatedAt: eventCreatedAt, - appSessionId: dependencyContainer.appSessionManager.appSession.id - ) - - let eventData = EventData( - name: event, - parameters: JSON(parameters.eventParams), - createdAt: eventCreatedAt - ) - - let presentationRequest = dependencyContainer.makePresentationRequest( - .explicitTrigger(eventData), - isDebuggerLaunched: false, - isPaywallPresented: false - ) - - return await getTrackResult(for: presentationRequest) - } - - /// Preemptively get the result of tracking an event. - /// - /// Use this function if you want to preemptively get the result of tracking - /// an event. - /// - /// This is useful for when you want to know whether a particular event will - /// present a paywall in the future. - /// - /// Note that this method does not present a paywall. To do that, use - /// ``track(event:params:paywallOverrides:paywallHandler:)``. - /// - /// - Parameters: - /// - event: The name of the event you want to track. - /// - params: Optional parameters you'd like to pass with your event. - /// - completion: A completion block that accepts a ``TrackResult`` indicating - /// the result of tracking an event. - public func getTrackResult( - forEvent event: String, - params: [String: Any]? = nil, - completion: @escaping (TrackResult) -> Void - ) { - Task { - let result = await getTrackResult(forEvent: event, params: params) - completion(result) - } - } - - /// Objective-C only function to get information about the result of tracking an event. - /// - /// Use this function if you want to preemptively get the result of tracking - /// an event. - /// - /// This is useful for when you want to know whether a particular event will - /// present a paywall in the future. - /// - /// Note that this method does not present a paywall. To do that, use - /// ``track(event:params:products:ignoreSubscriptionStatus:presentationStyleOverride:onSkip:onPresent:onDismiss:)``. - /// - /// - Parameters: - /// - event: The name of the event you want to track. - /// - params: Optional parameters you'd like to pass with your event. - /// - /// - Returns: A ``TrackInfoObjc`` object that contains information about the result of tracking an event. - @available(swift, obsoleted: 1.0) - @objc public func getTrackInfo( - forEvent event: String, - params: [String: Any]? = nil - ) async -> TrackInfoObjc { - let result = await getTrackResult(forEvent: event, params: params) - return TrackInfoObjc(trackResult: result) - } - /// Converts dismissal result from enums with associated values, to old objective-c compatible way /// /// - Parameters: diff --git a/Sources/SuperwallKit/Superwall.swift b/Sources/SuperwallKit/Superwall.swift index 2d2dffcde..e74b0725a 100644 --- a/Sources/SuperwallKit/Superwall.swift +++ b/Sources/SuperwallKit/Superwall.swift @@ -277,7 +277,7 @@ public final class Superwall: NSObject, ObservableObject { return shared } - /// Objective-C only function that configures a shared instance of ``Superwall`` for use throughout your app. + /// Objective-C-only function that configures a shared instance of ``Superwall`` for use throughout your app. /// /// Call this as soon as your app finishes launching in `application(_:didFinishLaunchingWithOptions:)`. Check out /// our article for a tutorial on how to configure the SDK. @@ -307,7 +307,7 @@ public final class Superwall: NSObject, ObservableObject { ) } - /// Objective-C only function that configures a shared instance of ``Superwall`` for use throughout your app. + /// Objective-C-only function that configures a shared instance of ``Superwall`` for use throughout your app. /// /// Call this as soon as your app finishes launching in `application(_:didFinishLaunchingWithOptions:)`. Check out /// our article for a tutorial on how to configure the SDK. diff --git a/SuperwallKit.podspec b/SuperwallKit.podspec index cc61aba7a..e69214ffb 100644 --- a/SuperwallKit.podspec +++ b/SuperwallKit.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "SuperwallKit" - s.version = "3.0.0-beta.6" + s.version = "3.0.0-beta.7" s.summary = "Superwall: In-App Paywalls Made Easy" s.description = "Paywall infrastructure for mobile apps :) we make things like editing your paywall and running price tests as easy as clicking a few buttons. superwall.com" From 69fae15115842673f0b124a2859d45486e4fbdcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20To=CC=88r?= Date: Mon, 6 Mar 2023 12:02:22 +0000 Subject: [PATCH 3/7] Added objc convenience func for getTrackResult --- .../PublicGetTrackResult.swift | 20 +++++++++++++++++++ ...swift => WaitToPresentOperatorTests.swift} | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) rename Tests/SuperwallKitTests/Paywall/Presentation/Internal Presentation/Operators/{AwaitIdentityOperatorTests.swift => WaitToPresentOperatorTests.swift} (98%) diff --git a/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/PublicGetTrackResult.swift b/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/PublicGetTrackResult.swift index fc64e81ee..179539e7b 100644 --- a/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/PublicGetTrackResult.swift +++ b/Sources/SuperwallKit/Paywall/Presentation/Get Track Result/PublicGetTrackResult.swift @@ -105,4 +105,24 @@ extension Superwall { let result = await getTrackResult(forEvent: event, params: params) return TrackResultObjc(trackResult: result) } + + /// Objective-C-only function to preemptively get the result of tracking an event. + /// + /// This is useful for when you want to know whether a particular event will + /// present a paywall in the future. + /// + /// Note that this method does not present a paywall. To do that, use + /// ``track(event:params:products:ignoreSubscriptionStatus:presentationStyleOverride:onSkip:onPresent:onDismiss:)``. + /// + /// - Parameters: + /// - event: The name of the event you want to track. + /// + /// - Returns: A ``TrackResultObjc`` object that contains information about the result of tracking an event. + @available(swift, obsoleted: 1.0) + @objc public func getTrackResult( + forEvent event: String + ) async -> TrackResultObjc { + let result = await getTrackResult(forEvent: event, params: nil) + return TrackResultObjc(trackResult: result) + } } diff --git a/Tests/SuperwallKitTests/Paywall/Presentation/Internal Presentation/Operators/AwaitIdentityOperatorTests.swift b/Tests/SuperwallKitTests/Paywall/Presentation/Internal Presentation/Operators/WaitToPresentOperatorTests.swift similarity index 98% rename from Tests/SuperwallKitTests/Paywall/Presentation/Internal Presentation/Operators/AwaitIdentityOperatorTests.swift rename to Tests/SuperwallKitTests/Paywall/Presentation/Internal Presentation/Operators/WaitToPresentOperatorTests.swift index abd52209c..985730108 100644 --- a/Tests/SuperwallKitTests/Paywall/Presentation/Internal Presentation/Operators/AwaitIdentityOperatorTests.swift +++ b/Tests/SuperwallKitTests/Paywall/Presentation/Internal Presentation/Operators/WaitToPresentOperatorTests.swift @@ -9,7 +9,7 @@ import XCTest @testable import SuperwallKit import Combine -final class AwaitIdentityOperatorTests: XCTestCase { +final class WaitToPresentTests: XCTestCase { var cancellables: [AnyCancellable] = [] let dependencyContainer = DependencyContainer() var identityManager: IdentityManager { From c5535eec99aa3c2b7e3c8368851bbfa39fab30e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20To=CC=88r?= Date: Tue, 7 Mar 2023 13:15:56 +0000 Subject: [PATCH 4/7] Update CHANGELOG.md --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a8a85b6d..e2979df28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,6 @@ The changelog for `SuperwallKit`. Also see the [releases](https://github.com/sup - `reset` is no longer an async function. - `presentedViewController` and `latestPaywallInfo` no longer restricted to the main actor. - Removes `localizationOverride(localeIdentifier:)` and replaces it with the `SuperwallOption` `localeIdentifier`. You set this on configure. -- `setUserAttributes(_:)` is now an async function. It always was async under the hood but this makes it more explicit and helps you avoid race conditions. - Removes delegate from `configure`. You now set the delegate via `Superwall.shared.delegate`. - Removes `presenter` introduced in beta 5. - Removes ASN1Swift as a package dependency. From fc1ee71a23ebd459815d7040664f609ed8fd2766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20To=CC=88r?= Date: Wed, 8 Mar 2023 16:32:12 +0000 Subject: [PATCH 5/7] Bugfix for occasional crash when window destroyed --- CHANGELOG.md | 1 + Sources/SuperwallKit/Config/ConfigManager.swift | 2 +- .../Paywall/Manager/PaywallManager.swift | 15 ++++----------- .../Manager/PaywallViewControllerCache.swift | 9 +++++---- .../Paywall/Presentation/PresentationItems.swift | 5 +++-- .../Paywall/Presentation/PublicPresentation.swift | 8 ++++---- .../View Controller/PaywallViewController.swift | 8 -------- 7 files changed, 18 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2979df28..f9a35cf53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The changelog for `SuperwallKit`. Also see the [releases](https://github.com/sup ### Fixes - Makes `NetworkEnvironment` Objective-C compatible. +- Fixes an issue where a manually dismissed modally presented paywall wouldn't properly dismiss. ## 3.0.0-beta.6 diff --git a/Sources/SuperwallKit/Config/ConfigManager.swift b/Sources/SuperwallKit/Config/ConfigManager.swift index 7d956945f..80c644a4c 100644 --- a/Sources/SuperwallKit/Config/ConfigManager.swift +++ b/Sources/SuperwallKit/Config/ConfigManager.swift @@ -259,7 +259,7 @@ class ConfigManager { /// Preloads paywalls referenced by triggers. private func preloadPaywalls(withIdentifiers paywallIdentifiers: Set) { for identifier in paywallIdentifiers { - Task { + Task { [unowned self] in let request = factory.makePaywallRequest( eventData: nil, responseIdentifiers: .init(paywallId: identifier), diff --git a/Sources/SuperwallKit/Paywall/Manager/PaywallManager.swift b/Sources/SuperwallKit/Paywall/Manager/PaywallManager.swift index 00390fcbb..ac7f8c12c 100644 --- a/Sources/SuperwallKit/Paywall/Manager/PaywallManager.swift +++ b/Sources/SuperwallKit/Paywall/Manager/PaywallManager.swift @@ -25,8 +25,8 @@ class PaywallManager { self.paywallRequestManager = paywallRequestManager } - func removePaywallViewController(forKey: String) { - cache.removePaywallViewController(forKey: forKey) + func removePaywallViewController(forKey key: String) { + cache.removePaywallViewController(forKey: key) } func resetCache() { @@ -69,15 +69,8 @@ class PaywallManager { ) cache.save(paywallViewController, forKey: cacheKey) - if let window = UIApplication.shared.activeWindow { - paywallViewController.view.alpha = 0.01 - window.addSubview(paywallViewController.view) - paywallViewController.view.transform = CGAffineTransform( - translationX: UIScreen.main.bounds.width, - y: 0 - ) - .scaledBy(x: 0.1, y: 0.1) - } + // Preloads the view. + _ = paywallViewController.view return paywallViewController } diff --git a/Sources/SuperwallKit/Paywall/Manager/PaywallViewControllerCache.swift b/Sources/SuperwallKit/Paywall/Manager/PaywallViewControllerCache.swift index 87a9fdcca..e0b33cb65 100644 --- a/Sources/SuperwallKit/Paywall/Manager/PaywallViewControllerCache.swift +++ b/Sources/SuperwallKit/Paywall/Manager/PaywallViewControllerCache.swift @@ -23,11 +23,12 @@ final class PaywallViewControllerCache: @unchecked Sendable { private var _activePaywallVcKey: String? var activePaywallViewController: PaywallViewController? { - guard let activePaywallVcKey = activePaywallVcKey else { - return nil + queue.sync { [unowned self] in + guard let activePaywallVcKey = _activePaywallVcKey else { + return nil + } + return cache[activePaywallVcKey] } - - return getPaywallViewController(forKey: activePaywallVcKey) } private let queue = DispatchQueue(label: "com.superwall.paywallcache") diff --git a/Sources/SuperwallKit/Paywall/Presentation/PresentationItems.swift b/Sources/SuperwallKit/Paywall/Presentation/PresentationItems.swift index b35d06480..79bb6b047 100644 --- a/Sources/SuperwallKit/Paywall/Presentation/PresentationItems.swift +++ b/Sources/SuperwallKit/Paywall/Presentation/PresentationItems.swift @@ -50,8 +50,9 @@ final class PresentationItems: @unchecked Sendable { self._last = nil self._paywallInfo = nil } - Task { @MainActor in - window = nil + + Task { @MainActor [weak self] in + self?.window = nil } } } diff --git a/Sources/SuperwallKit/Paywall/Presentation/PublicPresentation.swift b/Sources/SuperwallKit/Paywall/Presentation/PublicPresentation.swift index bfe1cb9bb..700761103 100644 --- a/Sources/SuperwallKit/Paywall/Presentation/PublicPresentation.swift +++ b/Sources/SuperwallKit/Paywall/Presentation/PublicPresentation.swift @@ -21,8 +21,8 @@ extension Superwall { /// - Parameter completion: An optional completion block that gets called after the paywall is dismissed. /// Defaults to `nil`. @objc public func dismiss(completion: (() -> Void)? = nil) { - Task { - await dismiss() + Task { [weak self] in + await self?.dismiss() completion?() } } @@ -30,8 +30,8 @@ extension Superwall { /// Objective-C-only method. Dismisses the presented paywall. @available(swift, obsoleted: 1.0) @objc public func dismiss() { - Task { - await dismiss() + Task { [weak self] in + await self?.dismiss() } } diff --git a/Sources/SuperwallKit/Paywall/View Controller/PaywallViewController.swift b/Sources/SuperwallKit/Paywall/View Controller/PaywallViewController.swift index 9d8b00358..5d42962ab 100644 --- a/Sources/SuperwallKit/Paywall/View Controller/PaywallViewController.swift +++ b/Sources/SuperwallKit/Paywall/View Controller/PaywallViewController.swift @@ -179,10 +179,6 @@ class PaywallViewController: UIViewController, SWWebViewDelegate, LoadingDelegat fatalError("init(coder:) has not been implemented") } - deinit { - cache?.removePaywallViewController(forKey: cacheKey) - } - override func viewDidLoad() { super.viewDidLoad() configureUI() @@ -475,7 +471,6 @@ class PaywallViewController: UIViewController, SWWebViewDelegate, LoadingDelegat || isBeingPresented { return completion(false) } - addShimmerView(onPresent: true) prepareForPresentation() @@ -643,9 +638,6 @@ extension PaywallViewController { override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) - if view.window == nil { - return - } guard isPresented else { return } From 9f93421585d3dc54a26abad3440d93323e6c214d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20To=CC=88r?= Date: Thu, 9 Mar 2023 12:09:36 +0000 Subject: [PATCH 6/7] Added a dispatch group --- .../SuperwallKit/Identity/IdentityManager.swift | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Sources/SuperwallKit/Identity/IdentityManager.swift b/Sources/SuperwallKit/Identity/IdentityManager.swift index a6ffd95eb..5f9c497b7 100644 --- a/Sources/SuperwallKit/Identity/IdentityManager.swift +++ b/Sources/SuperwallKit/Identity/IdentityManager.swift @@ -12,6 +12,9 @@ // synchronised via a dispatch queue. When writing, use queue.async, when // reading use a computed var with a queue.sync block. You do not need to // use the queue during init. +// A Dispatch Group is used when calling functions that will call didSetIdentity. +// This is to prevent the case where identitySubject sends a true value before +// all functions affecting the identity have finished. // // ******************************************************************* @@ -80,6 +83,7 @@ class IdentityManager { /// When `false`, the SDK is unable to present paywalls. private let identitySubject = CurrentValueSubject(false) private let queue = DispatchQueue(label: "com.superwall.identitymanager") + private let group = DispatchGroup() private unowned let deviceHelper: DeviceHelper private unowned let storage: Storage @@ -100,6 +104,7 @@ class IdentityManager { /// Checks for static config upgrade before setting identity. func configure() async { + group.enter() let neverCalledStaticConfig = storage.neverCalledStaticConfig let isFirstAppOpen = !(storage.get(DidTrackFirstSeen.self) ?? false) @@ -110,6 +115,7 @@ class IdentityManager { ) { await configManager.getAssignments() } + group.leave() didSetIdentity() } @@ -129,6 +135,8 @@ class IdentityManager { return } + group.enter() + queue.async { [weak self] in guard let self = self else { return @@ -156,6 +164,7 @@ class IdentityManager { Task.detached { await self.configManager.getAssignments() } + self.group.leave() self.didSetIdentity() } @@ -167,6 +176,7 @@ class IdentityManager { if options.restorePaywallAssignments { Task { await self.configManager.getAssignments() + self.group.leave() self.didSetIdentity() } } else { @@ -181,7 +191,9 @@ class IdentityManager { /// Sends a `true` value to the `identitySubject` in order to fire /// triggers after reset. func didSetIdentity() { - identitySubject.send(true) + group.notify(queue: .main) { [weak self] in + self?.identitySubject.send(true) + } } /// Saves the aliasId and appUserId to storage and user attributes. @@ -220,8 +232,10 @@ extension IdentityManager { if duringIdentify { self._reset() } else { + group.enter() queue.async { [weak self] in self?._reset() + self?.group.leave() self?.didSetIdentity() } } From e9a6661af8028d6e8d6a853fe13bc690fe6beb89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20To=CC=88r?= Date: Thu, 9 Mar 2023 12:35:01 +0000 Subject: [PATCH 7/7] PurchaseController mainactor conformance moved to funcs and setUserAttributesDictionary changed for objc --- CHANGELOG.md | 3 +++ .../Services/SSASuperwallService.m | 2 +- .../Subscription Controller/PurchaseController.swift | 3 ++- .../PurchaseControllerObjc.swift | 3 ++- .../Extensions/SuperwallExtension.md | 5 +++-- .../Documentation.docc/SettingUserAttributes.md | 2 +- Sources/SuperwallKit/Identity/UserAttributes.swift | 4 ++-- .../Paywall/Presentation/PublicPresentation.swift | 10 +++++----- Sources/SuperwallKit/Superwall.swift | 2 +- 9 files changed, 20 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9a35cf53..c6385683c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,14 @@ The changelog for `SuperwallKit`. Also see the [releases](https://github.com/sup - Changes Objective-C method `getTrackInfo` to `getTrackResult` to be in line with the Swift API. - Removes the error case from the `TrackResult` and adds in `userIsSubscribed` and `paywallNotAvailable` cases. +- Moves main actor conformance to functions of PurchaseController protocol rather than the whole protocol. +- Changes Objective-C method `setUserAttributesDictionary(_:)` to `setUserAttributes(_:)`. ### Fixes - Makes `NetworkEnvironment` Objective-C compatible. - Fixes an issue where a manually dismissed modally presented paywall wouldn't properly dismiss. +- Fixes race condition when calling identify and tracking a paywall. ## 3.0.0-beta.6 diff --git a/Examples/UIKit-ObjC/Superwall-UIKit-ObjC/Services/SSASuperwallService.m b/Examples/UIKit-ObjC/Superwall-UIKit-ObjC/Services/SSASuperwallService.m index 6cb12bba8..20b7bd809 100644 --- a/Examples/UIKit-ObjC/Superwall-UIKit-ObjC/Services/SSASuperwallService.m +++ b/Examples/UIKit-ObjC/Superwall-UIKit-ObjC/Services/SSASuperwallService.m @@ -91,7 +91,7 @@ - (nullable NSString *)name { - (void)setName:(nullable NSString *)name { id userAttributeFirstName = name ? : [NSNull null]; - [[Superwall sharedInstance] setUserAttributesDictionary:@{ kUserAttributesFirstNameKey : userAttributeFirstName }]; + [[Superwall sharedInstance] setUserAttributes:@{ kUserAttributesFirstNameKey : userAttributeFirstName }]; } #pragma mark - Public Methods diff --git a/Sources/SuperwallKit/Delegate/Subscription Controller/PurchaseController.swift b/Sources/SuperwallKit/Delegate/Subscription Controller/PurchaseController.swift index d3465b937..e19d0f807 100644 --- a/Sources/SuperwallKit/Delegate/Subscription Controller/PurchaseController.swift +++ b/Sources/SuperwallKit/Delegate/Subscription Controller/PurchaseController.swift @@ -20,7 +20,6 @@ import StoreKit /// /// To learn how to implement the ``PurchaseController`` in your app /// and best practices, see . -@MainActor public protocol PurchaseController: AnyObject { /// Called when the user initiates purchasing of a product. /// @@ -31,6 +30,7 @@ public protocol PurchaseController: AnyObject { /// /// - Returns: A``PurchaseResult`` object, which is the result of your purchase logic. /// **Note**: Make sure you handle all cases of ``PurchaseResult``. + @MainActor func purchase(product: SKProduct) async -> PurchaseResult /// Called when the user initiates a restore. @@ -39,5 +39,6 @@ public protocol PurchaseController: AnyObject { /// and return its result. /// /// - Returns: A boolean that's `true` if the user's purchases were restored or `false` if they weren't. + @MainActor func restorePurchases() async -> Bool } diff --git a/Sources/SuperwallKit/Delegate/Subscription Controller/PurchaseControllerObjc.swift b/Sources/SuperwallKit/Delegate/Subscription Controller/PurchaseControllerObjc.swift index 8ecc61c2a..982787862 100644 --- a/Sources/SuperwallKit/Delegate/Subscription Controller/PurchaseControllerObjc.swift +++ b/Sources/SuperwallKit/Delegate/Subscription Controller/PurchaseControllerObjc.swift @@ -20,7 +20,6 @@ import StoreKit /// /// To learn how to implement the ``PurchaseControllerObjc`` in your app /// and best practices, see . -@MainActor @objc(SWKPurchaseController) public protocol PurchaseControllerObjc: AnyObject { /// Called when the user initiates purchasing of a product. @@ -33,6 +32,7 @@ public protocol PurchaseControllerObjc: AnyObject { /// Call this with the result of your purchase logic. When you pass a `.failed` result, make sure you also pass /// the error. /// **Note:** Make sure you handle all cases of ``PurchaseResult``. + @MainActor @objc func purchase( product: SKProduct, completion: @escaping (PurchaseResultObjc, Error?) -> Void @@ -45,5 +45,6 @@ public protocol PurchaseControllerObjc: AnyObject { /// /// - Parameters: /// - completion: Call the completion with `true` if the user's purchases were restored or `false` if they weren't. + @MainActor @objc func restorePurchases(completion: @escaping (Bool) -> Void) } diff --git a/Sources/SuperwallKit/Documentation.docc/Extensions/SuperwallExtension.md b/Sources/SuperwallKit/Documentation.docc/Extensions/SuperwallExtension.md index e8db7bbfc..7354f6818 100644 --- a/Sources/SuperwallKit/Documentation.docc/Extensions/SuperwallExtension.md +++ b/Sources/SuperwallKit/Documentation.docc/Extensions/SuperwallExtension.md @@ -41,6 +41,7 @@ The ``Superwall`` class is used to access all the features of the SDK. Before us - ``getTrackResult(forEvent:params:)-1qexk`` - ``getTrackResult(forEvent:params:completion:)`` - ``getTrackResult(forEvent:params:)-2j7qn`` +- ``getTrackResult(forEvent:)`` - ``dismiss()-844a9`` - ``dismiss()-4objm`` - ``dismiss(completion:)`` @@ -64,8 +65,8 @@ The ``Superwall`` class is used to access all the features of the SDK. Before us - ``identify(userId:)`` - ``IdentityOptions`` - ``reset()`` -- ``setUserAttributes(_:)`` -- ``setUserAttributesDictionary(_:)`` +- ``setUserAttributes(_:)-1wql2`` +- ``setUserAttributes(_:)-8jken`` - ``removeUserAttributes(_:)`` - ``userAttributes`` diff --git a/Sources/SuperwallKit/Documentation.docc/SettingUserAttributes.md b/Sources/SuperwallKit/Documentation.docc/SettingUserAttributes.md index 0b337ab36..69aa82311 100644 --- a/Sources/SuperwallKit/Documentation.docc/SettingUserAttributes.md +++ b/Sources/SuperwallKit/Documentation.docc/SettingUserAttributes.md @@ -6,7 +6,7 @@ Set user attributes for use in your paywalls and the dashboard. You can display information about the user on the paywall by setting user attributes. -You do this by passing a `[String: Any?]` dictionary of attributes to ``Superwall/setUserAttributes(_:)``: +You do this by passing a `[String: Any?]` dictionary of attributes to ``Superwall/setUserAttributes(_:)-1wql2``: ```swift extension SuperwallService { diff --git a/Sources/SuperwallKit/Identity/UserAttributes.swift b/Sources/SuperwallKit/Identity/UserAttributes.swift index a7b819bcc..8f24eaa04 100644 --- a/Sources/SuperwallKit/Identity/UserAttributes.swift +++ b/Sources/SuperwallKit/Identity/UserAttributes.swift @@ -47,7 +47,7 @@ extension Superwall { /// /// ``` /// NSDictionary *userAttributes = @{ key : value, key2 : value2}; - /// [[Superwall sharedInstance] setUserAttributesDictionary: userAttributes]; + /// [[Superwall sharedInstance] setUserAttributes:userAttributes]; /// ``` /// /// - Parameters: @@ -56,7 +56,7 @@ extension Superwall { /// Note: Keys beginning with `$` are reserved for Superwall and will be dropped. Arrays and dictionaries /// as values are not supported at this time, and will be dropped. @available(swift, obsoleted: 1.0) - @objc public func setUserAttributesDictionary(_ attributes: NSDictionary) { + @objc public func setUserAttributes(_ attributes: NSDictionary) { var swiftDictionary: [String: Any?] = [:] let keys = attributes.allKeys.compactMap { $0 as? String } for key in keys { diff --git a/Sources/SuperwallKit/Paywall/Presentation/PublicPresentation.swift b/Sources/SuperwallKit/Paywall/Presentation/PublicPresentation.swift index 700761103..db7da23f9 100644 --- a/Sources/SuperwallKit/Paywall/Presentation/PublicPresentation.swift +++ b/Sources/SuperwallKit/Paywall/Presentation/PublicPresentation.swift @@ -55,7 +55,7 @@ extension Superwall { // MARK: - Objective-C-only Track /// An Objective-C-only method that shows a paywall to the user when: An event you provide is tied to an /// active trigger inside a campaign on the [Superwall Dashboard](https://superwall.com/dashboard); - /// and the user matches a rule in the campaign. **Note**: Please use ``Superwall/setUserAttributes(_:)`` + /// and the user matches a rule in the campaign. **Note**: Please use ``Superwall/setUserAttributes(_:)-1wql2`` /// if you’re using Swift. /// /// Triggers enable you to retroactively decide where or when to show a specific paywall in your app. Use this method @@ -215,7 +215,7 @@ extension Superwall { /// An Objective-C-only method that shows a paywall to the user when: An event you provide is tied to an /// active trigger inside a campaign on the [Superwall Dashboard](https://superwall.com/dashboard); - /// and the user matches a rule in the campaign. **Note**: Please use ``Superwall/setUserAttributes(_:)`` + /// and the user matches a rule in the campaign. **Note**: Please use ``Superwall/setUserAttributes(_:)-1wql2`` /// if you’re using Swift. /// /// Triggers enable you to retroactively decide where or when to show a specific paywall in your app. Use this method @@ -239,7 +239,7 @@ extension Superwall { /// An Objective-C-only method that shows a paywall to the user when: An event you provide is tied to an /// active trigger inside a campaign on the [Superwall Dashboard](https://superwall.com/dashboard); - /// and the user matches a rule in the campaign. **Note**: Please use ``Superwall/setUserAttributes(_:)`` + /// and the user matches a rule in the campaign. **Note**: Please use ``Superwall/setUserAttributes(_:)-1wql2`` /// if you’re using Swift. /// /// Triggers enable you to retroactively decide where or when to show a specific paywall in your app. Use this method @@ -269,7 +269,7 @@ extension Superwall { /// An Objective-C-only method that shows a paywall to the user when: An event you provide is tied to an /// active trigger inside a campaign on the [Superwall Dashboard](https://superwall.com/dashboard); - /// and the user matches a rule in the campaign. **Note**: Please use ``Superwall/setUserAttributes(_:)`` + /// and the user matches a rule in the campaign. **Note**: Please use ``Superwall/setUserAttributes(_:)-1wql2`` /// if you’re using Swift. /// /// Triggers enable you to retroactively decide where or when to show a specific paywall in your app. Use this method @@ -310,7 +310,7 @@ extension Superwall { /// An Objective-C-only method that shows a paywall to the user when: An event you provide is tied to an /// active trigger inside a campaign on the [Superwall Dashboard](https://superwall.com/dashboard); - /// and the user matches a rule in the campaign. **Note**: Please use ``Superwall/setUserAttributes(_:)`` + /// and the user matches a rule in the campaign. **Note**: Please use ``Superwall/setUserAttributes(_:)-1wql2`` /// if you’re using Swift. /// /// Triggers enable you to retroactively decide where or when to show a specific paywall in your app. Use this method diff --git a/Sources/SuperwallKit/Superwall.swift b/Sources/SuperwallKit/Superwall.swift index e74b0725a..ac87155d9 100644 --- a/Sources/SuperwallKit/Superwall.swift +++ b/Sources/SuperwallKit/Superwall.swift @@ -42,7 +42,7 @@ public final class Superwall: NSObject, ObservableObject { } } - /// Properties stored about the user, set using ``setUserAttributes(_:)``. + /// Properties stored about the user, set using ``setUserAttributes(_:)-1wql2``. public var userAttributes: [String: Any] { return dependencyContainer.identityManager.userAttributes }