Skip to content
Merged
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
40 changes: 40 additions & 0 deletions AdyenCheckout/Setup/Checkout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
//

import Adyen
#if canImport(AdyenActions)
import AdyenActions
#endif
#if canImport(AdyenSession)
import AdyenSession
#endif
Expand Down Expand Up @@ -71,6 +74,43 @@ public enum Checkout {
provider: CheckoutProvider.default
)
}

#if canImport(AdyenActions)
/// Passes a URL to the SDK to resume an active redirect action after the shopper returns from a browser or external app.
///
/// Call this from every entry point where your app receives incoming URLs:
///
/// **UIKit - AppDelegate:**
/// ```swift
/// func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
/// Checkout.handleReturn(url: url)
/// return true
/// }
/// ```
///
/// **UIKit - SceneDelegate:**
/// ```swift
/// func scene(_ scene: UIScene, openURLContexts contexts: Set<UIOpenURLContext>) {
/// guard let url = contexts.first?.url else { return }
/// Checkout.handleReturn(url: url)
/// }
/// ```
///
/// **SwiftUI:**
/// ```swift
/// ContentView()
/// .onOpenURL { url in Checkout.handleReturn(url: url) }
/// ```
///
/// It is safe to pass all incoming URLs; any URL not belonging to an active checkout redirect is ignored.
///
/// - Parameter url: The URL received when the shopper returns to the app.
/// - Returns: `true` if the URL was handled by an active checkout redirect; `false` otherwise.
@discardableResult
public static func handleReturn(url: URL) -> Bool {
RedirectComponent.applicationDidOpen(from: url)
}
#endif
}

internal extension Checkout {
Expand Down
30 changes: 30 additions & 0 deletions Tests/UnitTests/AdyenCheckout/CheckoutTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,36 @@ final class CheckoutTests: XCTestCase {
XCTAssertFalse(onFailureCalled)
}

// MARK: - handleReturn

func test_handleReturn_withRegisteredHandler_returnsTrue() throws {
// Given
let url = try XCTUnwrap(URL(string: "adyen://redirect?payload=test"))
let handlerExpectation = expectation(description: "URL handler called")
RedirectListener.registerForURL { receivedURL in
XCTAssertEqual(receivedURL, url)
handlerExpectation.fulfill()
}

// When
let result = Checkout.handleReturn(url: url)

// Then
XCTAssertTrue(result)
waitForExpectations(timeout: 1)
}

func test_handleReturn_withNoRegisteredHandler_returnsFalse() throws {
// Given
let url = try XCTUnwrap(URL(string: "adyen://redirect?payload=test"))

// When
let result = Checkout.handleReturn(url: url)

// Then
XCTAssertFalse(result)
}

private func makeSessionCheckoutCore(
session: SessionProtocol,
callbackStore: SessionCheckoutCallbackStore = SessionCheckoutCallbackStore()
Expand Down
3 changes: 0 additions & 3 deletions docs/redirect/index.html

This file was deleted.

26 changes: 18 additions & 8 deletions docs/v6/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,21 +220,31 @@ Use app-bundle `.strings` or `.xcstrings` files when you want to add a fully new

## Redirect return URLs

If you need to build redirect details from a return URL yourself, use the public `RedirectDetails` API:
Pass incoming URLs to the SDK so active redirect actions can resume after the shopper returns from a browser or external app.

**UIKit - AppDelegate:**
```swift
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
guard let redirectDetails = try? RedirectDetails(returnURL: url) else {
return false
}

let actionData = ActionComponentData(details: redirectDetails, paymentData: nil)
// Submit actionData to your /payments/details handling.
Checkout.handleReturn(url: url)
return true
}
```

If your backend expects `paymentData`, use the value from your previous `/payments` response instead of `nil`.
**UIKit - SceneDelegate:**
```swift
func scene(_ scene: UIScene, openURLContexts contexts: Set<UIOpenURLContext>) {
guard let url = contexts.first?.url else { return }
Checkout.handleReturn(url: url)
}
```

**SwiftUI:**
```swift
ContentView()
.onOpenURL { url in Checkout.handleReturn(url: url) }
```

It is safe to pass all incoming URLs; any URL not belonging to an active checkout redirect is ignored.

## Next steps

Expand Down
Loading