Die folgende Dokumentation erklärt, was sich zwischen v1.0.0 und v2.0.0 des iOS SDK geändert hat und was bei der Migration auf die neueste Version zu beachten ist.
Änderungen in Version 2.0.0
Wir haben die Parameter aktualisiert, die bei Zahlungsabschluss zurückgegeben werden. Dies beinhaltet nun:
- Liste der Antworten auf die Anfrage.
- Das Feld threedresponse (falls vorhanden).
- Alle aufgetretenen Fehler.
Was kann threedresponse verwendet werden?
In v1.0.0 konnten Sie das zurückgegebene Objekt-Array (responseObjects) in transactionSuccessClosure, und finden Sie das Antwortobjekt aus der Anfrage THREEDQUERY .
(Beispiel)
let threeDQueryResponse = responseObjects.filter({ $0.requestTypeDescription(contains: TypeDescription.threeDQuery) }).first
Dann könnten Sie die Felder (threeDQueryResponse.threeDResponse oder threeDQueryResponse.pares), die in diesem Objekt gespeichert sind, um die payload für die AUTH Anfrage zu generieren.
In Version 2.0.0 wird die threedresponse Objekt erstellt wurde (das die Autorisierungsparameter enthält), das direkt in transactionResponseClosure.
Sie können die Felder (threedresponse.threeDResponse oder threedresponse.pares), die in diesem Objekt gespeichert sind, um die payload für die AUTH Anfrage zu generieren.
transactionResponseClosure
In v1.0.0, als Teil der transactionSuccessClosure und transactionErrorClosure, haben wir ein geparstes Transaktionsantwortobjekt zurückgegeben.
In v2.0.0 haben wir jedoch nur eine transactionResponseClosure, weil wir unseren Händlern mehr Kontrolle darüber geben wollten, wie sie die Antwort interpretieren. Wie im Beispiel unten gezeigt:
transactionResponseClosure: {
(
responseJwtList: [String],
threeDResponse: ThreeDResponse?,
error: APIClientError?
)
in}
transactionSuccessClosure: {
(
// JWT from the last response returned for verification
jwt: String,
// parsed response objects from JWT
responses: [JWTResponseObject],
cardReference: TPCardReference?
)
in},
transactionErrorClosure: {
(
jwt: String?,
responses: [JWTResponseObject]?,
errorMessage: String,
// error indicating that there was a general error in connecting to the server or in 3dsecure authentication, or an error object constructed from the errorcode property
error: APIClientError?
)
in}
Beispielszenario
In v1.0.0 wurde bei einer Anfrage von "THREEDQUERY","AUTH","SUBSCRIPTION", bei der THREEDQUERY und AUTH erfolgreich waren, aber bei SUBSCRIPTION ein Fehler auftrat, vom SDK eine transactionErrorClosure, obwohl die THREEDQUERY und AUTH erfolgreich bearbeitet wurden. Die Anzeige einer Fehlermeldung für den Kunden kann in diesem speziellen Szenario irreführend sein, da Gelder auf seinem Bankkonto reserviert wurden.
Um die Gefahr zu verringern, dass der Kunde falsch über das Ergebnis der Zahlungstransaktion informiert wird, unterscheiden wir in Version 2.0.0 nicht mehr zwischen Erfolg und Misserfolg, sondern geben nur noch die vollständige Liste der Ergebnisse zurück, die Sie zunächst überprüfen, analysieren und dann die errorcode in jeder der Antworten zurück.
In Bezug auf das obige Szenario könnten Sie Ihr System so konfigurieren, dass es die Antworten THREEDQUERY und AUTH als Erfolg behandelt und die entsprechende Antwortmeldung im Browser des Kunden anzeigt (um anzuzeigen, dass Mittel für die Zahlung reserviert wurden), aber auch eine Fehlermeldung anzeigt, um den Kunden darüber zu informieren, dass die automatischen Abonnementzahlungen aufgrund eines Fehlers noch nicht geplant werden konnten und dass dem Kunden empfohlen wird, sich mit Ihnen in Verbindung zu setzen.
Bevor die Informationen im Antwortobjekt vertrauenswürdig sind, müssen Sie die Signatur jeder JWT-Antwort überprüfen.
Wir stellen ein Parsing-Dienstprogramm zur Verfügung, um die Daten des Feldes payload als Teil der Überprüfung der Zahlungsantwortfelder zu extrahieren:
transactionResponseClosure: { [unowned self] responseJwtList, threeDResponse, error in
// Every JWT returned from the SDK should be verified before further usage.
let isVerified = !responseJwtList.map { JWTHelper.verifyJwt(jwt: $0, secret: self.appFoundation.keys.jwtSecretKey) }.contains(false)
AppLog.log("JWT verification status: \(isVerified)")
if !isVerified {
// throw error and show the appropriate message
return
}
// error indicating that there was a general error in connecting to the server or in 3dsecure authentication (APIClientError enum)
guard let error = error else {
// a parsing utility
guard let tpResponses = try? TPHelper.getTPResponses(jwt: responseJwtList) else { return }
// an example of how to get a card reference object which in version 1.0.0 was part of the closure (TPCardReference object)
let cardReference = tpResponses.last?.cardReference
// an example of how to get the JWTResponseObject array which in version 1.0.0 was part of the closure
let responseObjects = tpResponses.flatMap { $0.responseObjects }
// an example of how to find a response object that interests us
let riskDecResponse = tpResponses.compactMap { $0.responseObjects.first(where: { $0.requestTypeDescription(contains: TypeDescription.riskDec) }) }.first
// the error object constructed from the errorcode property (in version 1.0.0 it was part of the APIClientError class, in version 2.0.0 the TPError class was created)
guard let firstTPError = tpResponses.compactMap({ $0.tpError }).first else {
self.showAlert(controller: self.navigationController, message: LocalizableKeys.DropInViewController.successfulPayment.localizedStringOrEmpty) { _ in
self.navigationController.popViewController(animated: true)
}
return
}
if case TPError.invalidField(let errorCode, let localizedError) = firstTPError {
AppLog.log("RESPONSEVALIDATIONERROR.INVALIDFIELD: code: \(errorCode.rawValue), message: \(localizedError ?? errorCode.message)")
}
if case TPError.gatewayError(let errorCode, let error) = firstTPError {
AppLog.log("GATEWAYERROR: responseErrorCode: \(errorCode.rawValue)), errorCode: \((error as NSError).code) message: \(error.localizedDescription)")
}
self.showAlert(controller: self.navigationController, message: firstTPError.humanReadableDescription) { _ in }
return
}
self.showAlert(controller: self.navigationController, message: error.humanReadableDescription) { _ in }
}