Para la gran mayoría de desarrollos y aplicaciones, los distintos SDKs cubren completamente las necesidades de analítica y comunicación dentro de la app, ya que se ejecuta directamente en el entorno móvil y ofrece todas las capacidades de EMMA sin depender de elementos externos.
Sin embargo, muchas aplicaciones modernas no son 100% nativas. En ocasiones incluyen:
Pantallas híbridas desarrolladas en web.
Landings promocionales cargadas dinámicamente.
Formularios embebidos en WebViews.
Contenidos reutilizados desde la versión web del producto.
En estos casos, parte de la experiencia del usuario ocurre dentro de un WebView, y estos contenidos web también necesitan enviar eventos a EMMA para mantener una trazabilidad completa del comportamiento del usuario dentro de la app.
Las compañias que ofrecen trazabilidad entre web y cookies . Las cookies cada vez van perdiendo perdiendo relevacia a medida que la privacidad de los usuarios empieza a ser el foco principal en el sector del marketing. EMMA desarrolla todas sus soluciones de tracking basadas en "cookieless", forma parte de la filosofía de la compañia.
La comunicación Web ↔ Nativo no funciona igual en Android y en iOS:
Android WebView permite exponer métodos nativos directamente al JavaScript mediante addJavascriptInterface, lo que ofrece gran flexibilidad al definir tanto el nombre de la interfaz como el método a invocar desde JS.
iOS WKWebView, por motivos de seguridad, no permite exponer funciones nativas directamente. Toda comunicación desde la web debe hacerse a través de postMessage(), enviando mensajes a un WKScriptMessageHandler en Swift.
Esto significa que, aunque la intención es la misma, enviar un evento desde el WebView hacia la app, los mecanismos técnicos en cada plataforma son completamente distintos.
Para evitar que los desarrolladores tengan que preocuparse por estas diferencias, EMMA proporciona una capa de abstracción en JavaScript que unifica el proceso.
Esta capa detecta automáticamente en qué plataforma está ejecutándose el contenido web y reenvía el evento utilizando la técnica adecuada:
En Android → mediante la interfaz registrada con addJavascriptInterface
En iOS → mediante postMessage hacia el WKScriptMessageHandler
En la web → uso del web SDK llamando al método sendEventToApp para poder enviar el evento a los anteriores sistemas operativos.
Para recibir eventos en Android primero hay que habilitar el entorno de webview donde se van a recibir eventos:
class EmmaBridge {
@JavascriptInterface
fun onEmmaEvent(json: String) {
try {
val jsonObj = JSONObject(json)
val token = jsonObj.getString("token")
val attributesJson = jsonObj.optJSONObject("attributes")
val attributes = attributesJson?.let { json ->
json.keys().asSequence().associateWith { key -> json.get(key) }
} ?: emptyMap()
// Se construye el request de EMMA
val eventRequest = EMMAEventRequest(token)
eventRequest.attributes = attributes
// Se envía el evento al SDK de EMMA
EMMA.getInstance().trackEvent(eventRequest)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
El importante la JS Interface tenga como método onEmmaEvent(json: String).
Una vez esté creado el EMMABridge activamos el uso de JS en el WebView y declaramos el bridge:
val webView = findViewById<WebView>(R.id.webview)
webView.settings.javaScriptEnabled = true
webView.addJavascriptInterface(EmmaBridge(), "EmmaBridge")
webView.loadUrl("https://landing-url.com")
Para recibir eventos en iOS hay que añadir el WKUserContentController a la configuración del WKWeView:
import UIKit
import WebKit
class ViewController: UIViewController, WKScriptMessageHandler {
var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
let contentController = WKUserContentController()
contentController.add(self, name: "EmmaBridge")
let config = WKWebViewConfiguration()
config.userContentController = contentController
webView = WKWebView(frame: .zero, configuration: config)
view = webView
// Cargar una URL remota usando load(URLRequest)
if let url = URL(string: "https://landing-url.com") {
let request = URLRequest(url: url)
webView.load(request)
}
}
// Recibir JSON desde el WebView
func userContentController(_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage) {
guard message.name == "EmmaBridge",
let jsonString = message.body as? String else {
return
}
do {
// Convertimos el string JSON a diccionario
guard let data = jsonString.data(using: .utf8),
let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] else { return }
let token = json["token"] as? String ?? ""
let attributes = json["attributes"] as? [String: Any] ?? [:]
// Montamos la request de EMMA
let eventRequest = EMMAEventRequest.init(token: token)
eventRequest?.attributes = attributes
EMMA.trackEvent(eventRequest)
} catch {
print("Error parseando JSON:", error)
}
}
}
Descargar el SDK de aquí y añadirlo a vuestro CDN:
https://gist.github.com/adriancarrera31/bda66419f139ba4c02779a9466504c3a
Dentro del entorno web usado en el WebView, cuando se produzca cualquier acción es necesario llamar al método EMMA.WebView.sendEventToApp():
const eventData = {
token: "click:bizum",
attributes : {
amount: 35
}
}
EMMA.WebView.sendEventToApp(eventData)
Este método hace comprobaciones internas para saber si el evento se está ejecutando en entorno de WebView o en cualquier otro entorno. En caso de que no se ejecute fuera del entorno de WebView el método no registra el evento, si el evento está dentro del entorno WebView se comunicará con el bridge añadido en Android e iOS para el envio del evento.