[Swift] 4.0.0-alpha.3
Pre-releaseBreaking changes
Checkout errors are now a flat value type
CheckoutError changed from an enum with associated values to a struct with stable properties:
-func checkoutDidFail(error: CheckoutError) {
- switch error {
- case .checkoutExpired(_, let code):
- recreateCart(for: code)
- case .checkoutUnavailable(_, let reason):
- handleUnavailableCheckout(reason)
- case .sdkError(let underlyingError):
- report(underlyingError)
- }
-}
+func checkoutDidFail(error: CheckoutError) {
+ switch error.code {
+ case .cartExpired, .cartCompleted, .invalidCart:
+ recreateCart(for: error.code)
+ case .httpError, .networkError:
+ showRetry()
+ case .sdkError, .unknown:
+ report(error.underlyingError)
+ case .storefrontPasswordRequired, .customerAccountRequired:
+ handleStorefrontRequirement(error.code)
+ }
+}The new properties are:
error.code
error.message
error.httpStatusCode
error.underlyingErrorThe intermediate CheckoutUnavailable type and enum cases such as .checkoutExpired, .checkoutUnavailable, and .sdkError have been removed.
Cancellation callbacks were renamed to dismissal
Buyer-initiated sheet closure is now described as dismissal:
final class CheckoutCoordinator: CheckoutDelegate {
- func checkoutDidCancel() {
+ func checkoutDidDismiss() {
closeCheckout()
}
}The SwiftUI modifier was also renamed:
ShopifyCheckout(checkout: checkoutURL)
- .onCancel {
+ .onDismiss {
isCheckoutPresented = false
}Color scheme configuration was replaced by appearance
Configuration.colorScheme and the .colorScheme(...) view modifier were replaced by appearance:
ShopifyCheckoutKit.configure {
- $0.colorScheme = .web
+ $0.appearance = .storefront
} ShopifyCheckout(checkout: checkoutURL)
- .colorScheme(.automatic)
+ .appearance(.app(.automatic))Migration mappings:
-.web
+.storefront
-.automatic
+.app(.automatic)
-.light
+.app(.light)
-.dark
+.app(.dark)The default also changed from an automatic app color scheme to storefront appearance.
Log levels were normalized
LogLevel.all was removed and LogLevel.warn was added:
ShopifyCheckoutKit.configure {
- $0.logLevel = .all
+ $0.logLevel = .debug
}Log levels now behave as ordered thresholds:
debug → warn → error → none
The default changed from .error to .warn.
The Swift protocol module was renamed
Apps that directly depend on the protocol package must rename their product and import:
.target(
name: "YourApp",
dependencies: [
"ShopifyCheckoutKit",
- "ShopifyCheckoutProtocol",
+ "EmbeddedCheckoutProtocol",
]
)-import ShopifyCheckoutProtocol
+import EmbeddedCheckoutProtocolProtocol source types also moved into the EmbeddedCheckoutProtocol module.
Direct protocol event handlers receive envelopes
The underlying protocol descriptors now expose complete JSON-RPC notification and request envelopes. Direct EmbeddedCheckoutProtocol.Client integrations must update handler inputs accordingly.
-client.on(EmbeddedCheckoutProtocol.Event.complete) { checkout in
- handleCompletion(checkout)
+client.on(EmbeddedCheckoutProtocol.Event.complete) { notification in
+ handleCompletion(notification.params.checkout)
}ShopifyCheckoutKit.CheckoutProtocol continues projecting common checkout events to their narrower payloads:
client.on(CheckoutProtocol.complete) { checkout in
handleCompletion(checkout)
}Window-open protocol types moved
WindowOpenRequest, WindowOpenResult, and the window-open descriptor moved from ShopifyCheckoutKit into EmbeddedCheckoutProtocol.
Prefer the Checkout Kit facade when connecting through Checkout Kit:
-client.on(CheckoutProtocol.windowOpen) { request in
- return .success
+client.on(CheckoutProtocol.windowOpen) { request in
+ open(URL(string: request.url)!)
+ return EmbeddedCheckoutProtocol.WindowOpenResult(
+ ucp: /* response envelope */,
+ continueURL: nil,
+ messages: nil
+ )
}Additive changes
Observable preload state
preload(checkout:) now returns an optional CheckoutPreload handle:
-ShopifyCheckoutKit.preload(checkout: checkoutURL)
+let preload = ShopifyCheckoutKit.preload(checkout: checkoutURL)
+preload?.onStateChange = { state in
+ switch state {
+ case .ready:
+ showCheckoutReady()
+ case .failed(let reason):
+ recordPreloadFailure(reason)
+ default:
+ break
+ }
+}The handle publishes its latest state through:
@Published public private(set) var state: PreloadStateRetain the handle for as long as preload changes need to be observed.
New checkout error codes
The flattened error model adds stable codes for:
.customerAccountRequired
.httpError
.networkError
.sdkErrorHTTP failures expose their response status through httpStatusCode.
Warning-level logging
OSLogger now provides:
logger.warn("Checkout will retry")Selecting .warn emits warnings and errors while suppressing debug output.
Behavior changes
Transient navigation failures are retried once
Checkout now retries the initial checkout navigation once for selected transient network failures, including connection loss, host lookup failures, timeouts, and temporary resource unavailability.
If the retry also fails, the SDK reports a terminal .networkError.
Preload failures are observable
Preload can now transition to:
.failed(reason: .httpError(statusCode: status))
.failed(reason: .navigationFailed)
.failed(reason: .keepAliveLost)
.failed(reason: .protocolError)These states describe preload availability and do not necessarily mean a later checkout presentation will fail.
Protocol decode failures are logged
Malformed or unsupported protocol messages now provide more consistent diagnostic logging across the native and web implementations.
What's Changed
- Flatten Swift checkout failure type by @kiftio in #537
- [Android][Swift] Rename oncancel to ondismiss in swift and android by @kiftio in #482
- Retry on didFailProvisionalNavigation by @markmur in #492
- [Swift] Add preload state observability by @markmur in #445
- [Swift] remove color scheme from automatic swift by @kiftio in #470
- [Swift] Canonicalize LogLevel to debug/warn/error/none by @markmur in #441
- Add decode logging parity for Web + Swift + Android by @markmur in #437
- Widen protocol events to expose full envelope by @markmur in #398
- Add Swift checkout appearance configuration by @tiagocandido in #421
- Derive Swift checkout branding from color scheme by @tiagocandido in #405
- Move windowOpen to protocol by @markmur in #386
- Add native checkout close selector for RN E2E by @kyle-schellen in #333
- Rename ShopifyCheckoutProtocol to EmbeddedCheckoutProtocol by @markmur in #354
- Make the OpenRPC spec the single source of truth for the Swift protocol layer by @markmur in #330
- Bump protocol to 2026.04.08.1-alpha.2, Swift and Android to 4.0.0-alpha.3 by @kiftio in #563
Full Changelog: 4.0.0-alpha.2...4.0.0-alpha.3