Eventos in-app para aplicaciones híbridas

De un vistazo: Atribuye los eventos in-app de los usuarios que tienen tu aplicación instalada, pero realiza un evento en tu sitio web móvil, y no en la aplicación.

Introducción

Los eventos in-app que ocurren dentro de la aplicación se reportan mediante el SDK. ¿Qué pasa con los eventos que ocurren fuera de la aplicación?

Hay algunos escenarios en los que ocurren eventos fuera del contexto de la aplicación:

  • Eventos que tienen lugar en tu sitio web: implementa la atribución basada en personas (PBA) para obtener una vista unificada de las trayectorias del cliente en todos los canales, plataformas, incluidos el sitio web y los dispositivos. Esto te proporciona análisis de rutas de conversión de la web a la aplicación y raw data.
  • Servidores backend: los eventos ocurren independientemente de la acción del usuario en el sitio web o la aplicación. Por ejemplo, renovación automática de suscripción.
  • Híbrido: el evento se lleva a cabo en tu sitio web móvil en un dispositivo que tiene la aplicación como se describe en este artículo. Los eventos in-app se atribuyen llamando a la API del SDK de AppsFlyer usando Javascript.

Esta guía se refiere al escenario híbrido. Aprende a cerrar la brecha entre la vista HTML y las vistas nativas, lo que te permite atribuir eventos en la vista HTML y enviarlos a la aplicación. 

 Ejemplo

Tienes una aplicación híbrida que ofrece suscripciones. Implementa el formulario de suscripción en una vista web que realmente se carga desde tu sitio web.

Puedes atribuir el evento in-app de suscripción en la vista web y enviar datos relacionados con él, como el tipo de suscripción o el precio, al código nativo.

El código nativo recopila los datos y utiliza el SDK de AppsFlyer para enviar el evento in-app de suscripción.

Registro de eventos in-app en aplicaciones híbridas

En esta guía proporcionamos dos métodos para registrar eventos in-app en aplicaciones híbridas:

  • [Recomendado] Interfaz JavaScript: utiliza la interfaz JavaScript nativa para establecer la comunicación entre la vista HTML o web y el código nativo. De esta manera, puedes enviar datos relacionados con eventos in-app desde la vista web al código nativo. Una vez que el código nativo obtiene los datos, los envía a AppsFlyer usando el SDK.
  • Carga de URL: en este método, el código nativo escucha los eventos de carga de URL. Puedes establecer el código nativo para escuchar los eventos de carga de URL específicas y extraer datos de los parámetros de URL. Los datos se transfieren al SDK.

Interfaz JavaScript

Tanto Android como iOS tienen interfaces Javascript nativas que permiten que las vistas web llamen a código nativo.

Ventajas de usar la interfaz JavaScript nativa frente a la carga de URL:

  • No requiere la implementación de lógica que escuche la carga de URL.
  • Las interfaces nativas son preferibles a otras implementaciones.
  • No es necesario analizar los parámetros de la URL.
  • Hay menos código y, por lo tanto, se requiere menos mantenimiento.

La implementación consta de los siguientes pasos:

  1. Código HTML para vista web o página web
  2. Implementación de código nativo para vista web

Android

Código HTML para Android

Agrega el siguiente código HTML a la vista web o página web:

<h1>Recording Event From Web View</h1>
<div id="main">
 <button id="recordEvent" onclick="recordEvent()"> Record Event </button>
</div>
<script type="text/javascript">
 function recordEvent(){
 var eventName = "af_purchase"
 var eventParams = "{\"af_revenue\":\"6.72\", \"af_content_type\": \"wallets\", \"af_content_id\": \"15854\"}";
 app.recordEvent(eventName, eventParams)
}
</script>

Cuando pases el valor del evento, ten presente lo siguiente:

  • Asegúrate de pasar el valor del evento como un JSON en formato de secuencia.
    "{\"af_revenue\":\"6.72\", \"af_content_type\": \"wallets\", \"af_content_id\": \"15854\"}"
  • Para evitar posibles problemas, AppsFlyer recomienda usar únicamente caracteres alfanuméricos en minúsculas (a-z y 0-9) para tus nombres de eventos in-app. 

Clase WebActivity

Crea una clase de actividad web con el siguiente código:

public class WebActivity extends AppCompatActivity {
 WebView web;

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_web);
  web = (WebView) findViewById(R.id.webView);
  web.getSettings().setJavaScriptEnabled(true);
  web.addJavascriptInterface(new MainJsInterface(getApplicationContext()), "app");
  web.loadUrl("https://yourwebsite.com");
 }
}

El código anterior crea un objeto llamado app que actúa como puente entre la vista web y el código nativo.

Clase de interfaz JavaScript

Crea una clase MainJsInterface para implementar recordEvent() como JavascriptInterface

public class MainJsInterface {
 Context mContext;

 MainJsInterface(Context c) {
  mContext = c;
 }

 @JavascriptInterface
 public void recordEvent(String name, String json){
  Map<String, Object> params = null;
  if(json!=null) {
   try {
    JSONObject jsonObject = new JSONObject(json);
    params = new HashMap<>();
    Iterator keys = jsonObject.keys();
    while (keys.hasNext()) {
     String key = keys.next();
     Object value = jsonObject.opt(key);
     params.put(key, value);
    }
   } catch (JSONException e) {
    e.printStackTrace();
   }
  }
  AppsFlyerLib.getInstance().logEvent(this.mContext, name, params);
 }
}

El código anterior declara un método recordEvent al que se puede llamar en la vista web con Javascript.

En el código HTML, puedes ver que el método se llama utilizando app.recordEvent(eventName, eventParams). Recuerda que hemos configurado la aplicación para que actúe como puente entre la vista web y el código nativo. Esta es la razón por la que la aplicación puede llamar al recordEvent que definimos en la clase MainJsInterface.

iOS

Código HTML para iOS

Agrega el siguiente código HTML a la vista web o página web:

<body>
 <h1>Recroding Event From Web View</h1>
 <div id="main">
  <button id="recordEvent" onclick="recordEvent()"> Record Event </button>
 </div>
 <script type="text/javascript">
 function recordEvent(){
  var eventName = "af_purchase"
  var eventParams = "{\"af_revenue\":\"6.72\", \"af_content_type\": \"wallets\", \"af_content_id\": \"15854\"}";
  webkit.messageHandlers.event.postMessage(eventName + "+" + eventParams);
 }
 </script>
</body>

El código anterior establece una función que se activará cuando se haga clic en un botón. La función configura las variables eventName y eventParams y las pasa al código nativo usando webkit.messageHandlers.

Cuando pases el valor del evento, ten presente lo siguiente:

  • Asegúrate de pasar el valor del evento como un JSON en formato de secuencia.
    "{\"af_revenue\":\"6.72\", \"af_content_type\": \"wallets\", \"af_content_id\": \"15854\"}"
  • Para evitar posibles problemas, AppsFlyer recomienda usar únicamente caracteres alfanuméricos en minúsculas (a-z y 0-9) para tus nombres de eventos in-app. 

 Nota

El código HTML es tanto para Objective-C como para Swift.

Objective C

Controlador de vista web

En tu controlador de vista web, agrega el siguiente código en el controlador de vista.

-(void)loadView{
 [super loadView];

 WKWebViewConfiguration *configuration =
 [[WKWebViewConfiguration alloc] init];
 [configuration.userContentController
 addScriptMessageHandler:self name:@"event"];

 _webView = [[WKWebView alloc] initWithFrame:self.view.frame
         configuration:configuration];
 [self.view addSubview:_webView];
}

- (void)viewDidLoad {

 [super viewDidLoad];

 NSString* page = @"https://yourwebsite.com";

 NSURL *url = [NSURL URLWithString:page];
 NSURLRequest *request = [NSURLRequest requestWithURL:url];

 [_webView loadRequest:request];

 }

- (void)userContentController:(WKUserContentController *)userContentController
  didReceiveScriptMessage:(WKScriptMessage *)message {

 NSString* messageBody = message.body;
 NSString* eventName = [messageBody componentsSeparatedByString:@"+"][0];
 NSString* eventValue = [messageBody componentsSeparatedByString:@"+"][1];
 [self recordEvent:eventName eventValue:eventValue];
}

- (void)recordEvent:(NSString*)eventName eventValue:(NSString*)eventValue{

 NSData *eventValuedata = [eventValue dataUsingEncoding:(NSUTF8StringEncoding)];

 NSDictionary *eventValueDict = [NSJSONSerialization JSONObjectWithData:eventValuedata options:NSJSONReadingMutableContainers error:nil];

 [[AppsFlyerLib shared] logEvent:eventName withValues:eventValueDict];

}

El código anterior recibe el mensaje de la vista web. El mensaje contiene el nombre y el valor del evento. Cuando el código detecta el mensaje entrante, lo pasa al método recordEvent que analiza los valores y llama al método logEvent del SDK nativo.

Controlador Swift WebView

En el controlador de vista web, agrega el siguiente código en el método viewDidLoad.

import WebKit
import UIKit
import AppsFlyerLib
import JavaScriptCore

class JSViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler {
 func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
  let messageBody = message.body as? String
  let eventName = messageBody?.components(separatedBy: "+")[0]
  let eventValue = messageBody?.components(separatedBy: "+")[1]
  recordEvent(eventName: eventName!, eventValue: eventValue!)
 }

 var webView: WKWebView!
 override func loadView(){
  webView = WKWebView()
  webView.navigationDelegate = self
  view = webView
 }

 override func viewDidLoad() {
  super.viewDidLoad()
  let url = URL(string: "https://yourwebsite.com")!
  webView.load(URLRequest(url: url))
  webView.configuration.userContentController.add(self, name:"event")
 }

 func recordEvent(eventName: String, eventValue: String) {

  var eventValueDict = [String: String]()

  let eventValuesData = eventValue.data(using: String.Encoding.utf8)
  do {
   eventValueDict = try (JSONSerialization.jsonObject(with: eventValuesData!, options:[]) as? [String: String])!
  } catch let error as NSError{
   print(error)
  }

  AppsFlyerLib.shared().logEvent(eventName as String?, withValues: eventValueDict)
 }

}

El código anterior recibe el mensaje de la vista web. El mensaje contiene el nombre y el valor del evento. Cuando el código detecta el mensaje entrante, lo pasa al recordEvent que analiza los valores y llama al método logEvent del SDK de AppsFlyer.

Carga de URL

Tanto Android como iOS implementan un método nativo que escucha los eventos de carga de URL. Este método te permite hacer lo siguiente:

  • Escuchar un evento de carga de una URL específica
  • Extraer parámetros que se anexan a la URL
  • Usar estos parámetros en el código nativo

La implementación a continuación consta de dos pasos:

  1. Código HTML para vista web o página web
  2. Implementación de código nativo para la carga de URL

Implementación de WebView

Código HTML (tanto para Android WebView como para iOS WKWebView)

<html>
<head>
</head>
 <body>
  <h1>Recording From Web View</h1>
  <div id="main">
   <input id="button" type="button" value="Record Event" />
  </div>
  <script type="text/javascript">
  function recordEvent(eventName,eventValue){
   var iframe = document.createElement("IFRAME");
   iframe.setAttribute("src", "af-event://inappevent?eventName="+eventName+"&eventValue="+eventValue);
   document.documentElement.appendChild(iframe);
   iframe.parentNode.removeChild(iframe);
   iframe = null;
  }
  var button = document.getElementById("button");
  button.onclick = function(event) {
   var eventName = "af_purchase";
   var eventValue = "{\"af_revenue\":\"6.72\", \"af_content_type\": \"wallets\", \"af_content_id\": \"15854\"}";
   recordEvent(eventName, eventValue);
  }
  </script>
 </body>
</html>

El código anterior puede ser parte de una página web real o cargada de forma nativa en la vista web.

El código anterior establece una función que se activará cuando se haga clic en un botón. La función en sí crea un elemento iframe que carga una URL personalizada. Es esta carga de URL la que activa el método nativo de Android o iOS que luego llama al método logEvent.

Todos los parámetros requeridos (nombre del evento y valores del evento) se agregan a la URL. Los ejemplos de código de Android e iOS a continuación demuestran cómo extraer estos parámetros y pasarlos al método logEvent del SDK de AppsFlyer.

Cuando pases el valor del evento, ten presente lo siguiente:

  • Asegúrate de pasar el valor del evento como un JSON en formato de secuencia.
    "{\"af_revenue\":\"6.72\", \"af_content_type\": \"wallets\", \"af_content_id\": \"15854\"}"
  • Para evitar posibles problemas, AppsFlyer recomienda usar únicamente caracteres alfanuméricos en minúsculas (a-z y 0-9) para tus nombres de eventos in-app. 

Implementación nativa

Android iOS

Implementación de Android

Android WebView utiliza un WebViewClient que recibe notificaciones de la vista web. En shouldOverrideUrlLoading, puedes manejar los eventos de carga de URL que proceden de la vista web:

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
	if (url.startsWith("af-event://")) {
		String[] urlParts = url.split("\\?");
		if (urlParts.length > 1) {
			String query = urlParts[1];
			String eventName = null;
			HashMap<String, Object> eventValue = new HashMap<>();

			for (String param : query.split("&")) {
				String[] pair = param.split("=");
				String key = pair[0];
				if (pair.length > 1) {
					if ("eventName".equals(key)){
						eventName = pair[1];
					} else if ("eventValue".equals(key)){
						JSONObject event;
						JSONArray keys;
						try {
							event = new JSONObject(pair[1]);
							keys = event.names();
							for (int i = 0; i < keys.length(); i++){
								eventValue.put(keys.getString(i), event.getString(keys.getString(i)));
							}
						} catch (JSONException e) {
							e.printStackTrace();
						}
					}
				}
			}
			AppsFlyerLib.getInstance().logEvent(getApplicationContext(),eventName,eventValue);
		}
		return true;
	}
	view.loadUrl(url);
	return true;

}