Añade al archivo /app/build.gradle el repositorio en el cual se encuentra EMMA.
repositories {
maven { url 'https://repo.emma.io/emma' }
}
Añade la dependencia en el mismo archivo build.gradle.
Si estás usando la nueva versión 8 del Android Gradle Plugin y tienes la opción de minifyEnabled a true es necesario que actualices el SDK a la versión 4.14.1 o superiores para evitar un posible crash con una de nuestras dependencias. Si no es posible la actualización modifica las reglas de Proguard en la sección de más abajo.
dependencies {
implementation 'io.emma:eMMaSDK:4.14.+'
}
Si usas proguard consulta la documentación sobre proguard.
Por último, compilar el proyecto con gradle.
Session Key
de EMMAEMMA Key
en la página de documentación de EMMAEl SDK contiene por defecto los siguientes permisos obligatorios. Estos permisos NO se tienen que añadir en el AndroidManifest.xml
de la aplicación, ya que es el mismo SDK quien los añade:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="com.google.android.gms.permission.AD_ID"/>
Si quieres habilitar la localización tienes que añadir los siguientes permisos al AndroidManifest.xml
de tu aplicación:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Si la aplicación se va a subir a AppGallery o va a ser ejecutada en dispositivos compatibles con HMS, es necesario añadir la conexión con Huawei y la librería para obtener un identificador único para el dispositivo.
En el build.gradle del projecto añade el plugin de Huawei.
buildscript {
repositories {
google()`
jcenter()
maven { url 'http://developer.huawei.com/repo/' }
}
dependencies {
classpath 'com.android.tools.build:gradle:7.4.1'
classpath 'com.huawei.agconnect:agcp:1.6.2.300'
}
}
allprojects {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
}
En el build.gradle de app, añade la siguiente dependencia y aplica el plugin para recoger la información de configuración de la app en Huawei.
dependencies {
// other dependencies
implementation 'com.huawei.hms:ads-identifier:3.4.62.300'
}
apply plugin: 'com.huawei.agconnect'
Para obtener las credenciales primero hay que crear una cuenta en developer.huawei.com y convertirse en desarrollador.
Una vez creada una cuenta hay que añadir una aplicación en Huawei AppGallery Connect. La app se crea en modo draft, para hacer la integración de push es su cliente.
Una vez creada la app ya podemos activar el Push Kit (esto es opcional solo si se requiere usar notificaciones push) en la sección develop. Dentro de Project Settings aparecerá la información referente a la app.
Es necesario añadir el fingerprint del certificado que se usa para la firma de la app.
Descargamos el agconnect-services.json y lo añadimos en /app. De esta forma el servicio de HMS podrá autenticar la app.
Añadimos el appId y appSecret en la sección de preferencias de la app en el dashboard de EMMA.
En tu clase Application, añade lo siguiente:
import android.app.Application
import io.emma.android.EMMA
class ExampleApplication : Application() {
override fun onCreate() {
super.onCreate()
val configuration = EMMA.Configuration.Builder(this)
.setSessionKey("example0ikl98")
.setDebugActive(BuildConfig.DEBUG)
.build()
EMMA.getInstance().startSession(configuration)
}
}
import android.app.Application;
import io.emma.android.EMMA;
public class ExampleApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
EMMA.Configuration configuration = new EMMA.Configuration.Builder(this)
.setSessionKey("example0ikl98")
.setDebugActive(BuildConfig.DEBUG)
.build();
EMMA.getInstance().startSession(configuration);
}
}
El envio de pantallas está activo por defecto en el SDK de EMMA. Para desactivarlo usa la siguiente configuración.
import android.app.Application
import io.emma.android.EMMA
class ExampleApplication : Application() {
override fun onCreate() {
super.onCreate()
val configuration = EMMA.Configuration.Builder(this)
.setSessionKey("example0ikl98")
.trackScreenEvents(false)
.setDebugActive(BuildConfig.DEBUG)
.build()
EMMA.getInstance().startSession(configuration)
}
}
Configurar sub-dominio para el POWLINK
Para soportar Powlink en Android, consulta la guia de soporte para configurar Powlink en el dashboard de EMMA
Conociendo el subdominio que corresponde a tus POWLINKS, debes añadir una activity nueva al AndroidManifest.xml
de tu aplicación tal y como indicamos a continuación. Esta actividad es la que se tiene que utilizar también para el deeplink, como explicamos más abajo.
<activity
android:name="io.emma.android.activities.EMMADeepLinkActivity"
android:noHistory="true"
android:exported="true"
android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="{YOUR_DEEPLINK_SCHEME}"/>
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:host="subdomain.powlink.io"
android:scheme="https"/>
<data
android:host="shortsubdomain.pwlnk.io"
android:scheme="https"/>
</intent-filter>
</activity>
Como explicamos más abajo en el apartado de deeplink, también hay que añadir, dentro del tag application, el metadato con la activity a ejecutar para tratar la url del POWLINK.
<meta-data
android:name="io.emma.DEEPLINK_OPEN_ACTIVITY"
android:value="com.your.package.CustomDeeplinkActivity"/>
En el apartado de Deeplink se muestra como puedes manejar los POWLINKS o Deeplinks recibidos para procesarlos y mostrar la parte correspondiente de tu aplicación.
Si estas usando un tracker con un dominio que no es el de EMMA (.powlink.io o .pwlnk.io), es necesario añadir el dominio al iniciar la librería.
val configuration = EMMA.Configuration.Builder(this)
.setSessionKey("example0ikl98")
.setDebugActive(BuildConfig.DEBUG)
.setShortPowlinkDomains("emma.link.mycompany.com")
.setPowlinkDomains("emma.link.mycompany.com")
.build()
EMMA.getInstance().startSession(configuration)
Para diferenciar una notificación de nuestro sistema de push respecto a otros sistemas, el payload enviado por EMMA contiene un flag denominado “eMMa”.
EMMA ofrece un completo sistema de envío y reporting de Notificaciones Push fácil de integrar usando Firebase Cloud Messaging (FCM) en Android.
Obtén en primer lugar tu propio Sender ID y Server Key para FCM como se específica en este artículo y establece estos parámetros para la app en su cuenta de EMMA.
Para integrar FCM en tu app sigue los siguientes pasos:
Hay que añadir el siguiente service al AndroidManifest.xml:
<service
android:name="io.emma.android.push.EMMAFcmMessagingService"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
Añadimos la siguiente dependencia al build.gradle situado en la raíz del proyecto:
buildscript {
// ...
dependencies {
// ...`
classpath 'com.google.gms:google-services:4.3.10' // google-services plugin`
}
}
allprojects {
// ...
repositories {
// ...
google() // Google's Maven repository`
}
}
En el build.gradle de la app añadimos la dependencia de Firebase:
apply plugin: 'com.android.application'
android {
// ...
}
dependencies {
//
// ...
implementation 'io.emma:eMMaSDK:4.12.+'
implementation 'com.google.firebase:firebase-messaging:23.1.0'
}
// ADD THIS AT THE BOTTOM
apply plugin: 'com.google.gms.google-services'
Inicie el sistema de push debajo del inicio de sesión en el Application:
override fun onCreate() {
super.onCreate();
EMMA.Configuration configuration = new EMMA.Configuration.Builder(this)
.setSessionKey("example0ikl98")
.setDebugActive(BuildConfig.DEBUG)
.build();
EMMA.getInstance().startSession(configuration);
val pushOpt = EMMAPushOptions.Builder(PushActivity::class.java, R.drawable.notification_icon)
.setNotificationColor(ContextCompat.getColor(this, R.color.yellow))
.setNotificationChannelName("Mi custom channel")
.build()
EMMA.getInstance().startPushSystem(pushOpt);
}
MyActivity.class: Actividad que desea que se abra cuando se recibe el Push
R.drawable.icon: (Opcional) El resource id de la imagen que desea mostrar con la notificación Push. Si no se especifica ningún icono, el Push utilizará el icon de la app.
customDialog: (Opcional) Establecerlo para asegurar que se desea utilizar su Custom Dialog.
Desde Android 13 para recibir notificationes es necesario solicitar un permiso al usuario. Para ello, EMMA ha añadido un método al SDK disponible en la versión 4.12 o superiores. Para el correcto funcionamiento este método tiene que ser llamado en un Activity. Si la app ya cuenta con una alerta personalizada o ya integra la solicitud del permiso por defecto no hace falta usar este método:
class HomeActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState);
EMMA.getInstance().requestNotificationsPermission();
}
}
Añadir el método de Activity's onNewIntent() llamando a EMMA.onNewNotification(), que verificará si el usuario ha recibido una notificación cuando la app esta abierta.
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent);
EMMA.getInstance().onNewNotification(this, intent, true);
}
El boolean que tiene como parámetro el método onNewNotification comprueba que el push contiene Rich Push Url en el caso de estar a true.
Para comprobar el richPushUrl cuando se abre la app desde la notificación, añade en la activity de push lo siguiente:
class HomeActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState);
EMMA.getInstance().checkForRichPushUrl();
}
}
El checkForRichPushUrl también se puede utilizar en cualquier parte de la app si se prefiere.
Si tu aplicación se basa en un WebView, tienes que añadir el checkForRichPushUrl en el siguiente método:
webView.webViewClient = object : WebViewClient() {
...
override fun onPageFinished(view: WebView, url: String) {
EMMA.getInstance().checkForRichPushUrl();
}
}
Opcionalmente, si deseas controlar qué recibe de un Push, su Activity debe implementar la interfaz EMMANotificationInterface y el método onPushOpen que será llamado cuando el usuario abra la notificación.
class HomeActivity : Activity(), EMMAInAppMessageInterface {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState);
EMMA.getInstance().getNotificationInfo();
}
override fun onPushOpen(pushCampaign: EMMAPushCampaign) {
//Do whatever you want with push campaign
}
}
Para inhabilitar las notificaciones de un dispositivo, use EMMA.getInstance().unregisterPushService() y asegúrate de no llamar de nuevo a EMMA.getInstance().startPushSystem(...).
Puedes seleccionar el color que quieras en las notificaciones push añade el setNotificationColor a la opciones de push:
val pushOpt = EMMAPushOptions.Builder(PushActivity::class.java, R.drawable.notification_icon)
.setNotificationColor(ContextCompat.getColor(this, R.color.yellow))
.build()
EMMA.getInstance().startPushSystem(configuration);
Se necesita la versión del SDK 2.5.5 o una superior.
Para usar sonidos personalizados en las notificaciones que envíes con EMMA, tienes que añadir los archivos de sonido que quieras a la carpeta raw de los recursos de tu app (carpeta res). Recuerda que debes emplear para los sonidos los mismos nombres de archivo en iOS y Android.
Puedes redireccionar las aperturas de las notificaciones push a una sección en tu app. Para ello debes usar una estructura como esta:
scheme://host/page1/page2/page3...
La versión 4.2 trae cambios referentes a la gestión del deep link. Para integrarlo sigue los siguientes pasos:
Añade la siguiente actividad en el AndroidManifest.xml :
<activity
android:name="io.emma.android.activities.EMMADeepLinkActivity" android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="YOUR_SCHEME"`
android:host="YOUR_HOST"/>
</intent-filter>
</activity>
Añade la actividad a ser lanzada, en forma de meta-data dentro del tag en AndroidManifest.xml. Esta actividad será lanzada cuando el SDK ejecute un deeplink:
<meta-data
android:name="io.emma.DEEPLINK_OPEN_ACTIVITY"
android:value="com.your.package.CustomDeeplinkActivity"/>
Recuerda que en caso de ser una actividad que se pueda encontrar abierta en la app cuando un deeplink se ejecute, se tiene que declarar en el AndroidManifest.xml como singleTask:
<activity`
android:name=".activities.MainActivity"
android:launchMode="singleTask"/>
En este caso, si la actividad esta en la pila cuando se ejecuta el deeplink, el intent con la información de este llegará al método de la actividad onNewIntent. En caso de no tener el "launchMode" como singleTask ocasiona que la actividad se instancie nuevamente, lo que produce duplicaciones.
Para que el deeplink que se introduce en el campo Rich Push URL (en la web de EMMA) se ejecute correctamente, es importante añadir el siguiente método en la actividad que es abierta por el push o alguna otra que sea consecuente de esta, pero que se ejecute al abrir la app desde la notificación:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState);
EMMA.getInstance().checkForRichPush();
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent);
EMMA.getInstance().onNewNotification(intent, true);
}
El método checkForRichPush y onNewNotification comprueban el campo Rich Push enviado en el payload de la notificación y realizan las acciones pertinentes. En el caso de ser un deeplink lo ejecutarán abriendo la actividad definida en el metadato del AndroidManifest.xml.
Definir el comportamiento de la actividad que ha de abrir el deeplink. En este caso CustomDeepLinkActivity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view);
if (intent != null && intent.data != null ) {
processDeepLink(intent.data);
}
finish();
}
private fun processDeepLink(uri: Uri) {
if (uri.host.equals("home")) {
goHome();
}
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent);
if (intent != null && intent.data != null ) {
processDeepLink(intent.data);
}
}
EMMA da la posibilidad de integrar las notificaciones push fuera de su propio servicio.
class CustomService: FirebaseMessagingService() {
private fun isPushFromEMMA(remoteMessage: RemoteMessage): Boolean {
return remoteMessage.data["eMMa"] == "1"
}
override fun onMessageReceived(remoteMessage: RemoteMessage) {
if (isPushFromEMMA(remoteMessage)) {
EMMAPushNotificationsManager.handleNotification(applicationContext, remoteMessage.data)
}
}
override fun onNewToken(token: String) {
EMMAPushNotificationsManager.refreshToken(applicationContext, token, EMMAPushType.FCM)
}
}
A partir de la versión 4.10.x se ha desarrollado la funcionalidad de añadir botones con acciones en las notificaciones. Para añadir está funcionalidad a Android simplemente hay que tener el SDK actualizado a esta versión.
Para la configuración en la interfaz consulta aquí.
El 19 de mayo de 2019, Google decidió finalizar con Huawei aquellos negocios que requieran transferencia de hardware y software, menos aquellos cubiertos por licencias open source. Esto se traduce en que los dispositivos fabricados a partir de esta fecha no contarán con los servicios de Google como es la Play Store, aunque sí con el equivalente, la App Gallery de Huawei.
Desde EMMA, hemos modificado nuestro SDK para adaptarlo a la tienda de aplicaciones de Huawei. Con el objetivo de medir la atribución así como permitir el envío de notificaciones Push mediante su servicio.
La versión mínima del SDK disponible para hacer la integración de Huawei, es la versión 4.7.0. Si tienes una versión del SDK anterior, deberás actualizarla para que todo funcione debidamente.
Para realizar integración hay que seguir los siguientes pasos:
Lo primero que debemos hacer es añadir las dependencias al build.gradle del proyecto.
buildscript {
repositories {
google()`
jcenter()
maven { url 'http://developer.huawei.com/repo/' }
}
dependencies {
classpath 'com.android.tools.build:gradle:7.4.1'
classpath 'com.huawei.agconnect:agcp:1.6.2.300'
}
}
allprojects {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
}
A continuación añadimos las dependencias de HMS a la aplicación. La dependencia ads-identifier permite obtener el identificador de publicidad usado en Huawei. Le dependencia push permite el uso del servicio HMS para notificaciones push.
build.gradle
dependencies {
// other dependencies
implementation 'com.huawei.hms:ads-identifier:3.4.62.300'
implementation 'com.huawei.hms:push:6.10.0.300'
}
apply plugin: 'com.huawei.agconnect'
La integración del servicio HMS es compatible con la integración de FCM en el SDK de EMMA. La versión mínima de Android soportada para la integración de HMS es Android 19.
Hay que añadir el siguiente servicio al AndroidManifest.xml:
<service
android:name="io.emma.android.push.EMMAHmsMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.huawei.push.action.MESSAGING_EVENT" />
</intent-filter>
</service>
Para obtener las credenciales dirigete a la siguiente sección aquí
Por último, compilamos la app y ya podemos enviar notificaciones push a dispositivos Huawei
Con EMMA puedes realizar una integración completa del SDK que te permita conocer la localización de tus usuarios, cómo se registran en tu App, cuántas transacciones realizan y hasta sus características propias. Es decir, toda la información de tus usuarios que obtendrás en la sección de Behavior.
La plataforma de EMMA hace la diferenciación entre dos tipos de eventos. Los que la plataforma incluye por defecto y los eventos Custom que quieras integrar según la estructura de tu aplicación.
Puedes consultar más información sobre los eventos por defecto aquí.
El método EMMA.getInstance().registerUser() permite enviar información sobre los registros en la aplicación.
fun register() {
EMMA.getInstance().registerUser("554234", "test@emma.io")
}
function register() {
EMMA.getInstance().registerUser("554234", "test@emma.io")
}
El método EMMA.getInstance().loginUser() permite enviar información sobre los eventos login.
Si tenemos un evento login sucesivo con los mismos datos, podemos utilizar el método EMMA.loginDefault(). Este método sería útil en el caso de un "Auto-Login" por ejemplo.
fun login() {
EMMA.getInstance().loginUser("554234", "test@emma.io")
}
public void login() {
EMMA.getInstance().loginUser("554234", "test@emma.io");
}
EMMA permite medir cualquier transacción o compra que se realice en tu app. Este es el ejemplo paramedir una transacción:
fun trackTransaction() {
EMMA.getInstance().startOrder("<ORDER_ID>","<CUSTOMER_ID>",10.0, "")
EMMA.getInstance().addProduct("<PRODUCT_ID>", "<PRODUCT_NAME>", 1.0, 10.0)
EMMA.getInstance().trackOrder()
}
public void trackTransaction {
EMMA.getInstance().startOrder("<ORDER_ID>","<CUSTOMER_ID>",10.0, "");
EMMA.getInstance().addProduct("<PRODUCT_ID>", "<PRODUCT_NAME>", 1.0, 10.0);
EMMA.getInstance().trackOrder();
}
El método para iniciar la transacción es EMMA.getInstance().startOrder().
EMMA.getInstance().startOrder("<ORDER_ID>","<CUSTOMER_ID>",10.0, "")
EMMA.getInstance().startOrder("<ORDER_ID>","<CUSTOMER_ID>",10.0, "");
Una vez iniciada la transacción hay que añadir los productos a la misma. Para ello usaremos el método EMMA.getInstance().addProduct().
EMMA.getInstance().addProduct("<PRODUCT_ID>", "<PRODUCT_NAME>", 1.0, 10.0)
EMMA.getInstance().addProduct("<PRODUCT_ID>", "<PRODUCT_NAME>", 1.0, 10.0);
Una vez tenemos todos los productos añadidos, ejecutamos la medición de la transacción con el método EMMA..getInstance().trackOrder()
EMMA.getInstance().trackOrder()
EMMA.getInstance().trackOrder();
En el caso de que se necesite cancelar el tracking de una transacción usaremos el método EMMA.getInstance().cancelOrder().
fun cancelTransaction() {
EMMA.getInstance().cancelOrder("<ORDER_ID>")
}
public void cancelTransaction {
EMMA.getInstance().cancelOrder("<ORDER_ID>");
}
https://docs.emma.io/es/primeros-pasos/eventos#eventos-personalizados
Ejemplo para enviar un evento propio de la aplicación:
val eventRequest = EMMAEventRequest("f983d4bef8fc44dad43a1bb30dde9e3c")
//Optional: custom attributes
eventRequest.attributes = attributes
//Optional: request status listener
eventRequest.requestListener = requestListener
//Optional: cumtom id for request delegate
eventRequest.customId = customId
EMMA.getInstance().trackEvent(eventRequest)
EMMAEventRequest eventRequest = new EMMAEventRequest("f983d4bef8fc44dad43a1bb30dde9e3c");
//Optional: custom attributes
eventRequest.setAttributes(attributes);
//Optional: request status delegate
eventRequest.setRequestDelegate(requestDelegate);
//Optional: cumtom id for request delegate
eventRequest.setCustomId(customId);
EMMA.getInstance().trackEvent(eventRequest);
En EMMA podemos enriquecer el perfil del usuario con información almacenada mediante Clave / Valor a la que le llamamos tags de usuario.
Para enviar esta información deberemos implementar el método trackExtraUserInfo
:
val tags = ArrayMap<String, String>()
tags["MY_CUSTOM_TAG"] = "MY_CUSTOM_VALUE"
EMMA.getInstance().trackExtraUserInfo(tags)
Map<String, String> tags = new HashMap<>();
tags.put("MY_CUSTOM_TAG", "MY_CUSTOM_VALUE");
EMMA.getInstance().trackExtraUserInfo(tags);
Si tu aplicación cuenta con permisos de localización, EMMA puede guardar esa información en el perfil del usuario.
Si no se quiere registrar la información del usuario, hay que implementar el método disableTrackingLocation()
antes de ejecutar la llamada startSession
.
Podemos recuperar el identificador interno de EMMA con el método getUserID()
:
class MainActivity : BaseActivity(), EMMAUserInfoInterface {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
EMMA.getInstance().getUserID()
}
override fun OnGetUserInfo(userInfo: JSONObject?) {
// Not implemented
}
override fun OnGetUserID(id: Int) {
Log.d("MainActivity", id.toString())
}
}
public class MainActivity extends BaseActivity implements EMMAUserInfoInterface {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EMMA.getInstance().getUserID();
}
@Override
public void OnGetUserInfo(JSONObject userInfo) {
// Not implemented
}
@Override
public void OnGetUserID(int id) {
Log.d("MainActivity", Integer.toString(id));
}
}
El formato del identificador es de tipo UUID V4. Para obtener el identificador del dispositivo usa el siguiente método.
EMMA.getInstance().getDeviceId()
EMMA.getInstance().getDeviceId();
Para enviar el customer ID independientemente del login/registro usa el siguiente método:
EMMA.getInstance().setCustomerId("<Customer ID>")
EMMA.getInstance().setCustomerId("<Customer ID>")
Si necesitamos recuperar el perfil del usuario desde la aplicación usaremos el método getUserInfo()
:
class MainActivity : BaseActivity(), EMMAUserInfoInterface {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
EMMA.getInstance().getUserInfo()
}
override fun OnGetUserInfo(userInfo: JSONObject?) {
userInfo?.let {
// Do something with userInfo
}
}
override fun OnGetUserID(id: Int) {
// Not implemented
}
}
public class MainActivity extends BaseActivity implements EMMAUserInfoInterface {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EMMA.getInstance().getUserInfo();
}
@Override
public void OnGetUserInfo(JSONObject userInfo) {
if (userInfo != null) {
// Do something with userInfo
}
}
@Override
public void OnGetUserID(int id) {
// Not implemented
}
}
Después del proceso de atribución, EMMA pone a disposición del SDK la información de atribución del usuario.
Para obtener la información de atribución usaremos el método getInstallAttributionInfo
:
class MainActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
EMMA.getInstance().getInstallAttributionInfo { attribution ->
if (attribution != null) {
// Do something with attribution
}
}
}
}
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EMMA.getInstance().getInstallAttributionInfo(new EMMAInstallAttributionInterface() {
@Override
public void onAttributionReceived(EMMAInstallAttribution attribution) {
if (attribution != null) {
// Do something with attribution
}
}
});
}
}
Consulta la descripción de los campos de atribución para ver la información disponible.
Si utilizas proguard o alguna alternativa compatible, a continuación tenemos un ejemplo del contenido del fichero de reglas progruard-rules.pro
. Puede que tengas que modificar otras reglas dependiendo de cada aplicación.
# EMMA SDK
-keep class io.emma.android.** { *; }
# Rules for play services ads identifier
-keep class com.google.android.gms.common.ConnectionResult {
int SUCCESS;
}
-keep class com.google.android.gms.ads.identifier.AdvertisingIdClient {
com.google.android.gms.ads.identifier.AdvertisingIdClient$Info getAdvertisingIdInfo(android.content.Context);
}
-keep class com.google.android.gms.ads.identifier.AdvertisingIdClient$Info {
java.lang.String getId();
boolean isLimitAdTrackingEnabled();
}
# Rule for google play referrer
-keep public class com.android.installreferrer.** { *; }
# Keep generic signatures; needed for correct type resolution
-keepattributes Signature
# Keep Gson annotations
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault
-if class com.google.gson.reflect.TypeToken
-keep,allowobfuscation class com.google.gson.reflect.TypeToken
-keep,allowobfuscation class * extends com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowoptimization @com.google.gson.annotations.JsonAdapter class *
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.Expose <fields>;
@com.google.gson.annotations.JsonAdapter <fields>;
@com.google.gson.annotations.Since <fields>;
@com.google.gson.annotations.Until <fields>;
}
-keepclassmembers class * extends com.google.gson.TypeAdapter {
<init>();
}
-keepclassmembers class * implements com.google.gson.TypeAdapterFactory {
<init>();
}
-keepclassmembers class * implements com.google.gson.JsonSerializer {
<init>();
}
-keepclassmembers class * implements com.google.gson.JsonDeserializer {
<init>();
}
-if class *
-keepclasseswithmembers,allowobfuscation class <1> {
@com.google.gson.annotations.SerializedName <fields>;
}
-if class * {
@com.google.gson.annotations.SerializedName <fields>;
}
-keepclassmembers,allowobfuscation,allowoptimization class <1> {
<init>();
}
# Rules for retrofit2
-keepattributes Signature, InnerClasses, EnclosingMethod
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
-keepattributes AnnotationDefault
-keepclassmembers,allowshrinking,allowobfuscation interface * {
@retrofit2.http.* <methods>;
}
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-dontwarn javax.annotation.**
-dontwarn kotlin.Unit
-dontwarn retrofit2.KotlinExtensions
-dontwarn retrofit2.KotlinExtensions$*
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface <1>
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface * extends <1>
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
-if interface * { @retrofit2.http.* public *** *(...); }
-keep,allowoptimization,allowshrinking,allowobfuscation class <3>
-keep,allowobfuscation,allowshrinking class retrofit2.Response
# Rules for okhttp3
-keepattributes Signature
-keepattributes Annotation
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
-dontwarn okio.**
# Rules for glide (used to display images by sdk)
-keep class com.bumptech.glide.** { *; }
-dontwarn com.bumptech.glide.**
# Rules for push
-keep class com.google.firebase.** { *; }
# Rules for Huawei hms push and odid identifier
-ignorewarnings
-keepattributes *Annotation*
-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
-keep class com.huawei.hianalytics.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}
# Rules for Huawei ads-identifier and ads referrer
-keep class com.huawei.hms.ads.** { *; }
-keep interface com.huawei.hms.ads.** { *; }
En algunos, es necesario cambiar la url de API EMMA (p.e proxies), para ello hay que añadir lo siguiente justo antes del método startSession(...)
:
val configuration = EMMA.Configuration.Builder(this)
.setSessionKey("example0ikl98")
.setWebServiceUrl("https://www.your_proxy_url.com/")
.setDebugActive(BuildConfig.DEBUG)
.build()
EMMA.Configuration configuration = new EMMA.Configuration.Builder(this)
.setSessionKey("example0ikl98")
.setDebugActive(BuildConfig.DEBUG)
.setWebserviceUrl("https://www.your_proxy_url.com/")
.build();
Messaging incluye 7 formatos comunicativos diferentes que puedes integrar para impactar a tus usuarios:
EMMA NativeAd te permite obtener la información de un NativeAd correspondiente a una plantilla que se haya definido y configurado en la plataforma de EMMA.
class NativeAdsActivity: BaseActivity(),
EMMAInAppMessageInterface,
EMMABatchNativeAdInterface,
EMMANativeAdInterface {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
fun getNativeAd(templateId: String) {
val nativeAdRequest = EMMANativeAdRequest()
nativeAdRequest.templateId = templateId
EMMA.getInstance().getInAppMessage(nativeAdRequest, this)
}
fun getNativeAdBatch(templateId: String) {
val nativeAdRequest = EMMANativeAdRequest()
nativeAdRequest.templateId = templateId
nativeAdRequest.isBatch = true
EMMA.getInstance().getInAppMessage(nativeAdRequest, this)
}
override fun onBatchReceived(nativeAds: MutableList<EMMANativeAd>) {
nativeAds.forEach { nativeAd ->
nativeAd.tag?.let { tag ->
print("Received batch nativead with tag: $tag")
}
}
}
override fun onReceived(nativeAd: EMMANativeAd) {
val content = nativeAd.nativeAdContent
val title = content["title"]?.fieldValue
if (title != null) {
print("Received NativeAd with Title: $title")
EMMA.getInstance().sendInAppImpression(CommunicationTypes.NATIVE_AD, nativeAd)
}
}
fun openNativeAd(nativeAd: EMMANativeAd) {
EMMA.getInstance().openNativeAd(nativeAd)
}
fun sendNativeAdClick(nativeAd: EMMANativeAd) {
EMMA.getInstance().sendInAppClick(CommunicationTypes.NATIVE_AD, nativeAd)
}
override fun onShown(campaign: EMMACampaign) {
print("Invocadoo método onShown")
}
override fun onHide(campaign: EMMACampaign) {
print("Invocadoo método onHide")
}
override fun onClose(campaign: EMMACampaign) {
print("Invocadoo método onClose")
}
}
Obtendremos toda la información del NativeAd disponible para el usuario referente al templateId, según las condiciones que se hayan configurado en la plataforma de EMMA.
Se llama a onReceived en el caso de que exista un NativeAd correspondiente a la plantilla con identificador “templateId”.
Se llama a onBatchReceived cuando se realiza la llamada de NativeAd con el parámetro batch a true y existen uno o más NativeAds correspondientes a la plantilla con identificador "templateId"
EMMANativeAd contiene todos los campos configurados en EMMA para esta plantilla de NativeAd, para obtenerlos se usará el siguiente método:
val content = nativeAd.nativeAdContent
val title = content["Title"]?.fieldValue
val image = content["Main picture"]?.fieldValue
val cta = content["CTA"]?.fieldValue
printSide(title, image, cta)
En el caso de configurar una plantilla contenedor se pueden obtener los valores del NativeAd de la siguiente forma:
val content = nativeAd.nativeAdContent
val container = content["container"]
container?.fieldContainer?.forEach { containerSide ->
val title = containerSide["Title"]?.fieldValue
val image = containerSide["Main picture"]?.fieldValue
val cta = containerSide["CTA"]?.fieldValue
printSide(title, image, cta)
}
Una vez obtenidos todos los campos requeridos, ya se puede crear la vista para pintar este NativeAd en pantalla en función del diseño que se le quiera aplicar. Una vez pintado el NativeAd en pantalla es necesario llamar a este método para poder obtener las impresiones en el reporting:
EMMA.getInstance().sendInAppImpression(CommunicationTypes.NATIVE_AD, nativeAd)
Para obtener un Native Ad único hay que utilizar el método getInAppMessage pasandole una instancia de EMMANativeAdRequest con el templateId especifico que se quiere usar. En el caso de tener varios Native Ad bajo el mismo templateId con este método se obtiene el último creado.
fun getNativeAd(templateId: String) {
val nativeAdRequest = EMMANativeAdRequest()
nativeAdRequest.templateId = templateId
EMMA.getInstance().getInAppMessage(nativeAdRequest, this)
}
Método usado para obtener todos los Native Ads activos bajo un mismo templateId.
fun getNativeAdBatch(templateId: String) {
val nativeAdRequest = EMMANativeAdRequest()
nativeAdRequest.templateId = templateId
nativeAdRequest.isBatch = true
EMMA.getInstance().getInAppMessage(nativeAdRequest, this)
}
El SDK proporciona un método para realizar la apertura de un Native Ad, este método se pone a modo de CTA cuando se haga click o se realize alguna acción sobre el Native Ad. Internamente este método lanza un WebView inapp o abre el browser con el CTA configurado en el Dashboard y seguidamente traquea el clic.
fun openNativeAd(nativeAd: EMMANativeAd) {
EMMA.getInstance().openNativeAd(nativeAd)
}
Alternativamente, si no se usa este método se puede enviar el click llamando al método:
EMMA.getInstance().sendInAppClick(nativeAd)
La StartView es un formato de comunicación que te permite mostrar un contenido HTML, alojado en una URL, en un WebView a pantalla completa.
fun getStartView() {
val startViewRequest = EMMAInAppRequest(EMMACampaign.Type.STARTVIEW)
EMMA.getInstance().getInAppMessage(startViewRequest)
}
El AdBall es una pequeña vista circular que muestra una imagen. Esta vista se puede arrastrar por toda la pantalla y eliminar de ella en cualquier momento, contiene un CTA que es una URL con contenido HTML que lanza un WebView al hacer clic en la ella.
fun getAdBall() {
val adBallRequest = EMMAInAppRequest(EMMACampaign.Type.ADBALL)
EMMA.getInstance().getInAppMessage(adBallRequest)
}
El banner es un formato de comunicación que permite adaptar una imagen o GIF en formato banner dentro de una pantalla de la aplicación. Este banner se puede mostrar en el de la pantalla dónde se muestra o en el bottom de esta. El banner contiene un CTA configurable en el Dashboard de EMMA y puede ser un deeplink o una url https, en el caso de ser la segunda opción al hacer hacer clic se abre un WebView con el contenido de la url.
Se recomienda hacer la llamada después de que todos los elementos de la pantalla esten cargados.
fun getBanner() {
val bannerRequest = EMMAInAppRequest(EMMACampaign.Type.BANNER)
EMMA.getInstance().getInAppMessage(bannerRequest);
}
El strip te permite mostrar un banner en lo alto de la pantalla del dispositivo con un texto que va pasando a modo de carrusel, variables como el tiempo de duración de la rotación o el tiempo de visualización son configurables desde el Dashboard.
fun getStrip() {
val stripRequest = EMMAInAppRequest(EMMACampaign.Type.STRIP)
EMMA.getInstance().getInAppMessage(stripRequest);
}
EMMA Coupons te permite obtener, verificar, canjear cupones que se hayan definido y configurado en la plataforma de EMMA.
class CouponsActivity: BaseActivity(), EMMACouponsInterface {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
EMMA.getInstance().addCouponsCallback(this)
getCoupons()
}
private fun getCoupons() {
EMMA.getInstance().getInAppMessage(EMMAInAppRequest(EMMACampaign.Type.COUPON))
}
private fun getSingleCoupon() {
val couponsRequest = EMMAInAppRequest(EMMACampaign.Type.COUPON)
couponsRequest.inAppMessageId = "<COUPON_ID>"
EMMA.getInstance().getInAppMessage(couponsRequest)
}
private fun redeemCoupon() {
val redeemCouponRequest = EMMAInAppRequest(EMMACampaign.Type.REDEEM_COUPON)
redeemCouponRequest.inAppMessageId = "<COUPON_ID>"
EMMA.getInstance().getInAppMessage(redeemCouponRequest)
}
private fun cancelCoupon() {
val cancelCouponRequest = EMMAInAppRequest(EMMACampaign.Type.CANCEL_COUPON)
cancelCouponRequest.inAppMessageId = "<COUPON_ID>"
EMMA.getInstance().getInAppMessage(cancelCouponRequest)
}
private fun couponValidRedeems() {
val couponValidRedeems = EMMAInAppRequest(EMMACampaign.Type.COUPON_VALID_REDEEMS)
couponValidRedeems.inAppMessageId = "<COUPON_ID>"
EMMA.getInstance().getInAppMessage(couponValidRedeems)
}
override fun onCouponsReceived(coupons: List<EMMACoupon>) {
coupons.let {
// Show coupons
coupons.forEach { coupon ->
EMMA.getInstance().sendInAppImpression(CommunicationTypes.COUPON, coupon)
}
}
}
override fun onCouponsFailure() {
print("An error has occurred obtaining coupons")
}
override fun onCouponRedemption(success: Boolean) {
print("Coupon redemption success: $success")
}
override fun onCouponCancelled(success: Boolean) {
print("Coupon cancelled success: $success")
}
override fun onCouponValidRedeemsReceived(numRedeems: Int) {
print("Coupon redeems: $numRedeems")
}
}
Con esta llamada, obtendremos toda la información de los coupons disponibles para el usuario, según las condiciones que se hayan configurado en la plataforma de EMMA.
private fun getCoupons() {
EMMA.getInstance().getInAppMessage(EMMAInAppRequest(EMMACampaign.Type.COUPON))
}
Se devolverá un listado de los cupones existentes listándose primero los cupones automáticos ordenados demás reciente a más antiguos y después se listarán los cupones clásicos ordenados también de más reciente a más antiguo.
Se llama a EMMACouponsInterface.onCouponsReceived
en el caso de que el usuario tenga disponibles coupons para canjear, o a EMMACouponsInterface.onCouponsFailure
si el usuario no tiene coupons disponibles. EMMACoupon contiene toda la información relativa al coupon: id (identificador interno de EMMA), código,número máximo de canjeos, número de veces canjeado, título, descripción, imagen...
Si se quiere enviar a EMMA la información de cuando se ha hecho click en el coupon o cuando este se muestra en la pantalla, hay que añadir los siguientes métodos cuando se realicen ambas acciones en la app:
EMMA.getInstance().sendInAppImpression(CommunicationTypes.COUPON, couponCampaign);
EMMA.getInstance().sendInAppClick(CommunicationTypes.COUPON, couponCampaign);
private fun cancelCoupon() {
val cancelCouponRequest = EMMAInAppRequest(EMMACampaign.Type.CANCEL_COUPON)
cancelCouponRequest.inAppMessageId = "<COUPON_ID>"
EMMA.getInstance().getInAppMessage(cancelCouponRequest)
}
Con esta llamada se puede cancelar el canjeo de un coupon realizado con anterioridad.
El parámetro couponId debe ser el identificador interno de EMMA de un coupon identificador que se puede obtener de una llamada a getCoupons hecha con anterioridad.
Se llama a EMMACouponsInterface.onCouponCancelled
, donde success indica si se ha cancelado el coupon.
A partir de la versión 4.9.0 se ha añadido la posibilidad de poder añadir plugins in-app al SDK. Los plugins inapp funcionan a través de la tecnología de Native Ad.
Puedes crear tu propio formato de comunicación y convertirlo en un plugin in-app, para ello es necesario que la clase principal del nuevo formato extienda de la clase abstracta EMMAInAppPlugin, esta clase obliga a sobrescribir dos métodos:
class CustomInAppPlugin: EMMAInAppPlugin() {
override fun getId(): String = "emma-plugin-custom"
override fun show(context: Activity?, nativeAd: EMMANativeAd) {
// Process data
}
override fun dismiss() {
}
El método show() es el método principal ya que es el que lanza el SDK cuando recibe el Native Ad
correspondiente al plugin, el SDK pasa al plugin como contexto la activity actual que hay visible en la app y el Native Ad con el contenido acorde a la plantilla marcada como plugin en el Dashboard. Con estos parámetros se puede crear cualquier formato de comunicación adaptado al contenido del Native Ad.
El método dismiss() es para ocultar el plugin automáticamente, de momento el SDK no tiene incorporado esta funcionalidad, deja el control de ocultado al propio plugin.
El método getId() devuelve el identificador del plugin que corresponde con el templateId generado en la plantilla..
La clase EMMAInAppPlugin contiene varios métodos estáticos cómo sendInAppImpression y sendInAppClick,al igual que en Native Ad, puedes enviar estas acciones. También puedes invocar al/los inappMessageListener con los métodos invokeShownListeners, invokeCloseListeners y invokeHideListeners.
Puedes consultar el ejemplo de plugin aquí
Para integrar un plugin es necesario añadirlo en el sdk después del inicio de sesión, para ello es necesario utilizar el método addInAppPlugin.
class App: Application {
override fun onCreate() {
super.onCreate()
....
EMMA.getInstance().startSession(configuration)
EMMA.getInstance().addInAppPlugins(CustomPlugin())
}
}
Una vez el sdk tenga el plugin simplemente hay que llamarlo en la parte de la app donde se requiera igual que si de un Native Ad se tratase.
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val request = EMMANativeAdRequest()
request.templateId = "emma-plugin-custom"
EMMA.getInstance().getInAppMessage(request)
}
}
Con esta funcionalidad podemos limitar las urls que abrirá el SDK de EMMA, de modo que en las
comunicaciones In-App, sólo se mostrarán en un Webview aquel contenido que empiece por alguna de las urls que hayamos indicado en la whitelist.
Si no indicamos ninguna url en la whitelist, cualquier url está permitida. Esta funcionalidad afectaría a los Push (Rich URL), Banners, StartViews y AdBalls. Las comunicaciones (Banners, StartViews y AdBalls) que pueden cargar contenido externo a la app mediante un Webview y para los Banners y AdBalls podrían cargar imágenes externas que también serían controladas por la whitelist.
Para un Push con Rich URL, si ésta no cumple, no se abriría la Webview correspondiente, pero el push sí que llega a la aplicación, hay que tener en cuenta que si en vez de una url se emplea un deeplink, el scheme del deeplink debe ser añadido a la whitelist para poder abrirlo.
fun enableWhitelist() {
EMMA.getInstance().whitelist = mutableListOf("https://mydomain.com", "https://mydomain2.com")
}
Si mi whitelist es “http://mydomain.com”.
Subimos al dashboard de EMMA un Banner con Target URL https://mydomain.com
El Banner no se mostrará, deberíamos añadir a la whitelist https://mydomain.com
Configuramos en el dashboard de EMMA una StartView con StartView URL http://www.mydomain.com
La StartView no se mostrará, deberíamos añadir a la whitelist http://www.mydomain.com
Configuramos en el dashboard de EMMA un Banner con Target URL http://mydomain.com/my/url y SmartPhone Banner URL http://subdomain.mydomain.com/my/image
El Banner no se mostrará, la url de la imagen no cumple con la whitelist, deberíamos añadir a la whitelist http://subdomain.mydomain.com
Subimos al dashboard de EMMA un Banner con Target URL http://mydomain.com/my/url/
El Banner se mostrará porque la url introducida en el campo Target URL empieza por el mismo protocolo y dominio que la url de la whitelist
Configuramos en el dashboard de EMMA una StartView con StartView URL http://mydomain.com/mypage.html¶m=value
La StartView se mostrará porque la url introducida en el campo StartView URL empieza por el mismo protocolo y dominio que la url de la whitelist
EMMA permite inhabilitar el trackeo o seguimiento para aquellos usuarios que manifiesten este deseo.
Este método es la mejor forma de adaptarse a la nueva RGPD (Reglamento General de la Protección de Datos).
La comunicación del usuario para expresar esta opción de no seguimiento debe ser tratada por la app haciendo una llamada al siguiente método:
public fun disableUserTracking(deleteUserData: Bool) {
/*
disableUserTracking() shuts down all communication with EMMA servers
If deleteUserData is true; EMMA will remove this device data from
their servers. This is a unrecoverable action.
*/
EMMA.getInstance().disableUserTracking(deleteUserData)
}
public void disableUserTracking(boolean deleteUserData) {
/*
disableUserTracking() shuts down all communication with EMMA servers
If deleteUserData is true; EMMA will remove this device data from
their servers. This is a unrecoverable action.
*/
EMMA.getInstance().disableUserTracking(deleteUserData)
}
En el caso de que se quiera volver a activar las comunicaciones del usuario, se puede utilizar este otro método:
public func enableUserTracking() {
EMMA.getInstance().enableUserTracking()
}
- public void enableUserTracking {
EMMA.getInstance().enableUserTracking()
}
Para todas aquellas apps que están dentro del programa "Designed for Famalies" necesitan cumplir una serie de requisitos respecto a la información a compartir, para ello EMMA ha habilitado una propiedad en el arranque de sesión para asegurar el cumplimiento de esta política.
import android.app.Application
import io.emma.android.EMMA
class ExampleApplication : Application() {
override fun onCreate() {
super.onCreate()
val configuration = EMMA.Configuration.Builder(this)
.setSessionKey("example0ikl98")
.setDebugActive(BuildConfig.DEBUG)
.setFamiliesPolicyTreatment(true)
.build()
EMMA.getInstance().startSession(configuration)
}
}
import android.app.Application;
import io.emma.android.EMMA;
public class ExampleApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
EMMA.Configuration configuration = new EMMA.Configuration.Builder(this)
.setSessionKey("example0ikl98")
.setFamiliesPolicyTreatment(true)
.setDebugActive(BuildConfig.DEBUG)
.build();
EMMA.getInstance().startSession(configuration);
}
}
Además, también es importante deshabilitar el permiso para recolectar el Google Advertasing ID en el AndroidManifest.
<uses-permission android:name="com.google.android.gms.permission.AD_ID"
tools:node="remove"/>