diff --git a/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/project.pbxproj b/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/project.pbxproj index 2de3226b..09dfabf1 100644 --- a/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/project.pbxproj +++ b/sample-apps/swift-sample-app/swift-sample-app.xcodeproj/project.pbxproj @@ -31,7 +31,6 @@ 0C8EE4682CEEF678006F17D6 /* FirebaseStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 0C8EE4672CEEF678006F17D6 /* FirebaseStorage */; }; 0C8EE46A2CEEF678006F17D6 /* FirebaseStorageCombine-Community in Frameworks */ = {isa = PBXBuildFile; productRef = 0C8EE4692CEEF678006F17D6 /* FirebaseStorageCombine-Community */; }; 0C8EE46C2CEEF678006F17D6 /* FirebaseVertexAI in Frameworks */ = {isa = PBXBuildFile; productRef = 0C8EE46B2CEEF678006F17D6 /* FirebaseVertexAI */; }; - 0CD4B0562CEF00BD000DD590 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0CD4B0552CEF00BD000DD590 /* GoogleService-Info.plist */; }; 0CEAAB3E2CF8BB4F00172B3E /* guitar.wav in Resources */ = {isa = PBXBuildFile; fileRef = 0CEAAB3D2CF8BB4F00172B3E /* guitar.wav */; }; 37088F332B3C38250000B218 /* IterableAppExtensions in Frameworks */ = {isa = PBXBuildFile; productRef = 37088F322B3C38250000B218 /* IterableAppExtensions */; }; 37088F352B3C38250000B218 /* IterableSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 37088F342B3C38250000B218 /* IterableSDK */; }; @@ -79,7 +78,6 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 0CD4B0552CEF00BD000DD590 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 0CEAAB3D2CF8BB4F00172B3E /* guitar.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = guitar.wav; sourceTree = ""; }; 551A5FEC251AB1510004C9A0 /* swift-sdk */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "swift-sdk"; path = ../..; sourceTree = ""; }; AC1BDF5720E30436000010CA /* DeepLinkHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLinkHandler.swift; sourceTree = ""; }; @@ -191,7 +189,6 @@ isa = PBXGroup; children = ( 0CEAAB3D2CF8BB4F00172B3E /* guitar.wav */, - 0CD4B0552CEF00BD000DD590 /* GoogleService-Info.plist */, E9C60B782B3C2061005C4462 /* EmbeddedMessages */, AC5ECD9D20E303F50081E1DA /* ViewControllers */, AC5ECD9B20E3038B0081E1DA /* Deep Link Handling */, @@ -386,7 +383,6 @@ 0CEAAB3E2CF8BB4F00172B3E /* guitar.wav in Resources */, ACA3A14320E2F6B100FEF74F /* LaunchScreen.storyboard in Resources */, ACA3A14020E2F6B100FEF74F /* Assets.xcassets in Resources */, - 0CD4B0562CEF00BD000DD590 /* GoogleService-Info.plist in Resources */, ACA3A13E20E2F6AF00FEF74F /* Main.storyboard in Resources */, E9C60B7B2B3C2061005C4462 /* embeddedmessages.json in Resources */, ); diff --git a/swift-sdk/Constants.swift b/swift-sdk/Constants.swift index 90965996..f3073010 100644 --- a/swift-sdk/Constants.swift +++ b/swift-sdk/Constants.swift @@ -77,6 +77,7 @@ enum Const { static let matchedCriteria = "itbl_matched_criteria" static let eventList = "itbl_event_list" static let anonymousUsageTrack = "itbl_anonymous_usage_track" + static let isNotificationsEnabled = "isNotificationsEnabled" static let attributionInfoExpiration = 24 } diff --git a/swift-sdk/Internal/InternalIterableAPI.swift b/swift-sdk/Internal/InternalIterableAPI.swift index 530d390a..eba6ec03 100644 --- a/swift-sdk/Internal/InternalIterableAPI.swift +++ b/swift-sdk/Internal/InternalIterableAPI.swift @@ -278,6 +278,7 @@ final class InternalIterableAPI: NSObject, PushTrackerProtocol, AuthProvider { } hexToken = token + isFromFCM = isFromFCM let registerTokenInfo = RegisterTokenInfo(hexToken: token, appName: appName, pushServicePlatform: config.pushPlatform, @@ -297,6 +298,9 @@ final class InternalIterableAPI: NSObject, PushTrackerProtocol, AuthProvider { onFailure?(reason, data) } ) + notificationStateProvider.isNotificationsEnabled { isEnabled in + self.localStorage.isNotificationsEnabled = isEnabled + } } @discardableResult @@ -657,10 +661,13 @@ final class InternalIterableAPI: NSObject, PushTrackerProtocol, AuthProvider { private var _userId: String? private var _successCallback: OnSuccessHandler? = nil private var _failureCallback: OnFailureHandler? = nil + + private let notificationCenter: NotificationCenterProtocol /// the hex representation of this device token private var hexToken: String? + private var isFromFCM: Bool? private var launchOptions: [UIApplication.LaunchOptionsKey: Any]? @@ -841,6 +848,7 @@ final class InternalIterableAPI: NSObject, PushTrackerProtocol, AuthProvider { //localStorage.email = nil // remove this before pushing the code (only for testing) inAppDisplayer = dependencyContainer.inAppDisplayer urlOpener = dependencyContainer.urlOpener + notificationCenter = dependencyContainer.notificationCenter deepLinkManager = DeepLinkManager(redirectNetworkSessionProvider: dependencyContainer) } @@ -873,10 +881,33 @@ final class InternalIterableAPI: NSObject, PushTrackerProtocol, AuthProvider { requestHandler.start() checkRemoteConfiguration() + + addForegroundObservers() return inAppManager.start() } + private func addForegroundObservers() { + NotificationCenter.default.addObserver(self, + selector: #selector(onAppDidBecomeActiveNotification(notification:)), + name: UIApplication.didBecomeActiveNotification, + object: nil) + } + + @objc private func onAppDidBecomeActiveNotification(notification: Notification) { + self.notificationStateProvider.isNotificationsEnabled { isEnabled in + if self.localStorage.isNotificationsEnabled != isEnabled { + if self.config.autoPushRegistration { + if let token = self.hexToken, let isFromFCM = self.isFromFCM, isFromFCM { + IterableAPI.registerFCM(token: token) + } else { + self.notificationStateProvider.registerForRemoteNotifications() + } + } + } + } + } + private func handle(launchOptions: [UIApplication.LaunchOptionsKey: Any]?) { guard let launchOptions = launchOptions else { return diff --git a/swift-sdk/Internal/IterableUserDefaults.swift b/swift-sdk/Internal/IterableUserDefaults.swift index 758caff9..0b570ba7 100644 --- a/swift-sdk/Internal/IterableUserDefaults.swift +++ b/swift-sdk/Internal/IterableUserDefaults.swift @@ -110,6 +110,14 @@ class IterableUserDefaults { } } + var isNotificationsEnabled: Bool { + get { + return bool(withKey: .isNotificationsEnabled) + } set { + save(bool: newValue, withKey: .isNotificationsEnabled) + } + } + var body = [AnyHashable: Any]() private func anonSessionsData(withKey key: UserDefaultsKey) -> IterableAnonSessionsWrapper? { @@ -310,6 +318,7 @@ class IterableUserDefaults { static let criteriaData = UserDefaultsKey(value: Const.UserDefault.criteriaData) static let anonymousSessions = UserDefaultsKey(value: Const.UserDefault.anonymousSessions) static let anonymousUsageTrack = UserDefaultsKey(value: Const.UserDefault.anonymousUsageTrack) + static let isNotificationsEnabled = UserDefaultsKey(value: Const.UserDefault.isNotificationsEnabled) } private struct Envelope: Codable { diff --git a/swift-sdk/Internal/LocalStorage.swift b/swift-sdk/Internal/LocalStorage.swift index 50a57f61..695a0b35 100644 --- a/swift-sdk/Internal/LocalStorage.swift +++ b/swift-sdk/Internal/LocalStorage.swift @@ -115,6 +115,14 @@ struct LocalStorage: LocalStorageProtocol { iterableUserDefaults.anonymousUsageTrack = newValue } } + + var isNotificationsEnabled: Bool { + get { + iterableUserDefaults.isNotificationsEnabled + } set { + iterableUserDefaults.isNotificationsEnabled = newValue + } + } func getAttributionInfo(currentDate: Date) -> IterableAttributionInfo? { iterableUserDefaults.getAttributionInfo(currentDate: currentDate) diff --git a/swift-sdk/Internal/LocalStorageProtocol.swift b/swift-sdk/Internal/LocalStorageProtocol.swift index efbdae65..add7565a 100644 --- a/swift-sdk/Internal/LocalStorageProtocol.swift +++ b/swift-sdk/Internal/LocalStorageProtocol.swift @@ -31,6 +31,8 @@ protocol LocalStorageProtocol { var anonymousSessions: IterableAnonSessionsWrapper? { get set } + var isNotificationsEnabled: Bool { get set } + func getAttributionInfo(currentDate: Date) -> IterableAttributionInfo? func save(attributionInfo: IterableAttributionInfo?, withExpiration expiration: Date?)