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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 2 additions & 1 deletion .github/actions/select-xcode/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ runs:
using: "composite"
steps:
- name: Select Xcode Version
run: sudo xcode-select -s '/Applications/Xcode_15.4.app/Contents/Developer'
# todo(andrii-vysotskyi): Migrate to public release once available
run: sudo xcode-select -s '/Applications/Xcode_16_beta_6.app/Contents/Developer'
shell: bash
6 changes: 0 additions & 6 deletions Example/Example/Sources/Application/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,4 @@ import ProcessOut
final class SceneDelegate: UIResponder, UIWindowSceneDelegate {

var window: UIWindow?

func scene(_ scene: UIScene, openURLContexts urlContexts: Set<UIOpenURLContext>) {
if let url = urlContexts.first?.url {
ProcessOut.shared.processDeepLink(url: url)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ final class AlternativePaymentsInteractor {

init(
gatewayConfigurationsRepository: POGatewayConfigurationsRepository,
invoicesService: POInvoicesService
invoicesService: POInvoicesService,
alternativePaymentsService: POAlternativePaymentsService
) {
self.gatewayConfigurationsRepository = gatewayConfigurationsRepository
self.invoicesService = invoicesService
self.alternativePaymentsService = alternativePaymentsService
state = .idle
}

Expand Down Expand Up @@ -90,28 +92,13 @@ final class AlternativePaymentsInteractor {
}

func authorize(invoice: POInvoice, gatewayConfigurationId: String) async throws {
let request = POAlternativePaymentMethodRequest(
let request = POAlternativePaymentAuthorizationRequest(
invoiceId: invoice.id, gatewayConfigurationId: gatewayConfigurationId
)
let result: POAlternativePaymentMethodResponse = try await withCheckedThrowingContinuation { continuation in
let session = POWebAuthenticationSession(
request: request,
returnUrl: Example.Constants.returnUrl,
completion: { result in
continuation.resume(with: result)
}
)
Task { @MainActor in
if await session.start() {
return
}
let failure = POFailure(message: "Unable to start alternative payment.", code: .generic(.mobile))
continuation.resume(throwing: failure)
}
}
let authRequest = POInvoiceAuthorizationRequest(invoiceId: invoice.id, source: result.gatewayToken)
let threeDSService = POTest3DSService(returnUrl: Example.Constants.returnUrl)
try await invoicesService.authorizeInvoice(request: authRequest, threeDSService: threeDSService)
let response = try await alternativePaymentsService.authorize(request: request)
let authorizationRequest = POInvoiceAuthorizationRequest(invoiceId: invoice.id, source: response.gatewayToken)
let threeDSService = POTest3DSService()
try await invoicesService.authorizeInvoice(request: authorizationRequest, threeDSService: threeDSService)
}

// MARK: - Private Nested Types
Expand All @@ -124,4 +111,5 @@ final class AlternativePaymentsInteractor {

private let gatewayConfigurationsRepository: POGatewayConfigurationsRepository
private let invoicesService: POInvoicesService
private let alternativePaymentsService: POAlternativePaymentsService
}
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,9 @@ final class AlternativePaymentsViewModel: ObservableObject {
let configuration = PONativeAlternativePaymentConfiguration(
invoiceId: invoice.id,
gatewayConfigurationId: gatewayConfigurationId,
secondaryAction: .cancel(),
cancelButton: .init(),
paymentConfirmation: .init(
showProgressIndicatorAfter: 5,
secondaryAction: .cancel(disabledFor: 10)
showProgressIndicatorAfter: 5, cancelButton: .init()
)
)
let nativePaymentItem = AlternativePaymentsViewModelState.NativePayment(
Expand All @@ -187,7 +186,8 @@ extension AlternativePaymentsViewModel {
convenience init() {
let interactor = AlternativePaymentsInteractor(
gatewayConfigurationsRepository: ProcessOut.shared.gatewayConfigurations,
invoicesService: ProcessOut.shared.invoices
invoicesService: ProcessOut.shared.invoices,
alternativePaymentsService: ProcessOut.shared.alternativePayments
)
self.init(interactor: interactor)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,33 +86,14 @@ extension CardPaymentViewModel: POCardTokenizationDelegate {
let threeDSService: PO3DSService
switch state.authenticationService.selection {
case .test:
threeDSService = POTest3DSService(returnUrl: Constants.returnUrl)
threeDSService = POTest3DSService()
case .checkout:
threeDSService = POCheckout3DSServiceBuilder()
.with(delegate: self)
.with(environment: .sandbox)
.build()
threeDSService = POCheckout3DSService(environment: .sandbox)
}
try await invoicesService.authorizeInvoice(request: invoiceAuthorizationRequest, threeDSService: threeDSService)
}
}

extension CardPaymentViewModel: POCheckout3DSServiceDelegate {

func handle(redirect: PO3DSRedirect, completion: @escaping (Result<String, POFailure>) -> Void) {
Task { @MainActor in
let session = POWebAuthenticationSession(
redirect: redirect, returnUrl: Constants.returnUrl, completion: completion
)
if await session.start() {
return
}
let failure = POFailure(message: "Unable to process redirect", code: .generic(.mobile))
completion(.failure(failure))
}
}
}

extension CardPaymentViewModel {

/// Convenience initializer that resolves its dependencies automatically.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ final class DynamicCheckoutViewModel: ObservableObject {
private func continueDynamicCheckout(invoice: POInvoice) {
let configuration = PODynamicCheckoutConfiguration(
invoiceRequest: .init(invoiceId: invoice.id, clientSecret: invoice.clientSecret),
alternativePayment: .init(returnUrl: Constants.returnUrl),
alternativePayment: .init(),
cancelButton: .init(confirmation: .init())
)
let item = DynamicCheckoutViewModelState.DynamicCheckout(
Expand Down Expand Up @@ -95,7 +95,7 @@ extension DynamicCheckoutViewModel: PODynamicCheckoutDelegate {
func dynamicCheckout(
willAuthorizeInvoiceWith request: inout POInvoiceAuthorizationRequest
) async -> any PO3DSService {
POTest3DSService(returnUrl: Constants.returnUrl)
POTest3DSService()
}

func dynamicCheckout(willAuthorizeInvoiceWith request: PKPaymentRequest) async {
Expand Down
5 changes: 1 addition & 4 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version: 5.9
// swift-tools-version: 6.0

import PackageDescription

Expand All @@ -21,9 +21,6 @@ let package = Package(
targets: [
.target(
name: "ProcessOut",
dependencies: [
.product(name: "cmark-gfm", package: "swift-cmark")
],
resources: [
.process("Resources")
]
Expand Down
5 changes: 2 additions & 3 deletions ProcessOut.podspec
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
Pod::Spec.new do |s|
s.name = 'ProcessOut'
s.version = '4.20.0'
s.swift_versions = ['5.9']
s.swift_versions = ['6.0']
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.homepage = 'https://github.com/processout/processout-ios'
s.author = 'ProcessOut'
s.summary = 'The smart router for payments. Smartly route each transaction to the relevant payment providers.'
s.source = { :git => 'https://github.com/processout/processout-ios.git', :tag => s.version.to_s }
s.frameworks = 'Foundation', 'UIKit'
s.ios.deployment_target = '13.0'
s.vendored_frameworks = "Vendor/cmark_gfm.xcframework"
s.ios.deployment_target = '14.0'
s.ios.resources = 'Sources/ProcessOut/Resources/**/*'
s.source_files = 'Sources/ProcessOut/**/*.swift'
s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS' => '-Xfrontend -module-interface-preserve-types-as-written' }
Expand Down
4 changes: 2 additions & 2 deletions ProcessOutCheckout3DS.podspec
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
Pod::Spec.new do |s|
s.name = 'ProcessOutCheckout3DS'
s.version = '4.20.0'
s.swift_versions = ['5.9']
s.swift_versions = ['6.0']
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.homepage = 'https://github.com/processout/processout-ios'
s.author = 'ProcessOut'
s.summary = 'Integration with Checkout.com 3D Secure (3DS) mobile SDK.'
s.source = { :git => 'https://github.com/processout/processout-ios.git', :tag => s.version.to_s }
s.frameworks = 'Foundation'
s.ios.deployment_target = '13.0'
s.ios.deployment_target = '14.0'
s.ios.resources = 'Sources/ProcessOutCheckout3DS/Resources/**/*'
s.source_files = 'Sources/ProcessOutCheckout3DS/**/*.swift'
s.pod_target_xcconfig = { 'EXCLUDED_ARCHS' => 'x86_64' }
Expand Down
4 changes: 2 additions & 2 deletions ProcessOutCoreUI.podspec
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
Pod::Spec.new do |s|
s.name = 'ProcessOutCoreUI'
s.version = '4.20.0'
s.swift_versions = ['5.9']
s.swift_versions = ['6.0']
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.homepage = 'https://github.com/processout/processout-ios'
s.author = 'ProcessOut'
s.summary = 'Reusable UI components and logic. Pod is meant to be used only with other ProcessOut pods.'
s.source = { :git => 'https://github.com/processout/processout-ios.git', :tag => s.version.to_s }
s.frameworks = 'Foundation', 'SwiftUI'
s.vendored_frameworks = "Vendor/cmark_gfm.xcframework"
s.ios.deployment_target = '14.0'
s.ios.resources = 'Sources/ProcessOutCoreUI/Resources/**/*'
s.source_files = 'Sources/ProcessOutCoreUI/**/*.swift'
s.dependency 'ProcessOut' # todo(andrii-vysotskyi): vendor cmark_gfm.xcframework instead after UI migration is completed
end
2 changes: 1 addition & 1 deletion ProcessOutUI.podspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|
s.name = 'ProcessOutUI'
s.version = '4.20.0'
s.swift_versions = ['5.9']
s.swift_versions = ['6.0']
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.homepage = 'https://github.com/processout/processout-ios'
s.author = 'ProcessOut'
Expand Down
5 changes: 4 additions & 1 deletion Scripts/Test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ set -euo pipefail
PROJECT='ProcessOut.xcodeproj'
DESTINATION=$(./Scripts/TestDestination.swift)

# todo(andrii-vysotskyi): reenable "ProcessOutCheckout3DS" tests
# when Swift6 compatibility is fixed

# Run Tests
for PRODUCT in "ProcessOut" "ProcessOutUI" "ProcessOutCheckout3DS"; do
for PRODUCT in "ProcessOut" "ProcessOutUI"; do
xcodebuild clean test \
-destination "$DESTINATION" \
-project $PROJECT \
Expand Down
13 changes: 3 additions & 10 deletions Sources/ProcessOut/ProcessOut.docc/3DS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

Some SDK methods may trigger 3DS flow, those methods could be identified by presence of required parameter
`threeDSService` whose argument should conform to ``PO3DSService`` protocol.
``POInvoicesService/authorizeInvoice(request:threeDSService:completion:)`` is an example of such method.
``POInvoicesService/authorizeInvoice(request:threeDSService:)`` is an example of such method.

### 3DS2

Expand All @@ -14,15 +14,8 @@ allows to abstract the details of 3DS handling and supply functionality in a con
We officially support our own implementation `POTest3DSService` (defined in `ProcessOutUI` package) that emulates
the normal 3DS authentication flow.

Also, there is an integration with [Checkout](https://checkout.com) 3DS2 SDK that is available in `ProcessOutCheckout3DS`
Also, there is an integration with [Checkout](https://checkout.com) 3DS2 SDK that is available
in [`ProcessOutCheckout3DS`](https://swiftpackageindex.com/processout/processout-ios/documentation/processoutcheckout3ds)
package.

### 3DS Redirect

Method ``PO3DSService/handle(redirect:completion:)`` is a part of 3DS service that is responsible for handling web
based redirects.

We provide an extension of `SFSafariViewController` (defined in `ProcessOutUI` package) that can be used to create an
instance, capable of handling redirects.

For additional details on 3DS UI see dedicated [documentation.](https://swiftpackageindex.com/processout/processout-ios/documentation/processoutui/3ds)
2 changes: 1 addition & 1 deletion Sources/ProcessOut/ProcessOut.docc/Localizations.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
## Overview

If the main application uses a language that we don't support, the implementation would attempt to use strings from
the main bundle's `ProcessOut.strings`.
the main bundle's `ProcessOut.strings`.

You may add translations to `ProcessOut.stringsdict` file if special rules for plurals are desired.
Loading