Manejo de eventos con postMessage
Función postMessage en JavaScript
*postMessage
es una función de JavaScript crucial para la comunicación segura entre iFrames y ventanas en aplicaciones web. Es especialmente importante en el contexto de pagos online, donde proteger los datos de los usuarios es esencial. Esta función nos permite intercambiar información de forma segura entre el sistema de pago y la página del comercio, garantizando que los datos sensibles, como la información de tarjetas de crédito, se manejen con la máxima seguridad. Utilizamos postMessage
** para enviar eventos estandarizados que informan sobre el progreso de las transacciones, mejorando la experiencia del usuario y asegurando transacciones seguras.*
En la siguiente sección, encontrarás detalles sobre estos eventos, ejemplos de implementación y recomendaciones sobre cómo actuar tras recibir y procesar estos eventos, facilitando una integración fluida en tu sistema de pagos.
Tabla de eventos
Evento | Meta-Payload | Descripción | Como reproducir en el ambiente de pruebas? |
---|---|---|---|
VaultStarted | Se emite cuando el widget haya cargado y el usuario ahora pueda interactuar dentro de los elementos de la página. | N/A | |
VaultSaveSuccess | createdCard: bankName (string), cardId (string), company (string), firstSix (string), lastFour (string), userId (string), storedCard (boolean, sera true si la tarjeta fue seleccionada de las tarjetas guardadas de usuario, de lo contrario es false si es nueva) | Emitido cuando se completa con éxito la creación de una tarjeta en DEUNA. | N/A |
VaultSaveError | errorMessage, errorCode | Se dispara cuando ocurre un error en la creación de la tarjeta. | Usar la tarjeta: 1354 1001 4004 955 |
VaultFailed | errorCode, errorMessage | Para errores generales durante la carga. | Al momento de cargar la URL de elements. Cambiar la public key por una valor random. |
VaultProcessing | N/A | Emitir cuando el usuario haga clic en el botón de acción y mientras la API de DEUNA responda. | N/A |
onBinDetected | Aquí se proporciona como metadata: BIN de la tarjeta (card_bin) Marca de la tarjeta (card_brand) Estos datos se enviarán únicamente si se ingresa el BIN. En caso de que el sistema detecte la introducción del BIN y posteriormente se borre, no se enviará metadata, para informar al comercio que no lo envíe en la transacción. | Emitido al reconocer algún cambio en el ingreso del BIN. | N/A |
onInstallmentSelected | parsedData.data?.metadata?.plan_option_id : dicho ID contiene la opción seleccionada de installment que se debe mandar en el /purchase API) | Se emite este evento cuando el usuario seleccionó alguna opción del dropdown de installments | N/A |
vaultSaveClick | N/A | Se emite cuando el usuario le hace click al botón de continuar/pagar. | N/A |
paymentMethodsCardNumberEntered | N/A | Se emite cuando el usuario termina de agregar todos los dígitos de la tarjeta. | |
paymentMethodsCardNumberInitiated | N/A | Se emite cuando el usuario selecciona el campo de número de tarjeta. | |
paymentMethodsCardExpirationDateInitiated | N/A | Se emite cuando el usuario selecciona el campo de fecha de expiración. | |
paymentMethodsCardExpirationDateEntered | N/A | Se emite cuando el usuario termina de agregar la fecha de expiración. | |
paymentMethodsCardSecurityCodeInitiated | N/A | Se emite cuando el usuario selecciona el campo de CVV. | |
paymentMethodsCardSecurityCodeEntered | N/A | Se emite cuando el usuario termina de agregar el CVV. | |
paymentMethodsCardNameInitiated | N/A | Se emite cuando el usuario selecciona el campo de nombre del tarjetahabiente. | |
paymentMethodsCardNameEntered | N/A | Se emite cuando se cumple con que el usuario agrega al menos dos palabras separadas por un espacio (sin caracteres especiales ni números) |
Orden de los eventos
TBD
Ejemplo de código para escuchar los postMessage (Web)
window.addEventListener("message", (event) => {
// Verificar el origen del mensaje para garantizar seguridad
if (event.origin !== "URL_DE_CONFIANZA") {
return;
}
// Procesar el evento recibido
switch (event.data.type) {
case 'VaultStarted':
console.log("VaultStarted: Click to Pay está listo para la interacción.");
// Implementar acciones cuando el proceso de pago ha iniciado
break;
case 'VaultSaveSuccess':
const cardId = event.data.metadata.createdCard.id;
console.log(`VaultSaveSuccess: Tarjeta guardada con éxito. ID de la tarjeta: ${cardId}`);
// Manejar el éxito en la creación de la tarjeta y proceder con el proceso de pago
break;
case 'VaultSaveError':
case 'VaultFailed':
const errorCode = event.data.metadata.errorCode;
const errorMessage = event.data.metadata.errorMessage;
console.error(`${event.data.type}: Error en el proceso. Código: ${errorCode}, Mensaje: ${errorMessage}`);
// Manejar errores en el guardado de la tarjeta o errores generales
break;
case 'VaultProcessing':
console.log("VaultProcessing: Procesando pago con DEUNA.");
// Implementar acciones mientras se procesa la transacción
break;
case 'onBinDetected':
// Cuando el usuario ingresa los primeros 6 dígitos de la tarjeta
const cardBrand = event.data?.metadata?.cardBrand;
case 'onInstallmentSelected':
// Cuando el usuario selecciona las cantidad de cuotas
const planOptionId = event.data.metadata.plan_option_id;
case 'onBinEmpty':
// Cuando el usuario limpia el BIN
default:
console.warn(`Evento no reconocido: ${event.data.type}`);
// Manejar cualquier otro caso no especificado
break;
}
});
Ejemplo de código para escuchar los postMessage (iOS - Swift)
// Step 1: Implement the following delegates: WKNavigationDelegate, WKUIDelegate
// Step 2: Define the webView and override the window.open behaviour
let configuration = WKWebViewConfiguration()
private var webView: WKWebView?
var scriptSource = """
window.open = function(open) {
return function(url, name, features) {
location.href = url; // or window.location.replace(url)
};
}(window.open);
"""
// Step 3: Initialize the webView
/// Loads the web view with the specified URL.
/// Parameter urlString: The URL string to load.
func loadUrl(urlString: String) {
let userScript = WKUserScript(
source: scriptSource,
injectionTime: .atDocumentStart,
forMainFrameOnly: false
)
self.configuration.preferences.javaScriptEnabled = true
self.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
self.configuration.userContentController.addUserScript(userScript)
self.configuration.userContentController.add(self, name: "deuna") // IMPORTANT the name "deuna"
self.webView = WKWebView(
frame: view.bounds,
configuration: self.configuration
)
self.webView!.navigationDelegate = self
if let url = URL(string: urlString) {
let request = URLRequest(url: url)
self.webView?.load(request)
}
}
// Step 4: Define the function to listen when the URL of the widget
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
view.addSubview(webView)
self.adjustScrolling(webView: webView)
}
// Listen to the PostMessages
// Gets the data from the script message as Foundation Data.
// - Parameter message: The script message.
// - Returns: The data from the script message, if available.
func getMessageData(message: WKScriptMessage) -> Foundation.Data? {
guard let jsonString = message.body as? String else {
return nil
}
return jsonString.data(using: .utf8)
}
/// Handler for receiving JavaScript messages.
///
/// - Parameters:
/// - userContentController: The user content controller.
/// - message: The message received.
func userContentController(
_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage
) {
// Attempt to decode the received JSON message
guard let jsonData = getMessageData(message: message) else {
return
}
do {
// Decode the JSON message
let decoder = JSONDecoder()
// listen the post message data
} catch {
}
}
Ejemplo de código para escuchar los postMessage (Android - Kotlin)
// Step 1: Create and show the WebView
lateinit var webView: WebView
private fun initialize() {
webView = findViewById(R.id.deuna_webview)
}
// Step 2: Enable JS and pass over the interface to listen the postMessages and show the URL
// Load the URL in the WebView
@SuppressLint("SetJavaScriptEnabled")
fun loadUrl(url: String) {
webView.settings.apply {
domStorageEnabled = true
javaScriptEnabled = true
setSupportMultipleWindows(true) // Enable support for multiple windows
}
// Add JavascriptInterface
webView.addJavascriptInterface(WebViewBridge(), "android") // IMPORTANT the name "android"
webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
// When the page finishes loading, the Web View is shown and the loader is hidden
}
}
webView.loadUrl(url)
}
// Step 3: To create a class with a postMessage function using the @javascriptInterface annotation and listen for post message events
// Class to handle communication between the WebView and the native Android code
class WebViewBridge {
/**
* The postMessage function is called when a message is received from JavaScript code in a WebView.
* The message is parsed and the corresponding callbacks are called based on the event type.
*/
@JavascriptInterface
fun postMessage(message: String) {
try {
val json = JSONObject(message)
// listen the post message events
} catch (e: Exception) {
Log.d("WebViewBridge", "postMessage: $e")
}
}
abstract fun handleEvent(message: String)
}
Acciones post-captura de evento
Tras la captura de un evento, es crucial que el comercio inicie un proceso en su backend para realizar una llamada al endpoint para procesar el pago de nuestro servicio. Esto garantiza la finalización efectiva de la transacción de pago, siguiendo nuestras directrices de seguridad y manejo de datos.
Updated 4 months ago