diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj index d7deeed3..d0f64be0 100644 --- a/Example/Example.xcodeproj/project.pbxproj +++ b/Example/Example.xcodeproj/project.pbxproj @@ -9,7 +9,6 @@ /* Begin PBXBuildFile section */ 0A0DE3482BB8455A00812E73 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A0DE3472BB8455A00812E73 /* NotificationService.swift */; }; 0A0DE34C2BB8455A00812E73 /* MindboxNotificationServiceExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 0A0DE3452BB8455A00812E73 /* MindboxNotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - 0A4B681A2BBC82B500639BC5 /* ChooseInAppMessagesDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A4B68192BBC82B500639BC5 /* ChooseInAppMessagesDelegate.swift */; }; 0A4B682A2BBD7D5100639BC5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0A4B68292BBD7D5100639BC5 /* LaunchScreen.storyboard */; }; 0AD271D02BB9D81E00750279 /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AD271CF2BB9D81D00750279 /* UserNotifications.framework */; }; 0AD271D22BB9D81E00750279 /* UserNotificationsUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AD271D12BB9D81E00750279 /* UserNotificationsUI.framework */; }; @@ -19,20 +18,10 @@ 0AEDBC7A2BB6F8F200EE8722 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AEDBC792BB6F8F200EE8722 /* AppDelegate.swift */; }; 0AEDBC7C2BB6F8F200EE8722 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AEDBC7B2BB6F8F200EE8722 /* SceneDelegate.swift */; }; 0AEDBC832BB6F8F400EE8722 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0AEDBC822BB6F8F400EE8722 /* Assets.xcassets */; }; - 0AEDBC922BB6FA4800EE8722 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AEDBC912BB6FA4800EE8722 /* MainView.swift */; }; - 0AEDBC962BB6FE4900EE8722 /* MainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AEDBC952BB6FE4900EE8722 /* MainViewModel.swift */; }; - 0AEDBC992BB7058B00EE8722 /* ButtonsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AEDBC982BB7058B00EE8722 /* ButtonsView.swift */; }; - 0AEDBC9B2BB70D6E00EE8722 /* SDKDataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AEDBC9A2BB70D6E00EE8722 /* SDKDataView.swift */; }; + 0AEDBC922BB6FA4800EE8722 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AEDBC912BB6FA4800EE8722 /* ContentView.swift */; }; + 0AEDBC962BB6FE4900EE8722 /* ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AEDBC952BB6FE4900EE8722 /* ViewModel.swift */; }; 43E1C73D7E87903545C2ACBC /* Pods_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9AF8ABB9430FE76D72FE17D /* Pods_Example.framework */; }; - 472423992C185B8400B2A9BC /* Item+SwiftData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472423982C185B8400B2A9BC /* Item+SwiftData.swift */; }; - 474F37A22C16F5A700F38BB0 /* NotificationCenterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 474F37A12C16F5A700F38BB0 /* NotificationCenterViewModel.swift */; }; - 474F37A42C16F5B000F38BB0 /* NotificationCenterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 474F37A32C16F5B000F38BB0 /* NotificationCenterView.swift */; }; - 474F37AE2C170FB600F38BB0 /* NotificationCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 474F37AD2C170FB600F38BB0 /* NotificationCellView.swift */; }; - 4774807A2C174BAA00580FB2 /* Payload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 477480792C174BAA00580FB2 /* Payload.swift */; }; - 47FFE2232C187B650007E2F6 /* Item+SwiftData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472423982C185B8400B2A9BC /* Item+SwiftData.swift */; }; - 47FFE2262C187D3C0007E2F6 /* SwiftDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FFE2252C187D3C0007E2F6 /* SwiftDataManager.swift */; }; - 47FFE2282C187D5C0007E2F6 /* SwiftDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FFE2252C187D3C0007E2F6 /* SwiftDataManager.swift */; }; - 47FFE22C2C1886550007E2F6 /* Payload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 477480792C174BAA00580FB2 /* Payload.swift */; }; + 472137C12CF784D400354602 /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472137C02CF784D400354602 /* WebView.swift */; }; 9E3108F96D4F26745D3B37A4 /* Pods_MindboxNotificationServiceExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4AF2BFD8ABA97C73F589C5DB /* Pods_MindboxNotificationServiceExtension.framework */; }; D9585975AC05213E1682C760 /* Pods_MindboxNotificationContentExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 91EB2315545CE887D05CB505 /* Pods_MindboxNotificationContentExtension.framework */; }; /* End PBXBuildFile section */ @@ -74,7 +63,6 @@ 0A0DE3472BB8455A00812E73 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; 0A0DE3492BB8455A00812E73 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 0A0DE3512BB8457100812E73 /* MindboxNotificationServiceExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MindboxNotificationServiceExtension.entitlements; sourceTree = ""; }; - 0A4B68192BBC82B500639BC5 /* ChooseInAppMessagesDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChooseInAppMessagesDelegate.swift; sourceTree = ""; }; 0A4B68292BBD7D5100639BC5 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 0AD271CE2BB9D81D00750279 /* MindboxNotificationContentExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = MindboxNotificationContentExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 0AD271CF2BB9D81D00750279 /* UserNotifications.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; }; @@ -88,20 +76,13 @@ 0AEDBC7B2BB6F8F200EE8722 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 0AEDBC822BB6F8F400EE8722 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 0AEDBC872BB6F8F400EE8722 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 0AEDBC912BB6FA4800EE8722 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; - 0AEDBC952BB6FE4900EE8722 /* MainViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewModel.swift; sourceTree = ""; }; - 0AEDBC982BB7058B00EE8722 /* ButtonsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonsView.swift; sourceTree = ""; }; - 0AEDBC9A2BB70D6E00EE8722 /* SDKDataView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SDKDataView.swift; sourceTree = ""; }; + 0AEDBC912BB6FA4800EE8722 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 0AEDBC952BB6FE4900EE8722 /* ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModel.swift; sourceTree = ""; }; 0AEDBC9C2BB7177A00EE8722 /* Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Example.entitlements; sourceTree = ""; }; 1B29989833584963EC18BDF2 /* Pods-MindboxNotificationContentExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MindboxNotificationContentExtension.release.xcconfig"; path = "Target Support Files/Pods-MindboxNotificationContentExtension/Pods-MindboxNotificationContentExtension.release.xcconfig"; sourceTree = ""; }; - 472423982C185B8400B2A9BC /* Item+SwiftData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Item+SwiftData.swift"; sourceTree = ""; }; - 474F37A12C16F5A700F38BB0 /* NotificationCenterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationCenterViewModel.swift; sourceTree = ""; }; - 474F37A32C16F5B000F38BB0 /* NotificationCenterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationCenterView.swift; sourceTree = ""; }; - 474F37AD2C170FB600F38BB0 /* NotificationCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationCellView.swift; sourceTree = ""; }; - 477480792C174BAA00580FB2 /* Payload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Payload.swift; sourceTree = ""; }; + 472137C02CF784D400354602 /* WebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebView.swift; sourceTree = ""; }; 47912FD92CB42D640063387D /* AppDelegate_IDFA.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate_IDFA.swift; sourceTree = ""; }; 47D63E2C2C2EAD220055E7D8 /* Mindbox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Mindbox.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 47FFE2252C187D3C0007E2F6 /* SwiftDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftDataManager.swift; sourceTree = ""; }; 4AF2BFD8ABA97C73F589C5DB /* Pods_MindboxNotificationServiceExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MindboxNotificationServiceExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4C06401BC9C282DDDDADEA9D /* Pods-Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.release.xcconfig"; path = "Target Support Files/Pods-Example/Pods-Example.release.xcconfig"; sourceTree = ""; }; 91EB2315545CE887D05CB505 /* Pods_MindboxNotificationContentExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MindboxNotificationContentExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -195,29 +176,17 @@ 0AEDBC822BB6F8F400EE8722 /* Assets.xcassets */, 0A4B68292BBD7D5100639BC5 /* LaunchScreen.storyboard */, 0AEDBC872BB6F8F400EE8722 /* Info.plist */, - 47FFE2242C187D360007E2F6 /* Services */, - 474F37AF2C1710BB00F38BB0 /* Models */, 0AEDBC9D2BB71FC600EE8722 /* Views */, 0AEDBC9E2BB71FD700EE8722 /* ViewModels */, ); path = Example; sourceTree = ""; }; - 0AEDBC972BB7050F00EE8722 /* CustomViews */ = { - isa = PBXGroup; - children = ( - 0AEDBC982BB7058B00EE8722 /* ButtonsView.swift */, - 0AEDBC9A2BB70D6E00EE8722 /* SDKDataView.swift */, - ); - path = CustomViews; - sourceTree = ""; - }; 0AEDBC9D2BB71FC600EE8722 /* Views */ = { isa = PBXGroup; children = ( - 0AEDBC972BB7050F00EE8722 /* CustomViews */, - 474F37AC2C170FA600F38BB0 /* NotificationCenterViews */, - 0AEDBC912BB6FA4800EE8722 /* MainView.swift */, + 0AEDBC912BB6FA4800EE8722 /* ContentView.swift */, + 472137C02CF784D400354602 /* WebView.swift */, ); path = Views; sourceTree = ""; @@ -225,39 +194,11 @@ 0AEDBC9E2BB71FD700EE8722 /* ViewModels */ = { isa = PBXGroup; children = ( - 477480842C1760BE00580FB2 /* ChooseInAppMessagesDelegate */, - 0AEDBC952BB6FE4900EE8722 /* MainViewModel.swift */, - 474F37A12C16F5A700F38BB0 /* NotificationCenterViewModel.swift */, + 0AEDBC952BB6FE4900EE8722 /* ViewModel.swift */, ); path = ViewModels; sourceTree = ""; }; - 474F37AC2C170FA600F38BB0 /* NotificationCenterViews */ = { - isa = PBXGroup; - children = ( - 474F37AD2C170FB600F38BB0 /* NotificationCellView.swift */, - 474F37A32C16F5B000F38BB0 /* NotificationCenterView.swift */, - ); - path = NotificationCenterViews; - sourceTree = ""; - }; - 474F37AF2C1710BB00F38BB0 /* Models */ = { - isa = PBXGroup; - children = ( - 477480792C174BAA00580FB2 /* Payload.swift */, - 472423982C185B8400B2A9BC /* Item+SwiftData.swift */, - ); - path = Models; - sourceTree = ""; - }; - 477480842C1760BE00580FB2 /* ChooseInAppMessagesDelegate */ = { - isa = PBXGroup; - children = ( - 0A4B68192BBC82B500639BC5 /* ChooseInAppMessagesDelegate.swift */, - ); - path = ChooseInAppMessagesDelegate; - sourceTree = ""; - }; 47912FD82CB4130C0063387D /* Samples */ = { isa = PBXGroup; children = ( @@ -266,14 +207,6 @@ path = Samples; sourceTree = ""; }; - 47FFE2242C187D360007E2F6 /* Services */ = { - isa = PBXGroup; - children = ( - 47FFE2252C187D3C0007E2F6 /* SwiftDataManager.swift */, - ); - path = Services; - sourceTree = ""; - }; 52C896E46FFA4E326FC946A8 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -521,10 +454,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 47FFE2282C187D5C0007E2F6 /* SwiftDataManager.swift in Sources */, - 47FFE2232C187B650007E2F6 /* Item+SwiftData.swift in Sources */, 0A0DE3482BB8455A00812E73 /* NotificationService.swift in Sources */, - 47FFE22C2C1886550007E2F6 /* Payload.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -540,19 +470,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 474F37A22C16F5A700F38BB0 /* NotificationCenterViewModel.swift in Sources */, 0AEDBC7A2BB6F8F200EE8722 /* AppDelegate.swift in Sources */, - 0AEDBC992BB7058B00EE8722 /* ButtonsView.swift in Sources */, - 474F37A42C16F5B000F38BB0 /* NotificationCenterView.swift in Sources */, - 0AEDBC922BB6FA4800EE8722 /* MainView.swift in Sources */, - 472423992C185B8400B2A9BC /* Item+SwiftData.swift in Sources */, - 47FFE2262C187D3C0007E2F6 /* SwiftDataManager.swift in Sources */, - 474F37AE2C170FB600F38BB0 /* NotificationCellView.swift in Sources */, - 4774807A2C174BAA00580FB2 /* Payload.swift in Sources */, - 0AEDBC962BB6FE4900EE8722 /* MainViewModel.swift in Sources */, + 0AEDBC922BB6FA4800EE8722 /* ContentView.swift in Sources */, + 0AEDBC962BB6FE4900EE8722 /* ViewModel.swift in Sources */, 0AEDBC7C2BB6F8F200EE8722 /* SceneDelegate.swift in Sources */, - 0AEDBC9B2BB70D6E00EE8722 /* SDKDataView.swift in Sources */, - 0A4B681A2BBC82B500639BC5 /* ChooseInAppMessagesDelegate.swift in Sources */, + 472137C12CF784D400354602 /* WebView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Example/Example/AppDelegate.swift b/Example/Example/AppDelegate.swift index 6ab3bd53..a2751e9e 100644 --- a/Example/Example/AppDelegate.swift +++ b/Example/Example/AppDelegate.swift @@ -33,7 +33,7 @@ final class AppDelegate: MindboxAppDelegate { } catch { print(error.localizedDescription) } - + // https://developers.mindbox.ru/docs/ios-send-push-notifications-appdelegate registerForRemoteNotifications() diff --git a/Example/Example/Models/Item+SwiftData.swift b/Example/Example/Models/Item+SwiftData.swift deleted file mode 100644 index 207c4674..00000000 --- a/Example/Example/Models/Item+SwiftData.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// Item+SwiftData.swift -// Example -// -// Created by Sergei Semko on 6/11/24. -// Copyright © 2024 Mindbox. All rights reserved. -// - -import Foundation -import SwiftData - -@Model -public final class Item { - public var timestamp: Date - public var mbPushNotification: PushNotification - - public init(timestamp: Date, pushNotification: PushNotification) { - self.timestamp = timestamp - self.mbPushNotification = pushNotification - } -} - -public struct PushNotification: Codable { - public let title: String? - public let body: String? - public let clickUrl: String? - public let imageUrl: String? - public let payload: String? - public let uniqueKey: String? - - var decodedPayload: Payload? { - guard let payloadData = payload?.data(using: .utf8) else { return nil } - return try? JSONDecoder().decode(Payload.self, from: payloadData) - } -} diff --git a/Example/Example/Models/Payload.swift b/Example/Example/Models/Payload.swift deleted file mode 100644 index 717e1b10..00000000 --- a/Example/Example/Models/Payload.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// Payload.swift -// Example -// -// Created by Sergei Semko on 6/10/24. -// Copyright © 2024 Mindbox. All rights reserved. -// - -import Foundation - -public struct Payload: Codable { - var pushName: String - var pushDate: String -} diff --git a/Example/Example/SceneDelegate.swift b/Example/Example/SceneDelegate.swift index e48bf989..60250494 100644 --- a/Example/Example/SceneDelegate.swift +++ b/Example/Example/SceneDelegate.swift @@ -20,8 +20,10 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { ) { guard let windowScene = (scene as? UIWindowScene) else { return } let window = UIWindow(windowScene: windowScene) - let viewModel = MainViewModel() - window.rootViewController = UIHostingController(rootView: MainView(viewModel: viewModel)) + + let viewModel = ViewModel() + window.rootViewController = UIHostingController(rootView: ContentView(webViewModel: viewModel)) + self.window = window window.makeKeyAndVisible() } diff --git a/Example/Example/Services/SwiftDataManager.swift b/Example/Example/Services/SwiftDataManager.swift deleted file mode 100644 index 5ff6221e..00000000 --- a/Example/Example/Services/SwiftDataManager.swift +++ /dev/null @@ -1,117 +0,0 @@ -// -// SwiftDataManager.swift -// Example -// -// Created by Sergei Semko on 6/11/24. -// Copyright © 2024 Mindbox. All rights reserved. -// - -import Foundation -import SwiftData -import SwiftUI - -public struct SwiftDataManager { - public static let shared = SwiftDataManager() - public var container: ModelContainer - - private var mockDataSaved: Bool { - UserDefaults.standard.bool(forKey: "isMockDataSaved") - } - - private init() { - SwiftDataManager.createDirectoryForSwiftData() - - let schema = Schema([ - Item.self, - ]) - - let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) - - do { - container = try ModelContainer(for: schema, configurations: [modelConfiguration]) - } catch { - fatalError("Could not create ModelContainer: \(error)") - } - } - - public func saveMockDataIfNeeded() { - guard !mockDataSaved else { - print("MockData already saved") - return - } - Task { - await saveMockData() - } - UserDefaults.standard.set(true, forKey: "isMockDataSaved") - } - - @MainActor - private func saveMockData() { - let context = SwiftDataManager.shared.container.mainContext - - mockNotifications.forEach { notification in - let newItem = Item(timestamp: Date(), pushNotification: notification) - - context.insert(newItem) - - do { - try context.save() - } catch { - print("Failed to save context: \(error.localizedDescription)") - } - } - } - - private static func createDirectoryForSwiftData() { - let fileManager = FileManager.default - let appGroupIdentifier = "group.cloud.Mindbox.cloud.Mindbox.ReleaseExampleIos" - if let appGroupURL = fileManager.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier) { - let applicationSupportURL = appGroupURL.appendingPathComponent("Library/Application Support") - - if !fileManager.fileExists(atPath: applicationSupportURL.path) { - do { - try fileManager.createDirectory(at: applicationSupportURL, withIntermediateDirectories: true, attributes: nil) - } catch { - print("Failed to create Application Support directory: \(error)") - } - } else { - print("Application Support directory already exists at \(applicationSupportURL.path)") - } - } else { - fatalError("Could not find App Group container URL.") - } - } -} - -private extension SwiftDataManager { - var mockNotifications: [PushNotification] { - [ - PushNotification( - title: "First notification title", - body: "First notification body", - clickUrl: "https://mindbox.ru/", - imageUrl: "https://mobpush-images.mindbox.ru/Mpush-test/1a73ebaa-3e5f-49f4-ae6c-462c9b64d34c/307be696-77e6-4d83-b7eb-c94be85f7a03.png", - payload: "{\"pushName\": \"\", \"pushDate\": \"\"}", - uniqueKey: "Push unique key: 1" - ), - - PushNotification( - title: "Second notification title", - body: "Second notification body", - clickUrl: "https://mindbox.ru/", - imageUrl: "https://mobpush-images.mindbox.ru/Mpush-test/1a73ebaa-3e5f-49f4-ae6c-462c9b64d34c/2397fea9-383d-49bf-a6a0-181a267faa94.png", - payload: "{\"pushName\": \"\", \"pushDate\": \"\"}", - uniqueKey: "Push unique key: 2" - ), - - PushNotification( - title: "Third notification title", - body: "Third notification body", - clickUrl: "https://mindbox.ru/", - imageUrl: "https://mobpush-images.mindbox.ru/Mpush-test/1a73ebaa-3e5f-49f4-ae6c-462c9b64d34c/bd4250b1-a7ac-4b8a-b91b-481b3b5c565c.png", - payload: "{\"pushName\": \"\", \"pushDate\": \"\"}", - uniqueKey: "Push unique key: 3" - ), - ] - } -} diff --git a/Example/Example/ViewModels/ChooseInAppMessagesDelegate/ChooseInAppMessagesDelegate.swift b/Example/Example/ViewModels/ChooseInAppMessagesDelegate/ChooseInAppMessagesDelegate.swift deleted file mode 100644 index bfd0f066..00000000 --- a/Example/Example/ViewModels/ChooseInAppMessagesDelegate/ChooseInAppMessagesDelegate.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// ChooseInAppMessagesDelegate.swift -// Example -// -// Created by Дмитрий Ерофеев on 02.04.2024. -// Copyright © 2024 Mindbox. All rights reserved. -// - -import Foundation -import Mindbox - -class ChooseInAppMessagesDelegate: InAppMessagesDelegate { - - private init() {} - static let shared = ChooseInAppMessagesDelegate() - - // https://developers.mindbox.ru/docs/in-app - func inAppMessageTapAction(id: String, url: URL?, payload: String) { - //Here you can add your custom logic - print("inAppMessageTapAction") - print("InApp ID: \(id)") - print("InApp URL: \(String(describing: url))") - print("InApp Payload: \(payload)") - } - - // https://developers.mindbox.ru/docs/in-app - func inAppMessageDismissed(id: String) { - //Here you can add your custom logic - print("inAppMessageDismissed") - print("InApp ID: \(id)") - } - - func select(chooseInappMessageDelegate: ChooseInappMessageDelegate) { - switch chooseInappMessageDelegate { - case .DefaultInappMessageDelegate: - break - case .InAppMessagesDelegate: - Mindbox.shared.inAppMessagesDelegate = self - } - } -} - -enum ChooseInappMessageDelegate { - case DefaultInappMessageDelegate - case InAppMessagesDelegate -} diff --git a/Example/Example/ViewModels/MainViewModel.swift b/Example/Example/ViewModels/MainViewModel.swift deleted file mode 100644 index b0287024..00000000 --- a/Example/Example/ViewModels/MainViewModel.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// MainViewModel.swift -// Example -// -// Created by Дмитрий Ерофеев on 29.03.2024. -// Copyright © 2024 Mindbox. All rights reserved. -// - -import Foundation -import Mindbox -import Observation - -@Observable final class MainViewModel { - - var SDKVersion: String = "" - var deviceUUID: String = "" - var APNSToken: String = "" - - // https://developers.mindbox.ru/docs/ios-sdk-methods - func setupData() { - self.SDKVersion = Mindbox.shared.sdkVersion - Mindbox.shared.getDeviceUUID { deviceUUID in - DispatchQueue.main.async { - self.deviceUUID = deviceUUID - } - } - Mindbox.shared.getAPNSToken { APNSToken in - DispatchQueue.main.async { - self.APNSToken = APNSToken - } - } - ChooseInAppMessagesDelegate.shared.select(chooseInappMessageDelegate: .InAppMessagesDelegate) - } - - // https://developers.mindbox.ru/docs/in-app-targeting-by-custom-operation - func showInAppWithExecuteSyncOperation () { - let json = """ - { "viewProduct": - { "product": - { "ids": - { "website": "1" } - } - } - } - """ - Mindbox.shared.executeSyncOperation(operationSystemName: "APIMethodForReleaseExampleIos", json: json) { result in - switch result { - case .success(let success): - Mindbox.logger.log(level: .info, message: "\(success)") - case .failure(let error): - Mindbox.logger.log(level: .error, message: "\(error)") - } - } - } - - // https://developers.mindbox.ru/docs/in-app-targeting-by-custom-operation - func showInAppWithExecuteAsyncOperation () { - let json = """ - { "viewProduct": - { "product": - { "ids": - { "website": "2" } - } - } - } - """ - Mindbox.shared.executeAsyncOperation(operationSystemName: "APIMethodForReleaseExampleIos", json: json) - } -} diff --git a/Example/Example/ViewModels/NotificationCenterViewModel.swift b/Example/Example/ViewModels/NotificationCenterViewModel.swift deleted file mode 100644 index 882ac0b8..00000000 --- a/Example/Example/ViewModels/NotificationCenterViewModel.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// NotificationCenterViewModel.swift -// Example -// -// Created by Sergei Semko on 6/10/24. -// Copyright © 2024 Mindbox. All rights reserved. -// - -import Mindbox -import Observation - -protocol NotificationCenterViewModelProtocol: AnyObject { - var lastTappedNotification: PushNotification? { get } - var errorMessage: String? { get } - - func sendOperationNCPushOpen(notification: PushNotification) - func sendOperationNCOpen() -} - -@Observable final class NotificationCenterViewModel: NotificationCenterViewModelProtocol { - - // MARK: - NotificationCenterViewModelProtocol - var errorMessage: String? - var lastTappedNotification: PushNotification? - - func sendOperationNCPushOpen(notification: PushNotification) { - lastTappedNotification = notification - - /*Assuming payload of push notification has this structure: - { - "pushName":"", - "pushDate":"" - }*/ - guard let dateTime = notification.decodedPayload?.pushDate, - let translateName = notification.decodedPayload?.pushName else { - errorMessage = "Payload isn't valid for operation" - print("Payload isn't valid for operation") - return - } - - let json = """ - { - "data": { - "customAction": { - "customFields": { - "mobPushSendDateTime": "\(dateTime)", - "mobPushTranslateName": "\(translateName)" - } - } - } - } - """ - - let operationName = "mobileapp.NCPushOpen" - - Mindbox.shared.executeAsyncOperation(operationSystemName: operationName, json: json) - - errorMessage = nil - } - - func sendOperationNCOpen() { - let operationName = "mobileapp.NCOpen" - - Mindbox.shared.executeAsyncOperation(operationSystemName: operationName, json: "{}") - } - - init() { - SwiftDataManager.shared.saveMockDataIfNeeded() - } -} diff --git a/Example/Example/ViewModels/ViewModel.swift b/Example/Example/ViewModels/ViewModel.swift new file mode 100644 index 00000000..d422cd09 --- /dev/null +++ b/Example/Example/ViewModels/ViewModel.swift @@ -0,0 +1,89 @@ +// +// MainViewModel.swift +// Example +// +// Created by Дмитрий Ерофеев on 29.03.2024. +// Copyright © 2024 Mindbox. All rights reserved. +// + +import Observation +import WebKit +import Mindbox + +@Observable final class ViewModel { + + /// Synchronize deviceUUID + func syncMindboxDeviceUUIDs(with webView: WKWebView) { + Mindbox.shared.getDeviceUUID { uuid in + guard !uuid.isEmpty else { + Mindbox.logger.log(level: .error, message: "[WebView]: Device UUID is empty or invalid") + return + } + + let script = """ + document.cookie = "mindboxDeviceUUID=\(uuid); path=/"; + window.localStorage.setItem('mindboxDeviceUUID', '\(uuid)'); + """ + + DispatchQueue.main.async { + webView.evaluateJavaScript(script) { _, error in + if let error = error { + Mindbox.logger.log(level: .error, message: "[WebView]: Error setting cookies and localStorage: \(error)") + } else { + Mindbox.logger.log(level: .default, message: "[WebView]: Cookies and localStorage set successfully.") + } + } + } + } + } + + /// Use this method to clear WebView data + func clearAllWebsiteData() { + let dataStore = WKWebsiteDataStore.default() + let dataTypes = WKWebsiteDataStore.allWebsiteDataTypes() + + dataStore.removeData(ofTypes: dataTypes, modifiedSince: Date.distantPast) { + Mindbox.logger.log(level: .default, message: "[WebView]: All web data cleared") + } + } +} + +// MARK: - Auxiliary functions for debugging + +extension ViewModel { + + /// Use it to debug data after tracker initialize. + /// For example add button for debug + func viewCookiesAndLocalStorage(with webView: WKWebView) { + print("\n" + #function) + + Mindbox.shared.getDeviceUUID { uuid in + let message = "[WebView]: Mobile SDK UUID: \(uuid)" + print(message) + Mindbox.logger.log(level: .default, message: message) + } + + let script = """ + JSON.stringify({ + cookies: document.cookie || "No cookies found", + localStorage: window.localStorage.getItem('mindboxDeviceUUID') || "No value found" + }) + """ + + DispatchQueue.main.async { + webView.evaluateJavaScript(script) { result, error in + if let error = error { + let message = "[WebView]: Error retrieving cookies and localStorage: \(error)" + print(message) + Mindbox.logger.log(level: .error, message: message) + } else { + let message = "[WebView]: Cookies and LocalStorage: \(result ?? "nil")" + print("Start===============") + print("Cookies and LocalStorage: \(result ?? "nil")") + print("===============End\n") + Mindbox.logger.log(level: .default, message: message) + } + } + } + } +} diff --git a/Example/Example/Views/ContentView.swift b/Example/Example/Views/ContentView.swift new file mode 100644 index 00000000..b90599e2 --- /dev/null +++ b/Example/Example/Views/ContentView.swift @@ -0,0 +1,35 @@ +// +// ContentView.swift +// Example +// +// Created by Дмитрий Ерофеев on 29.03.2024. +// Copyright © 2024 Mindbox. All rights reserved. +// + +import SwiftUI +import WebKit + +struct ContentView: View { + + let webViewModel: ViewModel + + private let url = URL(string: "https://your-website.com/") + + var body: some View { + VStack { + WebView(url: url, viewModel: webViewModel) + + Button("Print in console Cookies and LocalStorage") { + guard let webView = WebView.currentWebView else { + print("WebView is not initialized yet") + return + } + webViewModel.viewCookiesAndLocalStorage(with: webView) + }.padding() + } + } +} + +#Preview { + ContentView(webViewModel: ViewModel()) +} diff --git a/Example/Example/Views/CustomViews/ButtonsView.swift b/Example/Example/Views/CustomViews/ButtonsView.swift deleted file mode 100644 index def0c97b..00000000 --- a/Example/Example/Views/CustomViews/ButtonsView.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// ButtonsView.swift -// Example -// -// Created by Дмитрий Ерофеев on 29.03.2024. -// Copyright © 2024 Mindbox. All rights reserved. -// - -import SwiftUI - -struct ButtonsViewline: View { - - var label: String - var action: () -> () - - var body: some View { - HStack { - Text(label) - .foregroundStyle(.mbText) - Spacer() - Button("Show In-App") { - action() - } - .frame(width: 120) - .frame(height: 30) - .background(Color.mbGreen) - .cornerRadius(16) - .tint(.white) - } - } -} - -struct ButtonsView: View { - - var viewModel: MainViewModel - - var body: some View { - ZStack { - RoundedRectangle(cornerRadius: 20) - .frame(width: 350) - .frame(height: 110) - .foregroundColor(.mbView) - VStack { - ButtonsViewline(label: "Async operation") { - viewModel.showInAppWithExecuteAsyncOperation() - } - Divider() - ButtonsViewline(label: "Sync operation") { - viewModel.showInAppWithExecuteSyncOperation() - } - } - .frame(width: 310) - } - } -} diff --git a/Example/Example/Views/CustomViews/SDKDataView.swift b/Example/Example/Views/CustomViews/SDKDataView.swift deleted file mode 100644 index becf8ae5..00000000 --- a/Example/Example/Views/CustomViews/SDKDataView.swift +++ /dev/null @@ -1,74 +0,0 @@ -// -// SDKDataView.swift -// Example -// -// Created by Дмитрий Ерофеев on 29.03.2024. -// Copyright © 2024 Mindbox. All rights reserved. -// - -import SwiftUI - -struct TitleDescrptionView: View { - - var title: String - var message: String - - var body: some View { - HStack { - VStack(alignment: .leading) { - Text(title) - .font(.system(size: 9)) - .padding(.bottom, 2) - .lineLimit(1) - .foregroundStyle(.mbText) - Text(message) - .font(.system(size: 13)) - .contextMenu { - Button { - UIPasteboard.general.string = message - } label: { - Label("Copy", systemImage: "doc.on.doc.fill") - } - } - .lineLimit(1) - .foregroundStyle(.mbText) - } - Spacer() - } - } -} - -struct SDKDataView: View { - - var viewModel: MainViewModel - - var body: some View { - ZStack { - RoundedRectangle(cornerRadius: 20) - .frame(width: 350) - .frame(height: 190) - .foregroundColor(.mbView) - VStack { - HStack { - Text("Data from SDK:") - .foregroundStyle(.mbText) - .padding(.leading, -1) - .padding(.bottom, 5) - Spacer() - } - TitleDescrptionView(title: "SDK version", message: viewModel.SDKVersion) - Divider() - TitleDescrptionView(title: "APNS token", message: viewModel.APNSToken) - Divider() - TitleDescrptionView(title: "Device UUID", message: viewModel.deviceUUID) - } - .frame(width: 310) - } - } -} - -struct SDKDataView_Preview: PreviewProvider { - static var previews: some View { - SDKDataView(viewModel: MainViewModel()) - } -} diff --git a/Example/Example/Views/MainView.swift b/Example/Example/Views/MainView.swift deleted file mode 100644 index 06da3c19..00000000 --- a/Example/Example/Views/MainView.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// MainView.swift -// Example -// -// Created by Дмитрий Ерофеев on 29.03.2024. -// Copyright © 2024 Mindbox. All rights reserved. -// - -import SwiftUI - -struct MainView: View { - - var viewModel: MainViewModel - @State private var showingAlert = !UserDefaults.standard.bool(forKey: "ShownAlert") - - var body: some View { - NavigationStack { - ZStack { - Color.mbBackground.ignoresSafeArea() - VStack(spacing: 32) { - ButtonsView(viewModel: viewModel) - SDKDataView(viewModel: viewModel) - ZStack { - RoundedRectangle(cornerRadius: 20) - .frame(maxWidth: 350) - .frame(maxHeight: 110) - .foregroundColor(.mbView) - NavigationLink("Open Notification Center") { - NotificationCenterView(viewModel: NotificationCenterViewModel()) - .modelContainer(SwiftDataManager.shared.container) - } - .frame(maxWidth: 250) - .frame(maxHeight: 50) - .background(Color.mbGreen) - .cornerRadius(16) - .tint(.white) - } - } - }.onAppear { - viewModel.setupData() - let alertShown = UserDefaults.standard.bool(forKey: "ShownAlert") - if !alertShown { - UserDefaults.standard.set(true, forKey: "ShownAlert") - } - } - .alert("In-App can only be shown once per session", isPresented: $showingAlert) { - Button("OK", role: .cancel) {} - } - } - } -} - -#Preview { - MainView(viewModel: MainViewModel()) -} diff --git a/Example/Example/Views/NotificationCenterViews/NotificationCellView.swift b/Example/Example/Views/NotificationCenterViews/NotificationCellView.swift deleted file mode 100644 index cd477a7d..00000000 --- a/Example/Example/Views/NotificationCenterViews/NotificationCellView.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// NotificationCellView.swift -// Example -// -// Created by Sergei Semko on 6/10/24. -// Copyright © 2024 Mindbox. All rights reserved. -// - -import SwiftUI -import Mindbox - -struct NotificationCellView: View { - var notification: PushNotification - - var body: some View { - HStack(alignment: .center, content: { - if let imageUrl = notification.imageUrl, let url = URL(string: imageUrl) { - AsyncImage(url: url) { image in - image - .resizable() - .scaledToFill() - } placeholder: { - ProgressView() - } - .frame(maxWidth: 64, maxHeight: 64) - .clipShape(Circle()) - } - - VStack(alignment: .leading, content: { - Text(notification.title ?? "Empty") - .font(.headline) - Text(notification.body ?? "Empty") - .font(.subheadline) - .foregroundStyle(.gray) - Text(notification.clickUrl ?? "Empty") - .font(.footnote) - .foregroundStyle(.blue) - }) - }) - } -} diff --git a/Example/Example/Views/NotificationCenterViews/NotificationCenterView.swift b/Example/Example/Views/NotificationCenterViews/NotificationCenterView.swift deleted file mode 100644 index 8f9fad84..00000000 --- a/Example/Example/Views/NotificationCenterViews/NotificationCenterView.swift +++ /dev/null @@ -1,83 +0,0 @@ -// -// NotificationCenterView.swift -// Example -// -// Created by Sergei Semko on 6/10/24. -// Copyright © 2024 Mindbox. All rights reserved. -// - -import SwiftUI -import SwiftData - -struct NotificationCenterView: View { - - var viewModel: NotificationCenterViewModelProtocol - - @State private var showAlert = false - @State private var alertTitle = String() - @State private var alertMessage = String() - - @Environment(\.modelContext) private var modelContext - @Query private var items: [Item] - - var body: some View { - NavigationStack { - List { - ForEach(items.reversed()) { item in - ZStack { - Color.clear - HStack { - NotificationCellView(notification: item.mbPushNotification) - Spacer() - } - } - - .contentShape(Rectangle()) - .onTapGesture { - viewModel.sendOperationNCPushOpen(notification: item.mbPushNotification) - if let errorMessage = viewModel.errorMessage { - alertMessage = errorMessage - } else { - alertMessage = "Operation NCPushOpen sent to Mindbox" - } - showAlert = true - UIImpactFeedbackGenerator(style: .soft).impactOccurred() - } - } - .onDelete(perform: deleteItems) - } - } - .onAppear { - viewModel.sendOperationNCOpen() - } - .navigationTitle("Notification Center") - .navigationBarTitleDisplayMode(.large) - .alert( - alertMessage, - isPresented: $showAlert, - presenting: viewModel.lastTappedNotification) { notification in - Text("Unique key: \(notification.uniqueKey ?? "Empty")") - Button("OK", action: {}) - } - } - - private func deleteItems(offsets: IndexSet) { - withAnimation { - let originalOffsets = IndexSet(offsets.map { items.count - 1 - $0 }) - for index in originalOffsets { - let item = items[index] - if item.mbPushNotification.clickUrl == "https://mindbox.ru/" { - return - } else { - modelContext.delete(items[index]) - - } - } - } - UIImpactFeedbackGenerator(style: .heavy).impactOccurred() - } -} - -#Preview { - NotificationCenterView(viewModel: NotificationCenterViewModel()) -} diff --git a/Example/Example/Views/WebView.swift b/Example/Example/Views/WebView.swift new file mode 100644 index 00000000..67d101bc --- /dev/null +++ b/Example/Example/Views/WebView.swift @@ -0,0 +1,62 @@ +// +// WebView.swift +// Example +// +// Created by Sergei Semko on 11/27/24. +// Copyright © 2024 Mindbox. All rights reserved. +// + +import SwiftUI +import WebKit +import Mindbox + +struct WebView: UIViewRepresentable { + + static var currentWebView: WKWebView? + + let url: URL? + var viewModel: ViewModel + + func makeCoordinator() -> Coordinator { + Coordinator(viewModel: viewModel) + } + + func makeUIView(context: Context) -> WKWebView { + let wkWebView = WKWebView() + wkWebView.navigationDelegate = context.coordinator + +#if DEBUG + // Use this to enable debug + wkWebView.isInspectable = true +#endif + + guard let url else { return wkWebView } + + let request = URLRequest(url: url) + wkWebView.load(request) + + WebView.currentWebView = wkWebView + return wkWebView + } + + func updateUIView(_ uiView: WKWebView, context: Context) { } + + final class Coordinator: NSObject { + var viewModel: ViewModel + + init(viewModel: ViewModel) { + self.viewModel = viewModel + } + } +} + +// MARK: - WKNavigationDelegate + +extension WebView.Coordinator: WKNavigationDelegate { + func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) { + viewModel.syncMindboxDeviceUUIDs(with: webView) + + let message = "[WebView]: \(#function): Content started arriving for: \(webView.url?.absoluteString ?? "Unknown URL")" + Mindbox.logger.log(level: .debug, message: message) + } +} diff --git a/Example/MindboxNotificationServiceExtension/NotificationService.swift b/Example/MindboxNotificationServiceExtension/NotificationService.swift index ab6ef4b9..5496fe03 100644 --- a/Example/MindboxNotificationServiceExtension/NotificationService.swift +++ b/Example/MindboxNotificationServiceExtension/NotificationService.swift @@ -14,14 +14,6 @@ class NotificationService: UNNotificationServiceExtension { lazy var mindboxService = MindboxNotificationService() override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { - let userInfo = request.content.userInfo - - if mindboxService.isMindboxPush(userInfo: userInfo), let mindboxPushNotification = mindboxService.getMindboxPushData(userInfo: userInfo) { - Task { - await saveSwiftDataItem(mindboxPushNotification) - } - } - mindboxService.didReceive(request, withContentHandler: contentHandler) } @@ -30,24 +22,4 @@ class NotificationService: UNNotificationServiceExtension { // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. mindboxService.serviceExtensionTimeWillExpire() } - - @MainActor - private func saveSwiftDataItem(_ mindboxPushNotification: MBPushNotification) async { - let context = SwiftDataManager.shared.container.mainContext - - let push = PushNotification(title: mindboxPushNotification.aps?.alert?.title, - body: mindboxPushNotification.aps?.alert?.body, - clickUrl: mindboxPushNotification.clickUrl, - imageUrl: mindboxPushNotification.imageUrl, - payload: mindboxPushNotification.payload, - uniqueKey: mindboxPushNotification.uniqueKey) - let newItem = Item(timestamp: Date(), pushNotification: push) - - context.insert(newItem) - do { - try context.save() - } catch { - print("Failed to save context: \(error.localizedDescription)") - } - } }