From cc62d39069366a0ae231439e5a4e0940a469ba7f Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Sat, 28 Sep 2024 00:51:41 -0400 Subject: [PATCH 01/29] added KlaviyoWebViewController.swift --- Sources/KlaviyoUI/KlaviyoWebViewController.swift | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 Sources/KlaviyoUI/KlaviyoWebViewController.swift diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebViewController.swift new file mode 100644 index 00000000..3c222f3a --- /dev/null +++ b/Sources/KlaviyoUI/KlaviyoWebViewController.swift @@ -0,0 +1,6 @@ +// +// KlaviyoWebViewController.swift +// klaviyo-swift-sdk +// +// Created by Andrew Balmer on 9/28/24. +// From 6448ced297090dae8b3a4aaeb2c09cceb48bee07 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Sat, 28 Sep 2024 00:56:02 -0400 Subject: [PATCH 02/29] added FileIO.swift implemented `FileIO` removed `internal` access control fixed `getFileContents(...)` --- Sources/KlaviyoUI/Utilities/FileIO.swift | 27 ++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Sources/KlaviyoUI/Utilities/FileIO.swift diff --git a/Sources/KlaviyoUI/Utilities/FileIO.swift b/Sources/KlaviyoUI/Utilities/FileIO.swift new file mode 100644 index 00000000..8eb62c16 --- /dev/null +++ b/Sources/KlaviyoUI/Utilities/FileIO.swift @@ -0,0 +1,27 @@ +// +// FileIO.swift +// KlaviyoSwiftUIWebView +// +// Created by Andrew Balmer on 9/27/24. +// + +import Foundation + +enum FileIOError: Error { + case notFound +} + +enum FileIO { + static func getFileContents(path: String, type: String) throws -> String { + guard let path = Bundle.module.path(forResource: path, ofType: type) else { + throw FileIOError.notFound + } + + do { + let contents = try String(contentsOfFile: path, encoding: String.Encoding.utf8) + return contents + } catch { + throw error + } + } +} From 56bc9242f817596d49b8ed47ce748d35d89ee3ea Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Sat, 28 Sep 2024 19:08:17 -0400 Subject: [PATCH 03/29] initial KlaviyoWebViewController implementation removed config parameter added `createWebView` comments --- .../KlaviyoUI/KlaviyoWebViewController.swift | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebViewController.swift index 3c222f3a..7a4cd63f 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewController.swift @@ -4,3 +4,25 @@ // // Created by Andrew Balmer on 9/28/24. // + +import UIKit +import WebKit + +class KlaviyoWebViewController: UIViewController, WKUIDelegate { + var webView: WKWebView! + + override func loadView() { + super.loadView() + + webView = createWebView() + + view.addSubview(webView) + } + + func createWebView() -> WKWebView { + let webView = WKWebView() + // customize any WKWebView behaviors here + // ex: webView.allowsBackForwardNavigationGestures = true + return webView + } +} From f6127a855b061f413e09aab8f6bf79e33404c46b Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Sat, 28 Sep 2024 19:10:56 -0400 Subject: [PATCH 04/29] added `configureSubviewConstraints()` --- Sources/KlaviyoUI/KlaviyoWebViewController.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebViewController.swift index 7a4cd63f..4f7c48c1 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewController.swift @@ -17,6 +17,8 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { webView = createWebView() view.addSubview(webView) + + configureSubviewConstraints() } func createWebView() -> WKWebView { @@ -25,4 +27,12 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { // ex: webView.allowsBackForwardNavigationGestures = true return webView } + + func configureSubviewConstraints() { + webView.translatesAutoresizingMaskIntoConstraints = false + webView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true + webView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true + webView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true + webView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true + } } From 2cf0623bb195a4e8ed2b15321c0a359d29932e41 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Mon, 30 Sep 2024 10:37:25 -0400 Subject: [PATCH 05/29] added preview added preview title --- Sources/KlaviyoUI/KlaviyoWebViewController.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebViewController.swift index 4f7c48c1..420cc4a5 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewController.swift @@ -36,3 +36,10 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { webView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true } } + +// MARK: - Previews + +@available(iOS 17.0, *) +#Preview("Klaviyo.com") { + KlaviyoWebViewController() +} From b259f39ba0a5bacfe3ff78751732c7eeb6441378 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Mon, 30 Sep 2024 12:09:00 -0400 Subject: [PATCH 06/29] added `createWebViewConfiguration()` method added `createWebViewConfiguration` comments --- Sources/KlaviyoUI/KlaviyoWebViewController.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebViewController.swift index 420cc4a5..43667db2 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewController.swift @@ -21,8 +21,15 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { configureSubviewConstraints() } + func createWebViewConfiguration() -> WKWebViewConfiguration { + let config = WKWebViewConfiguration() + // customize any WKWebViewConfiguration properties here + // ex: config.allowsInlineMediaPlayback = true + return config + } + func createWebView() -> WKWebView { - let webView = WKWebView() + let webView = WKWebView(frame: .zero, configuration: config) // customize any WKWebView behaviors here // ex: webView.allowsBackForwardNavigationGestures = true return webView From ecb58ad8fc73482d8c1ede824a3afbea35b596b3 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Mon, 30 Sep 2024 15:57:58 -0400 Subject: [PATCH 07/29] added `WKNavigationEvent` enum added documentation to `WKNavigationEvent` enum --- .../KlaviyoUI/Models/WKNavigationEvent.swift | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Sources/KlaviyoUI/Models/WKNavigationEvent.swift diff --git a/Sources/KlaviyoUI/Models/WKNavigationEvent.swift b/Sources/KlaviyoUI/Models/WKNavigationEvent.swift new file mode 100644 index 00000000..00afc221 --- /dev/null +++ b/Sources/KlaviyoUI/Models/WKNavigationEvent.swift @@ -0,0 +1,26 @@ +// +// WKNavigationEvent.swift +// klaviyo-swift-sdk +// +// Created by Andrew Balmer on 9/30/24. +// + +enum WKNavigationEvent { + /// Invoked when a main frame navigation starts. + case didStartProvisionalNavigation + + /// Invoked when a server redirect is received for the main frame. + case didReceiveServerRedirectForProvisionalNavigation + + /// Invoked when an error occurs while starting to load data for the main frame. + case didFailProvisionalNavigation + + /// Invoked when content starts arriving for the main frame. + case didCommitNavigation + + /// Invoked when a main frame navigation completes. + case didFinishNavigation + + /// Invoked when an error occurs during a committed main frame navigation. + case didFailNavigation +} From 7c6e6839cacd2f5d73d5c772ebf9acab9bd59993 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Mon, 30 Sep 2024 16:31:36 -0400 Subject: [PATCH 08/29] inject URL --- .../KlaviyoUI/KlaviyoWebViewController.swift | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebViewController.swift index 43667db2..24c3c505 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewController.swift @@ -11,6 +11,18 @@ import WebKit class KlaviyoWebViewController: UIViewController, WKUIDelegate { var webView: WKWebView! + private let url: URL + + init(url: URL) { + self.url = url + super.init(nibName: nil, bundle: nil) + } + + @available(*, unavailable) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func loadView() { super.loadView() @@ -21,6 +33,11 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { configureSubviewConstraints() } + override func viewDidLoad() { + let request = URLRequest(url: url) + webView.load(request) + } + func createWebViewConfiguration() -> WKWebViewConfiguration { let config = WKWebViewConfiguration() // customize any WKWebViewConfiguration properties here @@ -48,5 +65,5 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { @available(iOS 17.0, *) #Preview("Klaviyo.com") { - KlaviyoWebViewController() + KlaviyoWebViewController(url: URL(string: "https://www.klaviyo.com")!) } From 91dc2531a4814996b1dfde688cbfcdf979f58fc9 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Mon, 30 Sep 2024 20:14:25 -0400 Subject: [PATCH 09/29] added `FileIO.getFileUrl(...)` method --- Sources/KlaviyoUI/Utilities/FileIO.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Sources/KlaviyoUI/Utilities/FileIO.swift b/Sources/KlaviyoUI/Utilities/FileIO.swift index 8eb62c16..387339f4 100644 --- a/Sources/KlaviyoUI/Utilities/FileIO.swift +++ b/Sources/KlaviyoUI/Utilities/FileIO.swift @@ -12,6 +12,14 @@ enum FileIOError: Error { } enum FileIO { + static func getFileUrl(path: String, type: String) throws -> URL { + guard let fileUrl = Bundle.module.url(forResource: path, withExtension: type) else { + throw FileIOError.notFound + } + + return fileUrl + } + static func getFileContents(path: String, type: String) throws -> String { guard let path = Bundle.module.path(forResource: path, ofType: type) else { throw FileIOError.notFound From c79b4c30bb9934b5ef10118bb447f666903ef50a Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Mon, 30 Sep 2024 22:12:50 -0400 Subject: [PATCH 10/29] added placeholder code for WKNavigationDelegate methods --- .../KlaviyoUI/KlaviyoWebViewController.swift | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebViewController.swift index 24c3c505..9fd871dd 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewController.swift @@ -27,6 +27,7 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { super.loadView() webView = createWebView() + webView.navigationDelegate = self view.addSubview(webView) @@ -61,6 +62,24 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { } } +extension KlaviyoWebViewController: WKNavigationDelegate { + func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { + <#TODO: code to handle navigation event#> + } + + func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: any Error) { + <#TODO: code to handle navigation event#> + } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + <#TODO: code to handle navigation event#> + } + + func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: any Error) { + <#TODO: code to handle navigation event#> + } +} + // MARK: - Previews @available(iOS 17.0, *) From 05c53d070b5bc6406677ebc89f85a6b3887f1d43 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Mon, 30 Sep 2024 22:25:53 -0400 Subject: [PATCH 11/29] added placeholder code to handle WKScriptMessage --- Sources/KlaviyoUI/KlaviyoWebViewController.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebViewController.swift index 9fd871dd..c0216d3b 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewController.swift @@ -28,6 +28,7 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { webView = createWebView() webView.navigationDelegate = self + webView.uiDelegate = self view.addSubview(webView) @@ -80,6 +81,12 @@ extension KlaviyoWebViewController: WKNavigationDelegate { } } +extension KlaviyoWebViewController: WKScriptMessageHandler { + func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { + <#TODO: code to handle WKSCriptMessage#> + } +} + // MARK: - Previews @available(iOS 17.0, *) From 3cfe28a8d7e15e6f3331c044739edbf6b1931131 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Mon, 30 Sep 2024 23:10:14 -0400 Subject: [PATCH 12/29] refactored webView initialization --- Sources/KlaviyoUI/KlaviyoWebViewController.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebViewController.swift index c0216d3b..c682ce2b 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewController.swift @@ -26,7 +26,8 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { override func loadView() { super.loadView() - webView = createWebView() + let config = createWebViewConfiguration() + webView = createWebView(with: config) webView.navigationDelegate = self webView.uiDelegate = self @@ -47,7 +48,7 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { return config } - func createWebView() -> WKWebView { + func createWebView(with config: WKWebViewConfiguration) -> WKWebView { let webView = WKWebView(frame: .zero, configuration: config) // customize any WKWebView behaviors here // ex: webView.allowsBackForwardNavigationGestures = true From b4e1e9354059e641ee3ca8f720ac654fd09e2a19 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Mon, 30 Sep 2024 23:20:31 -0400 Subject: [PATCH 13/29] added KlaviyoWebViewModel --- Sources/KlaviyoUI/KlaviyoWebViewModel.swift | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 Sources/KlaviyoUI/KlaviyoWebViewModel.swift diff --git a/Sources/KlaviyoUI/KlaviyoWebViewModel.swift b/Sources/KlaviyoUI/KlaviyoWebViewModel.swift new file mode 100644 index 00000000..0c4d823e --- /dev/null +++ b/Sources/KlaviyoUI/KlaviyoWebViewModel.swift @@ -0,0 +1,16 @@ +// +// KlaviyoWebViewModel.swift +// klaviyo-swift-sdk +// +// Created by Andrew Balmer on 9/30/24. +// + +import Foundation + +class KlaviyoWebViewModel { + let url: URL + + init(url: URL) { + self.url = url + } +} From 88e2c1d33dd81d20f61fd7f2e273336b5c28e51d Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Tue, 1 Oct 2024 00:10:42 -0400 Subject: [PATCH 14/29] inject viewModel into viewController --- Sources/KlaviyoUI/KlaviyoWebViewController.swift | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebViewController.swift index c682ce2b..2d14a459 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewController.swift @@ -10,11 +10,10 @@ import WebKit class KlaviyoWebViewController: UIViewController, WKUIDelegate { var webView: WKWebView! + private let viewModel: KlaviyoWebViewModel - private let url: URL - - init(url: URL) { - self.url = url + init(viewModel: KlaviyoWebViewModel) { + self.viewModel = viewModel super.init(nibName: nil, bundle: nil) } @@ -37,7 +36,7 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { } override func viewDidLoad() { - let request = URLRequest(url: url) + let request = URLRequest(url: viewModel.url) webView.load(request) } @@ -92,5 +91,7 @@ extension KlaviyoWebViewController: WKScriptMessageHandler { @available(iOS 17.0, *) #Preview("Klaviyo.com") { - KlaviyoWebViewController(url: URL(string: "https://www.klaviyo.com")!) + let url = URL(string: "https://www.klaviyo.com")! + let viewModel = KlaviyoWebViewModel(url: url) + KlaviyoWebViewController(viewModel: viewModel) } From 1787eaa4ef7ac387107835e88537bba098163b36 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Tue, 1 Oct 2024 00:12:19 -0400 Subject: [PATCH 15/29] added `handleNavigationEvent` method added // MARK --- Sources/KlaviyoUI/KlaviyoWebViewModel.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewModel.swift b/Sources/KlaviyoUI/KlaviyoWebViewModel.swift index 0c4d823e..0a6bb9fc 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewModel.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewModel.swift @@ -13,4 +13,10 @@ class KlaviyoWebViewModel { init(url: URL) { self.url = url } + + // MARK: handle WKWebView events + + func handleNavigationEvent(_ event: WKNavigationEvent) { + // TODO: handle navigation events + } } From 496bf680e6ba7f3de30dafa4dc1f9cc97e779898 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Tue, 1 Oct 2024 00:14:44 -0400 Subject: [PATCH 16/29] call `handleNavigationEvent` from viewController --- Sources/KlaviyoUI/KlaviyoWebViewController.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebViewController.swift index 2d14a459..5dfafc36 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewController.swift @@ -65,19 +65,19 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { extension KlaviyoWebViewController: WKNavigationDelegate { func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { - <#TODO: code to handle navigation event#> + viewModel.handleNavigationEvent(.didStartProvisionalNavigation) } func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: any Error) { - <#TODO: code to handle navigation event#> + viewModel.handleNavigationEvent(.didFailProvisionalNavigation) } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { - <#TODO: code to handle navigation event#> + viewModel.handleNavigationEvent(.didFinishNavigation) } func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: any Error) { - <#TODO: code to handle navigation event#> + viewModel.handleNavigationEvent(.didFailNavigation) } } From d85b440410c50919f0152718e699c124a69e04bd Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Tue, 1 Oct 2024 00:22:06 -0400 Subject: [PATCH 17/29] added `hanldeScriptMessage` method --- Sources/KlaviyoUI/KlaviyoWebViewController.swift | 2 +- Sources/KlaviyoUI/KlaviyoWebViewModel.swift | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebViewController.swift index 5dfafc36..9c9a5bfa 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewController.swift @@ -83,7 +83,7 @@ extension KlaviyoWebViewController: WKNavigationDelegate { extension KlaviyoWebViewController: WKScriptMessageHandler { func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { - <#TODO: code to handle WKSCriptMessage#> + viewModel.handleScriptMessage(message) } } diff --git a/Sources/KlaviyoUI/KlaviyoWebViewModel.swift b/Sources/KlaviyoUI/KlaviyoWebViewModel.swift index 0a6bb9fc..330c7850 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewModel.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewModel.swift @@ -6,6 +6,7 @@ // import Foundation +import WebKit class KlaviyoWebViewModel { let url: URL @@ -19,4 +20,8 @@ class KlaviyoWebViewModel { func handleNavigationEvent(_ event: WKNavigationEvent) { // TODO: handle navigation events } + + func handleScriptMessage(_ message: WKScriptMessage) { + // TODO: handle script message + } } From 7b0872cce4027541d24d988db5d2878590f9160b Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Tue, 1 Oct 2024 10:21:08 -0400 Subject: [PATCH 18/29] added `configureScripts()` renamed `configureScripts` and added documentation renamed `scripts` to `loadScripts` added TODO --- Sources/KlaviyoUI/KlaviyoWebViewController.swift | 9 +++++++++ Sources/KlaviyoUI/KlaviyoWebViewModel.swift | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebViewController.swift index 9c9a5bfa..37c817dc 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewController.swift @@ -32,6 +32,7 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { view.addSubview(webView) + configureLoadScripts() configureSubviewConstraints() } @@ -54,6 +55,14 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { return webView } + /// Configures the scripts to be injected into the website when the website loads. + func configureLoadScripts() { + for (name, script) in viewModel.loadScripts { + webView.configuration.userContentController.addUserScript(script) + webView.configuration.userContentController.add(self, name: name) + } + } + func configureSubviewConstraints() { webView.translatesAutoresizingMaskIntoConstraints = false webView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true diff --git a/Sources/KlaviyoUI/KlaviyoWebViewModel.swift b/Sources/KlaviyoUI/KlaviyoWebViewModel.swift index 330c7850..1b9e9a66 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewModel.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewModel.swift @@ -10,9 +10,19 @@ import WebKit class KlaviyoWebViewModel { let url: URL + let loadScripts: [String: WKUserScript] init(url: URL) { self.url = url + loadScripts = KlaviyoWebViewModel.initializeLoadScripts() + } + + private static func initializeLoadScripts() -> [String: WKUserScript] { + var scripts: [String: WKUserScript] = [:] + + // TODO: initialize scripts + + return scripts } // MARK: handle WKWebView events From a257b0abdd745ea2ded195c04153dd60551cb07c Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Mon, 30 Sep 2024 20:06:43 -0400 Subject: [PATCH 19/29] added resources to Package.swift added bridge.js file --- Package.swift | 3 ++- Sources/KlaviyoUI/Resources/bridge.js | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 Sources/KlaviyoUI/Resources/bridge.js diff --git a/Package.swift b/Package.swift index be1bf6a4..5cb0588c 100644 --- a/Package.swift +++ b/Package.swift @@ -60,7 +60,8 @@ let package = Package( .target( name: "KlaviyoUI", dependencies: ["KlaviyoSwift"], - path: "Sources/KlaviyoUI"), + path: "Sources/KlaviyoUI", + resources: [.process("Resources")]), .testTarget( name: "KlaviyoUITests", dependencies: [ diff --git a/Sources/KlaviyoUI/Resources/bridge.js b/Sources/KlaviyoUI/Resources/bridge.js new file mode 100644 index 00000000..94d16c8d --- /dev/null +++ b/Sources/KlaviyoUI/Resources/bridge.js @@ -0,0 +1,6 @@ +// +// Bridge.js +// klaviyo-swift-sdk +// +// Created by Andrew Balmer on 10/1/24. +// From 59d65b18c1efbe68d07a2867b187515126d73299 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Tue, 1 Oct 2024 14:53:56 -0400 Subject: [PATCH 20/29] added // MARK labels added // MARK labels added MARK --- Sources/KlaviyoUI/KlaviyoWebViewController.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebViewController.swift index 37c817dc..c098b5e2 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewController.swift @@ -12,6 +12,8 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { var webView: WKWebView! private let viewModel: KlaviyoWebViewModel + // MARK: - Initializers + init(viewModel: KlaviyoWebViewModel) { self.viewModel = viewModel super.init(nibName: nil, bundle: nil) @@ -22,6 +24,8 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { fatalError("init(coder:) has not been implemented") } + // MARK: - View loading + override func loadView() { super.loadView() @@ -41,6 +45,8 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { webView.load(request) } + // MARK: - WKWebView configuration + func createWebViewConfiguration() -> WKWebViewConfiguration { let config = WKWebViewConfiguration() // customize any WKWebViewConfiguration properties here @@ -55,6 +61,8 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { return webView } + // MARK: - Scripts + /// Configures the scripts to be injected into the website when the website loads. func configureLoadScripts() { for (name, script) in viewModel.loadScripts { @@ -63,6 +71,8 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { } } + // MARK: - Layout + func configureSubviewConstraints() { webView.translatesAutoresizingMaskIntoConstraints = false webView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true From f51a87f5ad3534a858ed435e31dac33784fb40bd Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Tue, 1 Oct 2024 15:47:10 -0400 Subject: [PATCH 21/29] added script execution logic --- Sources/KlaviyoUI/KlaviyoWebViewController.swift | 16 ++++++++++++++++ Sources/KlaviyoUI/KlaviyoWebViewModel.swift | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebViewController.swift index c098b5e2..8aafe945 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewController.swift @@ -5,12 +5,14 @@ // Created by Andrew Balmer on 9/28/24. // +import Combine import UIKit import WebKit class KlaviyoWebViewController: UIViewController, WKUIDelegate { var webView: WKWebView! private let viewModel: KlaviyoWebViewModel + private var cancellables = Set() // MARK: - Initializers @@ -37,6 +39,7 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { view.addSubview(webView) configureLoadScripts() + configureScriptEvaluator() configureSubviewConstraints() } @@ -71,6 +74,19 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { } } + func configureScriptEvaluator() { + viewModel.scriptSubject.sink { [weak self] script in + Task { [weak self] in + do { + let result = try await self?.webView.evaluateJavaScript(script) as? String ?? "" + // TODO: handle result + } catch { + // TODO: handle error + } + } + }.store(in: &cancellables) + } + // MARK: - Layout func configureSubviewConstraints() { diff --git a/Sources/KlaviyoUI/KlaviyoWebViewModel.swift b/Sources/KlaviyoUI/KlaviyoWebViewModel.swift index 1b9e9a66..2136c1e7 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewModel.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewModel.swift @@ -5,6 +5,7 @@ // Created by Andrew Balmer on 9/30/24. // +import Combine import Foundation import WebKit @@ -12,6 +13,9 @@ class KlaviyoWebViewModel { let url: URL let loadScripts: [String: WKUserScript] + /// Publishes scripts for the `WKWebView` to execute. + let scriptSubject = PassthroughSubject() + init(url: URL) { self.url = url loadScripts = KlaviyoWebViewModel.initializeLoadScripts() From 30e1a3ac9a22128e175c024139762bc872c3f176 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Tue, 1 Oct 2024 16:02:29 -0400 Subject: [PATCH 22/29] changed script executor injection to enable callbacks --- Sources/KlaviyoUI/KlaviyoWebViewController.swift | 8 ++++---- Sources/KlaviyoUI/KlaviyoWebViewModel.swift | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebViewController.swift index 8aafe945..9792cc06 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewController.swift @@ -75,13 +75,13 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { } func configureScriptEvaluator() { - viewModel.scriptSubject.sink { [weak self] script in + viewModel.scriptSubject.sink { [weak self] script, callback in Task { [weak self] in do { - let result = try await self?.webView.evaluateJavaScript(script) as? String ?? "" - // TODO: handle result + let result = try await self?.webView.evaluateJavaScript(script) + callback?(.success(result)) } catch { - // TODO: handle error + callback?(.failure(error)) } } }.store(in: &cancellables) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewModel.swift b/Sources/KlaviyoUI/KlaviyoWebViewModel.swift index 2136c1e7..5e5fab64 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewModel.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewModel.swift @@ -14,7 +14,7 @@ class KlaviyoWebViewModel { let loadScripts: [String: WKUserScript] /// Publishes scripts for the `WKWebView` to execute. - let scriptSubject = PassthroughSubject() + let scriptSubject = PassthroughSubject<(script: String, callback: ((Result) -> Void)?), Never>() init(url: URL) { self.url = url From 2c0f6c3a1161452b699b1104232b00100f291527 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Tue, 1 Oct 2024 16:47:11 -0400 Subject: [PATCH 23/29] made `loadScripts` optional --- Sources/KlaviyoUI/KlaviyoWebViewController.swift | 4 +++- Sources/KlaviyoUI/KlaviyoWebViewModel.swift | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebViewController.swift index 9792cc06..d830db38 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewController.swift @@ -68,7 +68,9 @@ class KlaviyoWebViewController: UIViewController, WKUIDelegate { /// Configures the scripts to be injected into the website when the website loads. func configureLoadScripts() { - for (name, script) in viewModel.loadScripts { + guard let scriptsDict = viewModel.loadScripts else { return } + + for (name, script) in scriptsDict { webView.configuration.userContentController.addUserScript(script) webView.configuration.userContentController.add(self, name: name) } diff --git a/Sources/KlaviyoUI/KlaviyoWebViewModel.swift b/Sources/KlaviyoUI/KlaviyoWebViewModel.swift index 5e5fab64..63a7aef1 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewModel.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewModel.swift @@ -11,7 +11,7 @@ import WebKit class KlaviyoWebViewModel { let url: URL - let loadScripts: [String: WKUserScript] + let loadScripts: [String: WKUserScript]? /// Publishes scripts for the `WKWebView` to execute. let scriptSubject = PassthroughSubject<(script: String, callback: ((Result) -> Void)?), Never>() From a19fd7a544e26542197ff13ad1eb184f38b4965f Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Tue, 1 Oct 2024 16:59:16 -0400 Subject: [PATCH 24/29] created `KlaviyoWebViewModeling` protocol --- .../KlaviyoUI/KlaviyoWebViewModeling.swift | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Sources/KlaviyoUI/KlaviyoWebViewModeling.swift diff --git a/Sources/KlaviyoUI/KlaviyoWebViewModeling.swift b/Sources/KlaviyoUI/KlaviyoWebViewModeling.swift new file mode 100644 index 00000000..ec2bccc0 --- /dev/null +++ b/Sources/KlaviyoUI/KlaviyoWebViewModeling.swift @@ -0,0 +1,23 @@ +// +// KlaviyoWebViewModeling.swift +// klaviyo-swift-sdk +// +// Created by Andrew Balmer on 10/1/24. +// + +import Combine +import Foundation +import WebKit + +protocol KlaviyoWebViewModeling { + var url: URL { get } + + /// Scripts to be injected into the ``WKWebView`` when the website loads. + var loadScripts: [String: WKUserScript]? { get } + + /// Publishes scripts for the ``WKWebView`` to execute. + var scriptSubject: PassthroughSubject<(script: String, callback: ((Result) -> Void)?), Never> { get } + + func handleNavigationEvent(_ event: WKNavigationEvent) + func handleScriptMessage(_ message: WKScriptMessage) +} From 80eabac333f4274992dbd3c0e6576c49f6726ca3 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Tue, 1 Oct 2024 17:06:50 -0400 Subject: [PATCH 25/29] implemented protocol --- Sources/KlaviyoUI/KlaviyoWebViewController.swift | 4 ++-- Sources/KlaviyoUI/KlaviyoWebViewModel.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebViewController.swift index d830db38..0df7c7eb 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewController.swift @@ -11,12 +11,12 @@ import WebKit class KlaviyoWebViewController: UIViewController, WKUIDelegate { var webView: WKWebView! - private let viewModel: KlaviyoWebViewModel + private let viewModel: KlaviyoWebViewModeling private var cancellables = Set() // MARK: - Initializers - init(viewModel: KlaviyoWebViewModel) { + init(viewModel: KlaviyoWebViewModeling) { self.viewModel = viewModel super.init(nibName: nil, bundle: nil) } diff --git a/Sources/KlaviyoUI/KlaviyoWebViewModel.swift b/Sources/KlaviyoUI/KlaviyoWebViewModel.swift index 63a7aef1..7bab7e89 100644 --- a/Sources/KlaviyoUI/KlaviyoWebViewModel.swift +++ b/Sources/KlaviyoUI/KlaviyoWebViewModel.swift @@ -9,7 +9,7 @@ import Combine import Foundation import WebKit -class KlaviyoWebViewModel { +class KlaviyoWebViewModel: KlaviyoWebViewModeling { let url: URL let loadScripts: [String: WKUserScript]? From b14952782dedcc09f56e6c9c0788fcb99b6e6c89 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Tue, 1 Oct 2024 17:11:02 -0400 Subject: [PATCH 26/29] reorganized files --- Package.swift | 2 +- .../{ => KlaviyoWebView}/KlaviyoWebViewController.swift | 0 .../KlaviyoUI/{ => KlaviyoWebView}/KlaviyoWebViewModel.swift | 0 .../KlaviyoUI/{ => KlaviyoWebView}/KlaviyoWebViewModeling.swift | 0 .../{Resources => KlaviyoWebView/Resources/Scripts}/bridge.js | 0 5 files changed, 1 insertion(+), 1 deletion(-) rename Sources/KlaviyoUI/{ => KlaviyoWebView}/KlaviyoWebViewController.swift (100%) rename Sources/KlaviyoUI/{ => KlaviyoWebView}/KlaviyoWebViewModel.swift (100%) rename Sources/KlaviyoUI/{ => KlaviyoWebView}/KlaviyoWebViewModeling.swift (100%) rename Sources/KlaviyoUI/{Resources => KlaviyoWebView/Resources/Scripts}/bridge.js (100%) diff --git a/Package.swift b/Package.swift index 5cb0588c..57a18cce 100644 --- a/Package.swift +++ b/Package.swift @@ -61,7 +61,7 @@ let package = Package( name: "KlaviyoUI", dependencies: ["KlaviyoSwift"], path: "Sources/KlaviyoUI", - resources: [.process("Resources")]), + resources: [.process("KlaviyoWebView/Resources")]), .testTarget( name: "KlaviyoUITests", dependencies: [ diff --git a/Sources/KlaviyoUI/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebView/KlaviyoWebViewController.swift similarity index 100% rename from Sources/KlaviyoUI/KlaviyoWebViewController.swift rename to Sources/KlaviyoUI/KlaviyoWebView/KlaviyoWebViewController.swift diff --git a/Sources/KlaviyoUI/KlaviyoWebViewModel.swift b/Sources/KlaviyoUI/KlaviyoWebView/KlaviyoWebViewModel.swift similarity index 100% rename from Sources/KlaviyoUI/KlaviyoWebViewModel.swift rename to Sources/KlaviyoUI/KlaviyoWebView/KlaviyoWebViewModel.swift diff --git a/Sources/KlaviyoUI/KlaviyoWebViewModeling.swift b/Sources/KlaviyoUI/KlaviyoWebView/KlaviyoWebViewModeling.swift similarity index 100% rename from Sources/KlaviyoUI/KlaviyoWebViewModeling.swift rename to Sources/KlaviyoUI/KlaviyoWebView/KlaviyoWebViewModeling.swift diff --git a/Sources/KlaviyoUI/Resources/bridge.js b/Sources/KlaviyoUI/KlaviyoWebView/Resources/Scripts/bridge.js similarity index 100% rename from Sources/KlaviyoUI/Resources/bridge.js rename to Sources/KlaviyoUI/KlaviyoWebView/Resources/Scripts/bridge.js From 1ec0bfde7f73b3c5295e5f3be065cc57103767f5 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Wed, 2 Oct 2024 11:17:40 -0400 Subject: [PATCH 27/29] added `return` to preview --- Sources/KlaviyoUI/KlaviyoWebView/KlaviyoWebViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/KlaviyoUI/KlaviyoWebView/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebView/KlaviyoWebViewController.swift index 0df7c7eb..756a7254 100644 --- a/Sources/KlaviyoUI/KlaviyoWebView/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebView/KlaviyoWebViewController.swift @@ -130,5 +130,5 @@ extension KlaviyoWebViewController: WKScriptMessageHandler { #Preview("Klaviyo.com") { let url = URL(string: "https://www.klaviyo.com")! let viewModel = KlaviyoWebViewModel(url: url) - KlaviyoWebViewController(viewModel: viewModel) + return KlaviyoWebViewController(viewModel: viewModel) } From b0a5d6757d1d74d372586289b317e56502ec2ea3 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Thu, 3 Oct 2024 16:43:02 -0400 Subject: [PATCH 28/29] added swift version check --- Sources/KlaviyoUI/KlaviyoWebView/KlaviyoWebViewController.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/KlaviyoUI/KlaviyoWebView/KlaviyoWebViewController.swift b/Sources/KlaviyoUI/KlaviyoWebView/KlaviyoWebViewController.swift index 756a7254..0c3b4eae 100644 --- a/Sources/KlaviyoUI/KlaviyoWebView/KlaviyoWebViewController.swift +++ b/Sources/KlaviyoUI/KlaviyoWebView/KlaviyoWebViewController.swift @@ -126,9 +126,11 @@ extension KlaviyoWebViewController: WKScriptMessageHandler { // MARK: - Previews +#if swift(>=5.9) @available(iOS 17.0, *) #Preview("Klaviyo.com") { let url = URL(string: "https://www.klaviyo.com")! let viewModel = KlaviyoWebViewModel(url: url) return KlaviyoWebViewController(viewModel: viewModel) } +#endif From ba283d5fe91dd8d41eb4ceda2c9c40a5cf1c4fa2 Mon Sep 17 00:00:00 2001 From: Andrew Balmer Date: Fri, 4 Oct 2024 15:20:26 -0500 Subject: [PATCH 29/29] reverted Xcode CI build versions --- .github/workflows/swift.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 454bf0f6..e832e28f 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -19,7 +19,7 @@ jobs: runs-on: macos-13 strategy: matrix: - xcode: ['15.2', '15.4', '16.0'] + xcode: ['14.3.1', '15.1'] config: ['debug', 'release'] steps: - uses: actions/checkout@v3