From 755ceae21a8167b5cf14483672e6d14eafd9cafb Mon Sep 17 00:00:00 2001 From: Bryan Dubno <121259911+super-bryan@users.noreply.github.com> Date: Mon, 8 Jan 2024 12:51:34 -0800 Subject: [PATCH 1/7] Update Experiment.swift to undo changes for Flutter --- Sources/SuperwallKit/Models/Triggers/Experiment.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/SuperwallKit/Models/Triggers/Experiment.swift b/Sources/SuperwallKit/Models/Triggers/Experiment.swift index 35708a2c6..8f92b379e 100644 --- a/Sources/SuperwallKit/Models/Triggers/Experiment.swift +++ b/Sources/SuperwallKit/Models/Triggers/Experiment.swift @@ -68,7 +68,7 @@ public final class Experiment: NSObject, Codable, Sendable { /// The identifier of the paywall variant. Only valid when the variant `type` is `treatment`. public let paywallId: String? - public init(id: String, type: VariantType, paywallId: String?) { + init(id: String, type: VariantType, paywallId: String?) { self.id = id self.type = type self.paywallId = paywallId @@ -100,7 +100,7 @@ public final class Experiment: NSObject, Codable, Sendable { case paywallId = "paywall_identifier" } - public init( + init( id: String, groupId: String, variant: Variant From d956e787bf15f5e38955158d4a58f77b1721b654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20To=CC=88r?= Date: Thu, 18 Jan 2024 18:38:35 -0500 Subject: [PATCH 2/7] Fixes `transaction_abandon` and `transaction_fail` bug with `paywall_decline` - Fixes bug where a `transaction_abandon` or `transaction_fail` event would prevent the presented paywall from dismissing if `paywall_decline` was a trigger. --- CHANGELOG.md | 8 +++++++- Sources/SuperwallKit/Misc/Constants.swift | 2 +- .../Presentation/Internal/Operators/GetPresenter.swift | 3 +-- .../View Controller/PaywallViewController.swift | 10 +++++++--- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c13e9450..cc71b1c09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,17 @@ The changelog for `SuperwallKit`. Also see the [releases](https://github.com/superwall-me/Superwall-iOS/releases) on GitHub. +## 3.4.7 + +### Fixes + +- Fixes bug where a `transaction_abandon` or `transaction_fail` event would prevent the presented paywall from dismissing if `paywall_decline` was a trigger. + ## 3.4.6 ### Enhancements -- Adds internal code for SDK wrappers like flutter. +- Adds internal code for SDK wrappers like Flutter. ## 3.4.5 diff --git a/Sources/SuperwallKit/Misc/Constants.swift b/Sources/SuperwallKit/Misc/Constants.swift index 4f3a2dce8..c065c73bd 100644 --- a/Sources/SuperwallKit/Misc/Constants.swift +++ b/Sources/SuperwallKit/Misc/Constants.swift @@ -18,5 +18,5 @@ let sdkVersion = """ */ let sdkVersion = """ -3.4.6 +3.4.7 """ diff --git a/Sources/SuperwallKit/Paywall/Presentation/Internal/Operators/GetPresenter.swift b/Sources/SuperwallKit/Paywall/Presentation/Internal/Operators/GetPresenter.swift index f827763b7..12f990e70 100644 --- a/Sources/SuperwallKit/Paywall/Presentation/Internal/Operators/GetPresenter.swift +++ b/Sources/SuperwallKit/Paywall/Presentation/Internal/Operators/GetPresenter.swift @@ -82,8 +82,7 @@ extension Superwall { logLevel: .error, scope: .paywallPresentation, message: "No Presenter To Present Paywall", - info: debugInfo, - error: nil + info: debugInfo ) let error = InternalPresentationLogic.presentationError( diff --git a/Sources/SuperwallKit/Paywall/View Controller/PaywallViewController.swift b/Sources/SuperwallKit/Paywall/View Controller/PaywallViewController.swift index d8f0b4198..226aba21e 100644 --- a/Sources/SuperwallKit/Paywall/View Controller/PaywallViewController.swift +++ b/Sources/SuperwallKit/Paywall/View Controller/PaywallViewController.swift @@ -787,14 +787,18 @@ extension PaywallViewController { ) let paywallPresenterEvent = info.presentedByEventWithName let presentedByPaywallDecline = paywallPresenterEvent == SuperwallEventObjc.paywallDecline.description + let presentedByTransactionAbandon = paywallPresenterEvent == SuperwallEventObjc.transactionAbandon.description + let presentedByTransactionFail = paywallPresenterEvent == SuperwallEventObjc.transactionFail.description await Superwall.shared.track(trackedEvent) if case .paywall = presentationResult, - !presentedByPaywallDecline { + !presentedByPaywallDecline, + !presentedByTransactionAbandon, + !presentedByTransactionFail { // If a paywall_decline trigger is active and the current paywall wasn't presented - // by paywall_decline, it lands here so as not to dismiss the paywall. - // track() will do that before presenting the next paywall. + // by paywall_decline, transaction_abandon, or transaction_fail, it lands here so + // as not to dismiss the paywall. track() will do that before presenting the next paywall. return } } From 1fe59fb749dabf4eb17dba34a1e0f0963174a207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20To=CC=88r?= Date: Mon, 22 Jan 2024 16:56:17 -0500 Subject: [PATCH 3/7] Closes SW-2630 Flushes events queue after transaction complete. --- .../SuperwallKit/Analytics/Internal Tracking/Tracking.swift | 2 +- Sources/SuperwallKit/Dependencies/DependencyContainer.swift | 5 +++-- .../Web View/Message Handling/PaywallMessageHandler.swift | 3 +-- Sources/SuperwallKit/Storage/EventsQueue.swift | 2 +- .../StoreKit/Transactions/TransactionManager.swift | 6 ++++++ 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Sources/SuperwallKit/Analytics/Internal Tracking/Tracking.swift b/Sources/SuperwallKit/Analytics/Internal Tracking/Tracking.swift index 9721a9891..fae718355 100644 --- a/Sources/SuperwallKit/Analytics/Internal Tracking/Tracking.swift +++ b/Sources/SuperwallKit/Analytics/Internal Tracking/Tracking.swift @@ -58,7 +58,7 @@ extension Superwall { disableVerboseEvents: verboseEvents, isSandbox: dependencyContainer.makeIsSandbox() ) { - await dependencyContainer.queue.enqueue(event: eventData.jsonData) + await dependencyContainer.eventsQueue.enqueue(event: eventData.jsonData) } dependencyContainer.storage.coreDataManager.saveEventData(eventData) diff --git a/Sources/SuperwallKit/Dependencies/DependencyContainer.swift b/Sources/SuperwallKit/Dependencies/DependencyContainer.swift index 8bc879725..7eb332ae5 100644 --- a/Sources/SuperwallKit/Dependencies/DependencyContainer.swift +++ b/Sources/SuperwallKit/Dependencies/DependencyContainer.swift @@ -30,7 +30,7 @@ final class DependencyContainer { var paywallManager: PaywallManager! var paywallRequestManager: PaywallRequestManager! var deviceHelper: DeviceHelper! - var queue: EventsQueue! + var eventsQueue: EventsQueue! var debugManager: DebugManager! var api: Api! var transactionManager: TransactionManager! @@ -83,7 +83,7 @@ final class DependencyContainer { factory: self ) - queue = EventsQueue( + eventsQueue = EventsQueue( network: network, configManager: configManager ) @@ -124,6 +124,7 @@ final class DependencyContainer { receiptManager: receiptManager, purchaseController: purchaseController, sessionEventsManager: sessionEventsManager, + eventsQueue: eventsQueue, factory: self ) diff --git a/Sources/SuperwallKit/Paywall/View Controller/Web View/Message Handling/PaywallMessageHandler.swift b/Sources/SuperwallKit/Paywall/View Controller/Web View/Message Handling/PaywallMessageHandler.swift index a4005d649..26d7de898 100644 --- a/Sources/SuperwallKit/Paywall/View Controller/Web View/Message Handling/PaywallMessageHandler.swift +++ b/Sources/SuperwallKit/Paywall/View Controller/Web View/Message Handling/PaywallMessageHandler.swift @@ -119,8 +119,7 @@ final class PaywallMessageHandler: WebEventDelegate { logLevel: .debug, scope: .paywallViewController, message: "Posting Message", - info: ["message": messageScript], - error: nil + info: ["message": messageScript] ) delegate?.webView.evaluateJavaScript(messageScript) { _, error in diff --git a/Sources/SuperwallKit/Storage/EventsQueue.swift b/Sources/SuperwallKit/Storage/EventsQueue.swift index 275e18860..9d3268993 100644 --- a/Sources/SuperwallKit/Storage/EventsQueue.swift +++ b/Sources/SuperwallKit/Storage/EventsQueue.swift @@ -82,7 +82,7 @@ actor EventsQueue { return true } - private func flushInternal(depth: Int = 10) { + func flushInternal(depth: Int = 10) { var eventsToSend: [JSON] = [] var i = 0 diff --git a/Sources/SuperwallKit/StoreKit/Transactions/TransactionManager.swift b/Sources/SuperwallKit/StoreKit/Transactions/TransactionManager.swift index 3133e09b7..60c5352e5 100644 --- a/Sources/SuperwallKit/StoreKit/Transactions/TransactionManager.swift +++ b/Sources/SuperwallKit/StoreKit/Transactions/TransactionManager.swift @@ -15,6 +15,7 @@ final class TransactionManager { private let receiptManager: ReceiptManager private let purchaseController: PurchaseController private let sessionEventsManager: SessionEventsManager + private let eventsQueue: EventsQueue private let factory: Factory typealias Factory = OptionsFactory & TriggerFactory @@ -27,12 +28,14 @@ final class TransactionManager { receiptManager: ReceiptManager, purchaseController: PurchaseController, sessionEventsManager: SessionEventsManager, + eventsQueue: EventsQueue, factory: Factory ) { self.storeKitManager = storeKitManager self.receiptManager = receiptManager self.purchaseController = purchaseController self.sessionEventsManager = sessionEventsManager + self.eventsQueue = eventsQueue self.factory = factory } @@ -387,6 +390,9 @@ final class TransactionManager { ) await Superwall.shared.track(trackedEvent) + // Immediately flush the events queue on transaction complete. + await eventsQueue.flushInternal() + if product.subscriptionPeriod == nil { let trackedEvent = InternalSuperwallEvent.NonRecurringProductPurchase( paywallInfo: paywallInfo, From e3c7013f710a18c6b7565eddf86952516f7231f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20To=CC=88r?= Date: Mon, 22 Jan 2024 17:39:48 -0500 Subject: [PATCH 4/7] Closes SW-2678 Fixes issue where the `subscription_start` event was being fired even if a non-recurring product was purchased. --- CHANGELOG.md | 1 + .../Transactions/TransactionManager.swift | 34 +++++++++---------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc71b1c09..5a7dd4e36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The changelog for `SuperwallKit`. Also see the [releases](https://github.com/sup ### Fixes - Fixes bug where a `transaction_abandon` or `transaction_fail` event would prevent the presented paywall from dismissing if `paywall_decline` was a trigger. +- SW-2678: Fixes issue where the `subscription_start` event was being fired even if a non-recurring product was purchased. ## 3.4.6 diff --git a/Sources/SuperwallKit/StoreKit/Transactions/TransactionManager.swift b/Sources/SuperwallKit/StoreKit/Transactions/TransactionManager.swift index 60c5352e5..88fecdc04 100644 --- a/Sources/SuperwallKit/StoreKit/Transactions/TransactionManager.swift +++ b/Sources/SuperwallKit/StoreKit/Transactions/TransactionManager.swift @@ -399,26 +399,26 @@ final class TransactionManager { product: product ) await Superwall.shared.track(trackedEvent) - } + } else { + if didStartFreeTrial { + let trackedEvent = InternalSuperwallEvent.FreeTrialStart( + paywallInfo: paywallInfo, + product: product + ) + await Superwall.shared.track(trackedEvent) - if didStartFreeTrial { - let trackedEvent = InternalSuperwallEvent.FreeTrialStart( - paywallInfo: paywallInfo, - product: product - ) - await Superwall.shared.track(trackedEvent) + let notifications = paywallInfo.localNotifications.filter { + $0.type == .trialStarted + } - let notifications = paywallInfo.localNotifications.filter { - $0.type == .trialStarted + await NotificationScheduler.scheduleNotifications(notifications, factory: factory) + } else { + let trackedEvent = InternalSuperwallEvent.SubscriptionStart( + paywallInfo: paywallInfo, + product: product + ) + await Superwall.shared.track(trackedEvent) } - - await NotificationScheduler.scheduleNotifications(notifications, factory: factory) - } else { - let trackedEvent = InternalSuperwallEvent.SubscriptionStart( - paywallInfo: paywallInfo, - product: product - ) - await Superwall.shared.track(trackedEvent) } } } From 7fcafc1174bccc8711ea39b70adc402283017ffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20To=CC=88r?= Date: Tue, 23 Jan 2024 13:19:04 -0500 Subject: [PATCH 5/7] Closes SW-2659 - Fixes issue on macOS where the window behind a paywall wasn't being removed when a paywall was dismissed, leading to the app appearing to be in a frozen state. --- CHANGELOG.md | 1 + .../Paywall/Presentation/Internal/Operators/GetPresenter.swift | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a7dd4e36..916e0430c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The changelog for `SuperwallKit`. Also see the [releases](https://github.com/sup - Fixes bug where a `transaction_abandon` or `transaction_fail` event would prevent the presented paywall from dismissing if `paywall_decline` was a trigger. - SW-2678: Fixes issue where the `subscription_start` event was being fired even if a non-recurring product was purchased. +- SW-2659: Fixes issue on macOS where the window behind a paywall wasn't being removed when a paywall was dismissed, leading to the app appearing to be in a frozen state. ## 3.4.6 diff --git a/Sources/SuperwallKit/Paywall/Presentation/Internal/Operators/GetPresenter.swift b/Sources/SuperwallKit/Paywall/Presentation/Internal/Operators/GetPresenter.swift index 12f990e70..c79227895 100644 --- a/Sources/SuperwallKit/Paywall/Presentation/Internal/Operators/GetPresenter.swift +++ b/Sources/SuperwallKit/Paywall/Presentation/Internal/Operators/GetPresenter.swift @@ -142,6 +142,7 @@ extension Superwall { @MainActor func destroyPresentingWindow() { + presentationItems.window?.windowScene = nil presentationItems.window = nil } } From 6943b446efeb5cf1cc56389c32b3f2192574de05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20To=CC=88r?= Date: Wed, 24 Jan 2024 11:47:36 -0500 Subject: [PATCH 6/7] Closes SW-2667 Adds `preferredLanguageCode` and `preferredLocale` to device attributes --- CHANGELOG.md | 4 +++ .../Network/Device Helper/DeviceHelper.swift | 27 ++++++++++++++++++- .../Templating/Models/DeviceTemplate.swift | 2 ++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 916e0430c..3268ad01d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ The changelog for `SuperwallKit`. Also see the [releases](https://github.com/sup ## 3.4.7 +### Enhancements + +- SW-2667: Adds `preferredLanguageCode` and `preferredLocale` to device attributes. If your app isn't already localized for a language you're trying to target, the `deviceLanguageCode` and `deviceLocale` may not be what you're expecting. Use these device attributes instead to access the first preferred locale the user has in their device settings. + ### Fixes - Fixes bug where a `transaction_abandon` or `transaction_fail` event would prevent the presented paywall from dismissing if `paywall_decline` was a trigger. diff --git a/Sources/SuperwallKit/Network/Device Helper/DeviceHelper.swift b/Sources/SuperwallKit/Network/Device Helper/DeviceHelper.swift index a822457de..256e3609c 100644 --- a/Sources/SuperwallKit/Network/Device Helper/DeviceHelper.swift +++ b/Sources/SuperwallKit/Network/Device Helper/DeviceHelper.swift @@ -15,6 +15,14 @@ class DeviceHelper { let localeIdentifier = factory.makeLocaleIdentifier() return localeIdentifier ?? Locale.autoupdatingCurrent.identifier } + + var preferredLocale: String { + guard let preferredIdentifier = Locale.preferredLanguages.first else { + return locale + } + return Locale(identifier: preferredIdentifier).identifier + } + let appInstalledAtString: String private let reachability: SCNetworkReachability? @@ -57,7 +65,22 @@ class DeviceHelper { }() var languageCode: String { - Locale.autoupdatingCurrent.languageCode ?? "" + if #available(iOS 16, *) { + Locale.autoupdatingCurrent.language.languageCode?.identifier ?? "" + } else { + Locale.autoupdatingCurrent.languageCode ?? "" + } + } + + var preferredLanguageCode: String { + guard let preferredIdentifier = Locale.preferredLanguages.first else { + return languageCode + } + if #available(iOS 16, *) { + return Locale(identifier: preferredIdentifier).language.languageCode?.identifier ?? "" + } else { + return Locale(identifier: preferredIdentifier).languageCode ?? "" + } } var currencyCode: String { @@ -400,7 +423,9 @@ class DeviceHelper { osVersion: osVersion, deviceModel: model, deviceLocale: locale, + preferredLocale: preferredLocale, deviceLanguageCode: languageCode, + preferredLanguageCode: preferredLanguageCode, deviceCurrencyCode: currencyCode, deviceCurrencySymbol: currencySymbol, interfaceType: interfaceType, diff --git a/Sources/SuperwallKit/Paywall/View Controller/Web View/Templating/Models/DeviceTemplate.swift b/Sources/SuperwallKit/Paywall/View Controller/Web View/Templating/Models/DeviceTemplate.swift index 5af149b3f..e3ac7a515 100644 --- a/Sources/SuperwallKit/Paywall/View Controller/Web View/Templating/Models/DeviceTemplate.swift +++ b/Sources/SuperwallKit/Paywall/View Controller/Web View/Templating/Models/DeviceTemplate.swift @@ -17,7 +17,9 @@ struct DeviceTemplate: Codable { var osVersion: String var deviceModel: String var deviceLocale: String + var preferredLocale: String var deviceLanguageCode: String + var preferredLanguageCode: String var deviceCurrencyCode: String var deviceCurrencySymbol: String var interfaceType: String From 785ca26fad790f30f17bc0f30737982451df54a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20To=CC=88r?= Date: Wed, 24 Jan 2024 12:27:42 -0500 Subject: [PATCH 7/7] Update DeviceHelper.swift --- Sources/SuperwallKit/Network/Device Helper/DeviceHelper.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/SuperwallKit/Network/Device Helper/DeviceHelper.swift b/Sources/SuperwallKit/Network/Device Helper/DeviceHelper.swift index 256e3609c..2a2272434 100644 --- a/Sources/SuperwallKit/Network/Device Helper/DeviceHelper.swift +++ b/Sources/SuperwallKit/Network/Device Helper/DeviceHelper.swift @@ -66,9 +66,9 @@ class DeviceHelper { var languageCode: String { if #available(iOS 16, *) { - Locale.autoupdatingCurrent.language.languageCode?.identifier ?? "" + return Locale.autoupdatingCurrent.language.languageCode?.identifier ?? "" } else { - Locale.autoupdatingCurrent.languageCode ?? "" + return Locale.autoupdatingCurrent.languageCode ?? "" } }