diff --git a/checkout-v3/modules-sdks/mobile-sdk/bare-minimum-implementation.md b/checkout-v3/modules-sdks/mobile-sdk/bare-minimum-implementation.md index 08d136240b..6ab2ef0868 100644 --- a/checkout-v3/modules-sdks/mobile-sdk/bare-minimum-implementation.md +++ b/checkout-v3/modules-sdks/mobile-sdk/bare-minimum-implementation.md @@ -179,10 +179,11 @@ PaymentSession.paymentSessionState.observe(viewLifecycleOwner) { paymentState -> ## Android Present Payment You are now ready to present the payment UI. You can ask the payment session -class to create a `PaymentFragment` for web view based payments: +class to create a `PaymentFragment` for web view based payments. We request a +menu mode web view, without any restriction of instruments. ```kotlin -paymentSession.createPaymentFragment() +paymentSession.createPaymentFragment(mode = SwedbankPayPaymentSessionSDKControllerMode.Menu(null)) ``` After getting back the `PaymentFragment` instance , you can present it in a way @@ -227,7 +228,7 @@ class MainActivity : AppCompatActivity() { Log.d("SwedbankPay", "Payment Session Fetched") // Reqeust a web based payment fragment instance - paymentSession.createPaymentFragment() + paymentSession.createPaymentFragment(mode = SwedbankPayPaymentSessionSDKControllerMode.Menu(null)) } is PaymentSessionState.ShowPaymentFragment -> { @@ -416,10 +417,11 @@ func paymentSessionCanceled() { ``` You are now ready to present the payment UI. You can ask the payment session -class to create a `SwedbankPaySDKController` for web view based payments. +class to create a `SwedbankPaySDKController` for web view based payments. We +request a menu mode web view, without any restriction of instruments. ```swift -paymentSession.createSwedbankPaySDKController() +paymentSession.createSwedbankPaySDKController(mode: .menu(restrictedToInstruments: nil)) ``` The `SwedbankPaySDKController` instance is returned via the @@ -455,7 +457,7 @@ class ViewController: UIViewController, SwedbankPaySDKPaymentSessionDelegate { func paymentSessionFetched(availableInstruments: [SwedbankPaySDK.AvailableInstrument]) { print("Available Instruments Fetched") - paymentSession.createSwedbankPaySDKController() + paymentSession.createSwedbankPaySDKController(mode: .menu(restrictedToInstruments: nil)) } func sessionProblemOccurred(problem: SwedbankPaySDK.ProblemDetails) { diff --git a/checkout-v3/modules-sdks/mobile-sdk/native-payments.md b/checkout-v3/modules-sdks/mobile-sdk/native-payments.md index 4a7ff23fab..0557babe78 100644 --- a/checkout-v3/modules-sdks/mobile-sdk/native-payments.md +++ b/checkout-v3/modules-sdks/mobile-sdk/native-payments.md @@ -210,9 +210,8 @@ PaymentSession.paymentSessionStatenativePaymentState.observe(viewLifecycleOwner) The `AvailableInstrumentsFetched` state contains a list of `AvailableInstrument` on the `availableInstruments` parameter. This list of payment methods that -can be used for native payments. These instrument object also contain saved -payment method data. This could be saved credit cards or known MSISDN for the -user. +can be used for payments. These instrument object also contain saved payment +method data. This could be saved credit cards or known MSISDN for the user. ## Swish @@ -241,9 +240,9 @@ the MSISDN string before making the native Swish payment attempt. When requesting local start, the SDK will automatically launch the Swish app on the local device. If an error occurred when starting the app, your app will be -informed by the problem by receiving the `SdkProblemOccurred` payment state, -where the `problem` parameter will be -`PaymentSessionProblem.ClientAppLaunchFailed`. +informed by the problem by receiving the `SessionProblemOccurred` payment state, +where the `problem` parameter will have the `type` value +`"https://api.payex.com/psp/errordetail/paymentorders/clientapplaunchfailed"`. ## Saved Credit Cards @@ -590,9 +589,8 @@ func paymentSessionCanceled() { The `availableInstruments` array provided in the `paymentSessionFetched(_:)` delegate method is an array of `SwedbankPaySDK.AvailableInstrument` with information of payment methods that -can be used for native payments. These instrument object also contain saved -payment method data. This could be saved credit cards or known MSISDN for the -user. +can be used for payments. These instrument object also contain saved payment +method data. This could be saved credit cards or known MSISDN for the user. ## Swish @@ -621,9 +619,9 @@ the MSISDN string before making the native Swish payment attempt. When requesting local start, the SDK will automatically launch the Swish app on the local device. If an error occurred when starting the app, the SDK will call -the `sdkProblemOccurred(problem:)` delegate method, and provide the -`SwedbankPaySDK.PaymentSessionProblem.clientAppLaunchFailed` problem as -parameter. +the `sessionProblemOccurred(problem:)` delegate method, and provide a problem +with type `type` parameter set to +`"https://api.payex.com/psp/errordetail/paymentorders/clientapplaunchfailed"`. ## Saved Credit Cards @@ -834,11 +832,6 @@ handled in the following ways: callback function on Android that you can call to retry the underlying API call. You should inform the user of the error and give the option to either abort the payment session or retry the call. -* `ClientAppLaunchFailed` informs you that the SDK have attempted to launch an - external app (such as Swish) and that it failed to do so. You should inform - the user of the problem and give them the option to either make a new - attempt (with any available payment method) or to abort the whole payment - session. * `InternalInconsistencyError` is the result of an logic inconsistency problem in the SDK. An example of this would be to call `abortPaymentSession()` before `startPaymentSession()`. If you receive this error during @@ -862,6 +855,127 @@ the payment order with on your backend. If you get this error in your production app, you should inform the user of a generic technical error and restart the checkout process. +## Alternative checkout flows + +Depending on the checkout flow in your app, there might be a need to implement +the Native Payment feature slightly different. + +### Payment menu fallback + +You might want to give the user an option to make payments in the regular, web +view based, payment menu using the SDK. You can easily achieve this by reusing +the same session and present the web view based SDK UI as a fallback depending +on the user choice. You can also use this functionality to directly present one +specific instrument for the user in the web view. This supports all instruments, +including the instruments not supported as native payments, such as Invoice +payments. + +In the `availableInstruments` array you receive from the session, you will find +instruments indicated as "Web Based". These don't have a corresponding +`PaymentAttemptInstrument`, and can therefore not be used to make native payment +attempts. They can instead be used to configure the web view based SDK UI. + +An example flow for presenting a "More payment methods" for the user: + +```mermaid +sequenceDiagram + participant App + participant SDK + + App ->> SDK: fetchPaymentSession() + activate SDK + App ->> App: Show loading indicator + SDK ->> App: paymentSessionFetched() + deactivate SDK + App ->> App: Present available payment methods to user + note over App: Include custom option
"More payment methods" + opt If a native payment instrument is picked by user + App ->> SDK: makeNativePaymentAttempt() + activate SDK + App ->> App: Show loading indicator + SDK ->> App: paymentComplete() + deactivate SDK + end + opt If "More payment methods" option is picked by user + App ->> SDK: Create payment menu + activate SDK + note over App, SDK: Android: createPaymentFragment()
iOS: createSwedbankPaySDKController() + SDK ->> App: Show payment menu + note over App, SDK: Android: ShowPaymentFragment
iOS: showSwedbankPaySDKController() + App ->> App: Present web based payment menu + SDK ->> App: paymentComplete() + deactivate SDK + end +``` + +You request a web view based payment menu, and specify the mode, using the SDK +with an ongoing session. This web based payment can be presented in three ways: + +1. As a payment menu, displaying all available instruments for the payment + order. +2. As a payment menu, restricting the instruments to a specific subset of the + available instruments for the payment order. +3. As instrument mode, displaying only one specific instrument. + +#### Payment menu + +For a payment menu with all available instruments for the payment order, we +specify the `mode` to `menu` and `restrictedToInstruments` to an empty value. + +```swift +paymentSession.createSwedbankPaySDKController(mode: .menu(restrictedToInstruments: nil)) +``` + +```kotlin +paymentSession.createPaymentFragment(mode = SwedbankPayPaymentSessionSDKControllerMode.Menu(null)) +``` + +#### Payment menu, restricted to instruments + +For a payment menu restricted to specific instruments, we specify the `mode` to +`menu` and `restrictedToInstruments` to an array with the instruments that you +want to show in the menu. In the example below, we filter out so that only the +purely web based instruments are shown, but you are free to specify any logic. +You are free to include both instruments that are web based and those that can +be performed as native payments. + +```swift +let restrictedToInstruments = availableInstruments.filter { + if case .webBased = $0 { + return true + } + + return false +} +paymentSession.createSwedbankPaySDKController(mode: .menu(restrictedToInstruments: restrictedToInstruments)) +``` + + +```kotlin +val restrictedToInstruments = availableInstruments.filterIsInstance() +paymentSession.createPaymentFragment(mode = SwedbankPayPaymentSessionSDKControllerMode.Menu(restrictedToInstruments = restrictedToInstruments)) +``` + +#### Instrument mode + +For instrument mode, we specify `mode` to `instrumentMode` and `instrument` to +the specific instrument that was picked by the user. Note that the SDK exposes +the instrument `paymentMethod` identifiers as strings, and it's up to you to +identify the relevant instrument from the list of available instruments. In the +example below, we explicitly look for the `Invoice-PayExFinancingSe` instrument. + +```swift +if let instrument = availableInstruments.first(where: { $0.paymentMethod == "Invoice-PayExFinancingSe" }) { + paymentSession.createSwedbankPaySDKController(mode: .instrumentMode(instrument: instrument)) +} +``` + +```kotlin +availableInstruments.firstOrNull { it.paymentMethod == "Invoice-PayExFinancingSe" }?.let { instrument -> + paymentSession.createPaymentFragment(SwedbankPayPaymentSessionSDKControllerMode.InstrumentMode(instrument = instrument)) +} +``` + ## Detailed usage flows To expand on the simple happy flow, there are a few more possible scenarios when @@ -943,48 +1057,6 @@ sequenceDiagram * ④ See [Problem handling][problem-handling] for different considerations and outcomes. -### Alternative checkout flows - -Depending on the checkout flow in your app, there might be a need to implement -the Native Payment feature slightly different. - -#### Payment menu fallback - -You might want to give the user an option to use the regular, web view based, -payment menu in the SDK. One simple way to achieve this is to reuse the same -payment order and present the regular SDK UI depending on the user choice: - -```mermaid -sequenceDiagram - participant App - participant SDK - - App ->> SDK: fetchPaymentSession() - activate SDK - App ->> App: Show loading indicator - SDK ->> App: paymentSessionFetched() - deactivate SDK - App ->> App: Present available payment methods to user - note over App: Include custom option
"More payment methods" - opt If a native payment instrument is picked by user - App ->> SDK: makeNativePaymentAttempt() - activate SDK - App ->> App: Show loading indicator - SDK ->> App: paymentComplete() - deactivate SDK - end - opt If "More payment methods" option is picked by user - App ->> SDK: Create payment menu - activate SDK - note over App, SDK: Android: createPaymentFragment()
iOS: createSwedbankPaySDKController() - SDK ->> App: Show payment menu - note over App, SDK: Android: ShowPaymentFragment
iOS: showSwedbankPaySDKController() - App ->> App: Present web based payment menu - SDK ->> App: paymentComplete() - deactivate SDK - end -``` - #### Present methods before payment order creation There might be scenarios where you want to presenting payment methods to your