Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 16 additions & 17 deletions platforms/swift/Sources/ShopifyCheckoutKit/CheckoutBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ enum BridgeError: Swift.Error {
case unencodableInstrumentation(Swift.Error? = nil)
}

@MainActor
protocol CheckoutBridgeProtocol {
static func instrument(_ webView: WKWebView, _ instrumentation: InstrumentationPayload)
static func sendMessage(_ webView: WKWebView, messageName: String, messageBody: String?)
Expand Down Expand Up @@ -95,25 +96,23 @@ enum CheckoutBridge: CheckoutBridgeProtocol {
}

static func sendResponse(_ webView: WKWebView, messageBody: String) {
DispatchQueue.main.async {
let script = """
(function() {
try {
if (window.EmbeddedCheckoutProtocol && typeof window.EmbeddedCheckoutProtocol.postMessage === 'function') {
window.EmbeddedCheckoutProtocol.postMessage(\(messageBody));
} else if (window && window.console && window.console.error) {
window.console.error('EmbeddedCheckoutProtocol.postMessage is not available.');
}
} catch (error) {
if (window && window.console && window.console.error) {
window.console.error('Failed to post message to checkout', error);
}
let script = """
(function() {
try {
if (window.EmbeddedCheckoutProtocol && typeof window.EmbeddedCheckoutProtocol.postMessage === 'function') {
window.EmbeddedCheckoutProtocol.postMessage(\(messageBody));
} else if (window && window.console && window.console.error) {
window.console.error('EmbeddedCheckoutProtocol.postMessage is not available.');
}
})();
"""
} catch (error) {
if (window && window.console && window.console.error) {
window.console.error('Failed to post message to checkout', error);
}
}
})();
"""

webView.evaluateJavaScript(script)
}
webView.evaluateJavaScript(script)
}

static func dispatchMessageTemplate(body: String) -> String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import SwiftUI
import UIKit

@MainActor
public class CheckoutViewController: UINavigationController {
public init(checkout url: URL, client: (any CheckoutCommunicationProtocol)? = nil) {
let rootViewController = CheckoutWebViewController(checkoutURL: url, client: client, entryPoint: nil)
Expand Down Expand Up @@ -108,34 +109,39 @@ public struct CheckoutSheet: UIViewControllerRepresentable, CheckoutConfigurable
}

public protocol CheckoutConfigurable {
func backgroundColor(_ color: UIColor) -> Self
func colorScheme(_ colorScheme: ShopifyCheckoutKit.Configuration.ColorScheme) -> Self
func tintColor(_ color: UIColor) -> Self
func title(_ title: String) -> Self
func closeButtonTintColor(_ color: UIColor?) -> Self
@MainActor func backgroundColor(_ color: UIColor) -> Self
@MainActor func colorScheme(_ colorScheme: ShopifyCheckoutKit.Configuration.ColorScheme) -> Self
@MainActor func tintColor(_ color: UIColor) -> Self
@MainActor func title(_ title: String) -> Self
@MainActor func closeButtonTintColor(_ color: UIColor?) -> Self
}

extension CheckoutConfigurable {
@MainActor
@discardableResult public func backgroundColor(_ color: UIColor) -> Self {
ShopifyCheckoutKit.configuration.backgroundColor = color
return self
}

@MainActor
@discardableResult public func colorScheme(_ colorScheme: ShopifyCheckoutKit.Configuration.ColorScheme) -> Self {
ShopifyCheckoutKit.configuration.colorScheme = colorScheme
return self
}

@MainActor
@discardableResult public func tintColor(_ color: UIColor) -> Self {
ShopifyCheckoutKit.configuration.tintColor = color
return self
}

@MainActor
@discardableResult public func title(_ title: String) -> Self {
ShopifyCheckoutKit.configuration.title = title
return self
}

@MainActor
@discardableResult public func closeButtonTintColor(_ color: UIColor?) -> Self {
ShopifyCheckoutKit.configuration.closeButtonTintColor = color
return self
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@
import UIKit
import WebKit

@MainActor
protocol CheckoutWebViewDelegate: AnyObject {
func checkoutViewDidStartNavigation()
func checkoutViewDidFinishNavigation()
func checkoutViewDidClickLink(url: URL)
func checkoutViewDidFailWithError(error: CheckoutError)
}

@MainActor
class CheckoutWebView: WKWebView {
private static var cache: CacheEntry?
var timer: Date?
Expand Down Expand Up @@ -166,10 +168,12 @@ class CheckoutWebView: WKWebView {
deinit {
OSLogger.shared.debug("De-allocating webview")

if isRecovery {
navigationObserver?.invalidate()
} else {
detachBridge()
MainActor.assumeIsolated {
if isRecovery {
navigationObserver?.invalidate()
} else {
detachBridge()
}
}
}

Expand Down Expand Up @@ -243,7 +247,7 @@ class CheckoutWebView: WKWebView {
}
}

extension CheckoutWebView: WKScriptMessageHandler {
extension CheckoutWebView: @preconcurrency WKScriptMessageHandler {
func userContentController(_: WKUserContentController, didReceive message: WKScriptMessage) {
guard let body = message.body as? String else {
return
Expand All @@ -258,15 +262,15 @@ extension CheckoutWebView: WKScriptMessageHandler {
return
}

Task {
Task { @MainActor in
if let response = await client.process(body) {
checkoutBridge.sendResponse(self, messageBody: response)
}
}
}
}

extension CheckoutWebView: WKNavigationDelegate {
extension CheckoutWebView: @preconcurrency WKNavigationDelegate {
func webView(_: WKWebView, decidePolicyFor action: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
guard let url = action.request.url else {
decisionHandler(.allow)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import UIKit
import WebKit

@MainActor
class CheckoutWebViewController: UIViewController, UIAdaptivePresentationControllerDelegate {
var onCancel: (() -> Void)?
var onFail: ((CheckoutError) -> Void)?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import UIKit

@MainActor
enum ConfettiCannon {
static func fire(in view: UIView) {
let layerName = "shopify-confetti"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import UIKit

@MainActor
class ProgressBarView: UIView {
lazy var progressBar: UIProgressView = {
let progressBar = UIProgressView(progressViewStyle: .bar)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ import UIKit
/// The version of the `ShopifyCheckoutKit` library.
public let version = "3.8.0"

var invalidateOnConfigurationChange = true
@MainActor var invalidateOnConfigurationChange = true

/// The configuration options for the `ShopifyCheckoutKit` library.
@MainActor
public var configuration = Configuration() {
didSet {
if invalidateOnConfigurationChange {
Expand All @@ -42,11 +43,13 @@ public var configuration = Configuration() {
}

/// A convienence function for configuring the `ShopifyCheckoutKit` library.
@MainActor
public func configure(_ block: (inout Configuration) -> Void) {
block(&configuration)
}

/// Preloads the checkout for faster presentation.
@MainActor
public func preload(checkout url: URL) {
guard configuration.preloading.enabled else {
return
Expand All @@ -58,10 +61,12 @@ public func preload(checkout url: URL) {
}

/// Invalidate the checkout cache from preload calls
@MainActor
public func invalidate() {
CheckoutWebView.invalidate(disconnect: true)
}

@MainActor
@discardableResult
public func present(checkout url: URL, from: UIViewController, client: (any CheckoutCommunicationProtocol)? = nil) -> CheckoutViewController {
let decorated = CheckoutProtocol.url(for: url, colorScheme: configuration.colorScheme.rawValue)
Expand All @@ -70,6 +75,7 @@ public func present(checkout url: URL, from: UIViewController, client: (any Chec
return viewController
}

@MainActor
@discardableResult
package func present(checkout url: URL, from: UIViewController, entryPoint: MetaData.EntryPoint, client: (any CheckoutCommunicationProtocol)? = nil) -> CheckoutViewController {
let decorated = CheckoutProtocol.url(for: url, colorScheme: configuration.colorScheme.rawValue)
Expand Down
Loading