Skip to content

Commit bbbcd62

Browse files
authored
Merge pull request #899 from Adyen/ios-error-handling
Improve invalid client key error handling
2 parents 529f8ab + 2b31aea commit bbbcd62

File tree

9 files changed

+165
-123
lines changed

9 files changed

+165
-123
lines changed

ios/CSE/ActionModule.swift

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,7 @@ internal final class ActionModule: BaseModule, ActionComponentDelegate {
3030
}
3131

3232
func didFail(with error: Error, from component: Adyen.ActionComponent) {
33-
let errorToSend = checkErrorType(error)
34-
if let error = error as? NativeModuleError {
35-
return reject(with: error)
36-
}
37-
rejecter?(Constant.componentError, error.localizedDescription, error)
33+
reject(with: error)
3834
}
3935

4036
@objc
@@ -50,12 +46,8 @@ internal final class ActionModule: BaseModule, ActionComponentDelegate {
5046
do {
5147
action = try parseAction(from: actionJson)
5248
context = try parser.fetchContext(session: BaseModule.session)
53-
} catch NativeModuleError.invalidAction {
54-
return reject(with: NativeModuleError.invalidAction)
55-
} catch NativeModuleError.noClientKey {
56-
return reject(with: NativeModuleError.noClientKey)
5749
} catch {
58-
return rejecter(Constant.parsingErrorCode, error.localizedDescription, error)
50+
return reject(with: error)
5951
}
6052

6153
let style = AdyenAppearanceLoader.findStyle()?.actionComponent ?? .init()
@@ -81,13 +73,18 @@ internal final class ActionModule: BaseModule, ActionComponentDelegate {
8173
}
8274

8375
private enum Constant {
84-
static var moduleName = "ActionModule"
8576
static var threeDS2SdkVersionName = "threeDS2SdkVersion"
86-
static var parsingErrorCode = "parsingError"
8777
static var componentError = "actionError"
8878
}
8979

9080
func reject(with error: NativeModuleError) {
9181
rejecter?(error.errorCode, error.errorDescription, error)
9282
}
83+
84+
func reject(with error: any Error) {
85+
if let nativeError = NativeModuleError.checkErrorType(error) as? NativeModuleError {
86+
return reject(with: nativeError)
87+
}
88+
rejecter?(Constant.componentError, error.localizedDescription, error)
89+
}
9390
}

ios/Components/ApplePay/ApplePayModule.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ struct PKPaymentAuthorizationServiceAdapter: PKPaymentAuthorizationService {
130130
func canMakePayments(usingNetworks: [PKPaymentNetwork]) -> Bool {
131131
PKPaymentAuthorizationViewController.canMakePayments(usingNetworks: usingNetworks)
132132
}
133-
133+
134134
func getAuthorizationViewController(paymentRequest: PKPaymentRequest) -> PKPaymentAuthorizationViewController? {
135135
PKPaymentAuthorizationViewController(paymentRequest: paymentRequest)
136136
}

ios/Components/BaseModule.swift

Lines changed: 5 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import Adyen
88
import Adyen3DS2
9+
import AdyenNetworking
910
import React
1011
import UIKit
1112

@@ -41,7 +42,9 @@ internal class BaseModule: RCTEventEmitter {
4142
internal var actionHandler: AdyenActionComponent?
4243

4344
internal func present(_ component: PresentableComponent) {
44-
guard let presenter = BaseModule.currentPresenter ?? UIViewController.topPresenter else { return sendEvent(error: NativeModuleError.notKeyWindow) }
45+
guard let presenter = BaseModule.currentPresenter ?? UIViewController.topPresenter else {
46+
return sendEvent(error: NativeModuleError.notKeyWindow)
47+
}
4548

4649
defer {
4750
BaseModule.currentPresenter = presenter
@@ -72,15 +75,8 @@ internal class BaseModule: RCTEventEmitter {
7275
sendEvent(withName: event.rawValue, body: [:])
7376
}
7477

75-
internal func checkErrorType(_ error: Error) -> Error {
76-
if error.isComponentCanceled || error.is3DSCanceled {
77-
return NativeModuleError.canceled
78-
}
79-
return error
80-
}
81-
8278
internal func sendEvent(error: Error) {
83-
let errorToSend = checkErrorType(error)
79+
let errorToSend = NativeModuleError.checkErrorType(error)
8480
sendEvent(withName: Events.didFail.rawValue, body: errorToSend.jsonObject)
8581
}
8682

@@ -164,87 +160,6 @@ internal class BaseModule: RCTEventEmitter {
164160
}
165161
}
166162
}
167-
}
168-
169-
extension Error {
170-
171-
var isComponentCanceled: Bool { (self as? ComponentError) == ComponentError.cancelled }
172-
173-
var is3DSCanceled: Bool {
174-
(self as NSError).domain == "com.adyen.Adyen3DS2.ADYRuntimeError" &&
175-
(self as NSError).code == ADYRuntimeErrorCode.challengeCancelled.rawValue
176-
}
177-
}
178-
179-
extension BaseModule {
180-
181-
enum NativeModuleError: LocalizedError, KnownError {
182-
case canceled
183-
case noClientKey
184-
case noPayment
185-
case notSupported
186-
case invalidPaymentMethods
187-
case invalidAction
188-
case notKeyWindow
189-
case paymentMethodNotFound(PaymentMethod.Type)
190-
case balanceCheck(message: String)
191-
case orderRequest(message: String)
192-
case sessionError
193-
194-
var errorCode: String {
195-
switch self {
196-
case .canceled:
197-
return "canceledByShopper"
198-
case .notSupported:
199-
return "notSupported"
200-
case .noClientKey:
201-
return "noClientKey"
202-
case .noPayment:
203-
return "noPayment"
204-
case .invalidPaymentMethods:
205-
return "invalidPaymentMethods"
206-
case .invalidAction:
207-
return "invalidAction"
208-
case .paymentMethodNotFound:
209-
return "noPaymentMethod"
210-
case .notKeyWindow:
211-
return "notKeyWindow"
212-
case .balanceCheck:
213-
return "balanceCheck"
214-
case .orderRequest:
215-
return "orderRequest"
216-
case .sessionError:
217-
return "sessionError"
218-
}
219-
}
220-
221-
var errorDescription: String? {
222-
switch self {
223-
case .canceled:
224-
return "Payment canceled by shopper"
225-
case .notSupported:
226-
return "Not supported on iOS"
227-
case .noClientKey:
228-
return "No clientKey in configuration"
229-
case .noPayment:
230-
return "No payment in configuration"
231-
case .invalidPaymentMethods:
232-
return "Can not parse paymentMethods or the list is empty"
233-
case .invalidAction:
234-
return "Can not parse action"
235-
case let .paymentMethodNotFound(type):
236-
return "Can not find payment method of type \(type) in provided list"
237-
case .notKeyWindow:
238-
return "Can not find root ViewController"
239-
case let .balanceCheck(message):
240-
return "Balance check error: \(message)"
241-
case let .orderRequest(message):
242-
return "Order request error: \(message)"
243-
case .sessionError:
244-
return "Something went wrong while starting session"
245-
}
246-
}
247-
}
248163

249164
enum Keys {
250165
static let sessionId = "sessionId"

ios/Components/DropInModule.swift

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ internal final class DropInModule: BaseModule {
3131
func update(_ results: NSArray) {
3232
guard let lookupHandler else { return }
3333

34-
let addressModels: [LookupAddressModel] = results.compactMap { $0 as? NSDictionary }.compactMap { try? $0.decode() }
34+
let addressModels: [LookupAddressModel] = results
35+
.compactMap { $0 as? NSDictionary }
36+
.compactMap { try? $0.decode() }
3537
DispatchQueue.main.async {
3638
lookupHandler(addressModels)
3739
}
@@ -136,7 +138,9 @@ internal final class DropInModule: BaseModule {
136138
}
137139

138140
extension DropInModule: DropInComponentDelegate {
139-
func didSubmit(_ data: Adyen.PaymentComponentData, from component: Adyen.PaymentComponent, in dropInComponent: Adyen.AnyDropInComponent) {
141+
func didSubmit(_ data: Adyen.PaymentComponentData,
142+
from component: Adyen.PaymentComponent,
143+
in dropInComponent: Adyen.AnyDropInComponent) {
140144
let response: SubmitData
141145
if let appleData = data.paymentMethod as? ApplePayDetails {
142146
response = SubmitData(paymentData: data.jsonObject, extra: appleData.extraData)
@@ -146,24 +150,32 @@ extension DropInModule: DropInComponentDelegate {
146150
sendEvent(event: .didSubmit, body: response.jsonObject)
147151
}
148152

149-
func didFail(with error: Error, from component: Adyen.PaymentComponent, in dropInComponent: Adyen.AnyDropInComponent) {
153+
func didFail(with error: Error,
154+
from component: Adyen.PaymentComponent,
155+
in dropInComponent: Adyen.AnyDropInComponent) {
150156
sendEvent(error: error)
151157
}
152158

153-
func didProvide(_ data: Adyen.ActionComponentData, from component: Adyen.ActionComponent, in dropInComponent: Adyen.AnyDropInComponent) {
159+
func didProvide(_ data: Adyen.ActionComponentData,
160+
from component: Adyen.ActionComponent,
161+
in dropInComponent: Adyen.AnyDropInComponent) {
154162
sendEvent(event: .didProvide, body: data.jsonObject)
155163
}
156164

157-
func didComplete(from component: Adyen.ActionComponent, in dropInComponent: Adyen.AnyDropInComponent) {
165+
func didComplete(from component: Adyen.ActionComponent,
166+
in dropInComponent: Adyen.AnyDropInComponent) {
158167
let result = ResultDTO(result: .presentToShopper)
159168
sendEvent(event: .didComplete, body: result.jsonObject)
160169
}
161170

162-
func didFail(with error: Error, from component: Adyen.ActionComponent, in dropInComponent: Adyen.AnyDropInComponent) {
171+
func didFail(with error: Error,
172+
from component: Adyen.ActionComponent,
173+
in dropInComponent: Adyen.AnyDropInComponent) {
163174
sendEvent(error: error)
164175
}
165176

166-
func didFail(with error: Error, from dropInComponent: Adyen.AnyDropInComponent) {
177+
func didFail(with error: Error,
178+
from dropInComponent: Adyen.AnyDropInComponent) {
167179
sendEvent(error: error)
168180
}
169181
}
@@ -175,15 +187,17 @@ extension DropInModule: AddressLookupProvider {
175187
sendEvent(event: .didUpdateAddress, body: searchTerm)
176188
}
177189

178-
func complete(incompleteAddress: LookupAddressModel, resultHandler: @escaping (Result<PostalAddress, any Error>) -> Void) {
190+
func complete(incompleteAddress: LookupAddressModel,
191+
resultHandler: @escaping (Result<PostalAddress, any Error>) -> Void) {
179192
lookupCompliationHandler = resultHandler
180193
sendEvent(event: .didConfirmAddress, body: incompleteAddress.jsonObject)
181194
}
182195

183196
}
184197

185198
extension DropInModule: StoredPaymentMethodsDelegate {
186-
func disable(storedPaymentMethod: any Adyen.StoredPaymentMethod, completion: @escaping Adyen.Completion<Bool>) {
199+
func disable(storedPaymentMethod: any Adyen.StoredPaymentMethod,
200+
completion: @escaping Adyen.Completion<Bool>) {
187201
disableStoredPaymentMethodHandler = completion
188202
sendEvent(event: .didDisableStoredPaymentMethod, body: storedPaymentMethod.jsonObject)
189203
}
@@ -204,7 +218,9 @@ struct AddressError: Error, LocalizedError, Codable {
204218

205219
extension DropInModule: PartialPaymentDelegate {
206220

207-
func checkBalance(with data: PaymentComponentData, component: any Adyen.Component, completion: @escaping (Result<Balance, any Error>) -> Void) {
221+
func checkBalance(with data: PaymentComponentData,
222+
component: any Adyen.Component,
223+
completion: @escaping (Result<Balance, any Error>) -> Void) {
208224
sendEvent(event: .didCheckBalance, body: data.jsonObject)
209225
checkBalanceHandler = completion
210226
}
@@ -222,7 +238,8 @@ extension DropInModule: PartialPaymentDelegate {
222238
}
223239
}
224240

225-
func requestOrder(for component: any Adyen.Component, completion: @escaping (Result<PartialPaymentOrder, any Error>) -> Void) {
241+
func requestOrder(for component: any Adyen.Component,
242+
completion: @escaping (Result<PartialPaymentOrder, any Error>) -> Void) {
226243
sendEvent(event: .didRequestOrder)
227244
requestOrderHandler = completion
228245
}
@@ -270,11 +287,11 @@ extension DropInModule: CardComponentDelegate {
270287
func didSubmit(lastFour: String, finalBIN: String, component: Adyen.CardComponent) {
271288
/* No Callback implemented */
272289
}
273-
290+
274291
func didChangeBIN(_ value: String, component: Adyen.CardComponent) {
275292
sendEvent(event: .didChangeBinValue, body: value)
276293
}
277-
294+
278295
func didChangeCardBrand(_ value: [Adyen.CardBrand]?, component: Adyen.CardComponent) {
279296
guard let value, !value.isEmpty else { return }
280297
let jsonData = value.map { BinLookupDataDTO(brand: $0.type.rawValue).jsonObject }

0 commit comments

Comments
 (0)