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
23 changes: 21 additions & 2 deletions platforms/swift/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ iOS handles checkout geolocation permission prompts through the system prompt. I

### Configure accelerated checkouts

Create shared configuration values and inject them into your SwiftUI hierarchy:
Create shared configuration values and apply them to your SwiftUI hierarchy:

```swift
import ShopifyAcceleratedCheckouts
Expand All @@ -484,13 +484,23 @@ struct YourApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.shopifyAcceleratedCheckoutsConfiguration, checkoutConfig)
.shopifyAcceleratedCheckouts(checkoutConfig)
.environment(\.shopifyApplePayConfiguration, applePayConfig)
}
}
}
```

Apply `.shopifyAcceleratedCheckouts(_:)` as soon as the shop configuration is available. The
modifier preserves the configuration in the SwiftUI environment and automatically prefetches the
shop settings used by the wallet buttons. Requests are deduplicated across button instances;
settings remain fresh for one hour and stale settings are served while they refresh in the
background. Existing direct environment injection remains supported.

Set `ShopifyAcceleratedCheckouts.logLevel = .debug` to inspect privacy-safe request, cache
freshness, prefetch, and wallet button loading timings. These logs do not include shop
configuration values or checkout identifiers.

Use one customer mode at a time:

```swift
Expand Down Expand Up @@ -528,6 +538,15 @@ AcceleratedCheckoutButtons(cartID: cartID)
.connect(client)
```

While shop settings load, the SDK renders neutral placeholders matching the height, spacing,
count, and corner radius of the configured wallet buttons. The placeholders respect Reduce Motion
and are hidden from accessibility. To provide your own loading UI, disable the SDK presentation:

```swift
AcceleratedCheckoutButtons(cartID: cartID)
.loadingPresentation(.hidden)
```

You can also render buttons for a single product variant:

```swift
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import ShopifyAcceleratedCheckouts
import ShopifyCheckoutKit
import UIKit

Expand All @@ -21,6 +22,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
let checkoutKitLogLevel: LogLevel = getLogLevel(
key: AppStorageKeys.checkoutKitLogLevel.rawValue
)
let acceleratedCheckoutsLogLevel: LogLevel = getLogLevel(
key: AppStorageKeys.acceleratedCheckoutsLogLevel.rawValue
)
let checkoutPreloadingEnabled = UserDefaults.standard.object(
forKey: AppStorageKeys.checkoutPreloadingEnabled.rawValue
) as? Bool ?? true
Expand All @@ -32,8 +36,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
$0.logLevel = checkoutKitLogLevel
$0.preloading.enabled = checkoutPreloadingEnabled
}
ShopifyAcceleratedCheckouts.logLevel = acceleratedCheckoutsLogLevel

print("[CheckoutKitSwiftDemo] CheckoutKit Log level set to \(checkoutKitLogLevel)")
print(
"[CheckoutKitSwiftDemo] Accelerated Checkouts Log level set to \(acceleratedCheckoutsLogLevel)"
)

UIBarButtonItem.appearance().tintColor = ColorPalette.primaryColor

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Combine
import ShopifyAcceleratedCheckouts
import ShopifyCheckoutKit
import SwiftUI
import UIKit
Expand All @@ -17,9 +18,15 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var cancellables: Set<AnyCancellable> = []

let uiKitCartController = CartViewController()
let swiftUICartController = UIHostingController(rootView: CartView())
let productGridController = UIHostingController(rootView: ProductGridView())
let productGalleryController = UIHostingController(rootView: ProductGalleryView())
let swiftUICartController = UIHostingController(
rootView: AcceleratedCheckoutsConfiguredView(content: CartView())
)
let productGridController = UIHostingController(
rootView: AcceleratedCheckoutsConfiguredView(content: ProductGridView())
)
let productGalleryController = UIHostingController(
rootView: AcceleratedCheckoutsConfiguredView(content: ProductGalleryView())
)
let accountController = UIHostingController(rootView: AccountView())
let settingsController = UIHostingController(rootView: SettingsView())

Expand Down Expand Up @@ -309,6 +316,31 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
}
}

struct AcceleratedCheckoutsConfiguredView<Content: View>: View {
let content: Content

var body: some View {
if #available(iOS 16.0, *) {
content
.shopifyAcceleratedCheckouts(
ShopifyAcceleratedCheckouts.Configuration(
storefrontDomain: InfoDictionary.shared.domain,
storefrontAccessToken: InfoDictionary.shared.accessToken
)
)
.environment(
\.shopifyApplePayConfiguration,
ShopifyAcceleratedCheckouts.ApplePayConfiguration(
merchantIdentifier: InfoDictionary.shared.merchantIdentifier,
contactFields: [.email, .phone]
)
)
} else {
content
}
}
}

extension Notification.Name {
static let colorSchemeChanged = Notification.Name("colorSchemeChanged")
static let navigateToAccount = Notification.Name("navigateToAccount")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,6 @@ struct CartView: View {
print("[AcceleratedCheckout] Dismissed")
}
.connect(client)
.environment(
\.shopifyAcceleratedCheckoutsConfiguration,
ShopifyAcceleratedCheckouts.Configuration(
storefrontDomain: InfoDictionary.shared.domain,
storefrontAccessToken: InfoDictionary.shared.accessToken
)
)
.environment(
\.shopifyApplePayConfiguration,
ShopifyAcceleratedCheckouts.ApplePayConfiguration(
merchantIdentifier: InfoDictionary.shared.merchantIdentifier,
contactFields: [.email, .phone]
)
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,20 +123,6 @@ struct ProductView: View {
.onDismiss {
print("[AcceleratedCheckout] Dismissed")
}
.environment(
\.shopifyAcceleratedCheckoutsConfiguration,
ShopifyAcceleratedCheckouts.Configuration(
storefrontDomain: InfoDictionary.shared.domain,
storefrontAccessToken: InfoDictionary.shared.accessToken
)
)
.environment(
\.shopifyApplePayConfiguration,
ShopifyAcceleratedCheckouts.ApplePayConfiguration(
merchantIdentifier: InfoDictionary.shared.merchantIdentifier,
contactFields: [.email, .phone]
)
)
}
}
}.padding([.leading, .trailing], 15)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Combine
import PassKit
import ShopifyAcceleratedCheckouts
import ShopifyCheckoutKit
import SwiftUI

Expand Down Expand Up @@ -36,6 +37,13 @@ struct SettingsView: View {
}
}

@AppStorage(AppStorageKeys.acceleratedCheckoutsLogLevel.rawValue)
var acceleratedCheckoutsLogLevel: LogLevel = .debug {
didSet {
ShopifyAcceleratedCheckouts.logLevel = acceleratedCheckoutsLogLevel
}
}

@AppStorage(AppStorageKeys.applePayStyle.rawValue)
var applePayStyle: ApplePayStyleOption = .automatic

Expand Down Expand Up @@ -160,6 +168,21 @@ struct SettingsView: View {
}
.pickerStyle(.menu)

Picker(
"Accelerated Checkouts",
selection: Binding(
get: { acceleratedCheckoutsLogLevel },
set: { acceleratedCheckoutsLogLevel = $0 }
)
) {
ForEach(LogLevel.allCases, id: \.self) { level in
Text(
level.rawValue.capitalized(with: Locale.current)
).tag(level)
}
}
.pickerStyle(.menu)

NavigationLink(destination: LogsView()) {
Text("Logs")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ struct ShopifyAcceleratedCheckoutsApp: App {
ShopifyAcceleratedCheckouts.logLevel = logLevel
updateConfiguration()
}
.environment(\.shopifyAcceleratedCheckoutsConfiguration, configuration)
.shopifyAcceleratedCheckouts(configuration)
.environment(\.shopifyApplePayConfiguration, applePayConfiguration)
}
.environment(\.locale, Locale(identifier: locale))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,6 @@ private struct CheckoutSection<Content: View>: View {
.foregroundColor(.primary)
.multilineTextAlignment(.center)

if case .loading = renderState {
VStack(spacing: 12) {
SkeletonButton(cornerRadius: 8)
SkeletonButton(cornerRadius: 8)
}
}

if case .error = renderState {
VStack {
Image(systemName: "exclamationmark.triangle")
Expand Down
Loading
Loading