Crear APK gratis

API del puente de JavaScript

La bandeja de entrada push y la audiencia

Mensajes que el creador envió desde un panel, guardados en el dispositivo para que la página pueda mostrar un historial y no solo una ventana emergente de la bandeja, además del ID de usuario con sesión iniciada y las etiquetas que permiten al centro de envíos dirigirse a un usuario o a una etiqueta, y disparar automatizaciones como un recordatorio de carrito abandonado.

AppMint.trackEvent ayudante#

window.AppMint.trackEvent

Ejemplo

Documentado junto con WebToApk.trackEvent: el ejemplo de allí también muestra este.

Le dice a la app que ocurrió algo ("signed_up", "checkout_done", "level:3"). Un mensaje dentro de la app que el creador hizo en el centro de envíos de AppMint Push con el activador "Cuando ocurre un evento" y el mismo nombre se muestra ahora (o tras la espera que el creador eligió).

Devuelve: true cuando se aceptó el evento; false para un nombre fuera de letras, dígitos y _ . : - (hasta 64), y en una app compilada sin AppMint Push. AppMint.trackEvent(name, props) es la misma llamada con props como objeto. Requiere: AppMint Push activado en el paso de Integración (Paso 3) al compilar. propsJson es opcional ('') y no se guarda.

// After a purchase: the creator's "Thanks, rate us?" message is set to trigger on "purchase_done".
function onPurchaseDone(order) {
  if (window.AppMint && AppMint.trackEvent) {
    AppMint.trackEvent('purchase_done', { total: order.total });
  }
}

El puente directo recibe las propiedades como una cadena JSON (pasa '' si no hay ninguna):

function track(name, props) {
  if (!(window.WebToApk && window.WebToApk.trackEvent)) return false;   // a browser: nothing to show
  return WebToApk.trackEvent(name, props ? JSON.stringify(props) : '');
}
track('level:3');
track('tutorial_skipped', { step: 2 });

Un cambio de pantalla que la dirección no muestra (pestañas, un asistente, una "página" modal) puede informarse como una ruta, para que los mensajes "En una página" del creador lo vean. La página también puede lanzar el evento appmint:route con la ruta; la app lo escucha:

function showTab(name) {
  document.querySelectorAll('.tab').forEach(function (t) { t.hidden = t.id !== name; });
  if (window.AppMint && AppMint.trackEvent) AppMint.trackEvent('appmint:route', { path: '/' + name });
}

// Same thing, without touching the bridge at all:
window.dispatchEvent(new CustomEvent('appmint:route', { detail: { path: '/cart' } }));

Notas: los mensajes por ruta ya siguen por sí solos los cambios reales de URL (cargas de página, rutas history.pushState, #/hash); informa de una ruta solo para vistas en las que la dirección no cambia. Los eventos no se cuentan ni se guardan en ningún sitio; solo deciden si se muestra un mensaje.

clearPushInbox puente#

window.WebToApk.clearPushInbox(): Boolean

Vacía la bandeja de entrada push (la bandeja de notificaciones y el historial del servidor no se tocan).

Ejemplo

Vacía la bandeja de entrada de notificaciones push de este teléfono.

Devuelve: true cuando termina; false ante un error interno. Requiere: activar AppMint Push en el paso Integrar (Paso 3) al compilar.

document.getElementById('clear-inbox').addEventListener('click', function () {
  if (!(window.WebToApk && window.WebToApk.clearPushInbox)) return;
  if (!confirm('Delete all messages? This cannot be undone.')) return;
  if (WebToApk.clearPushInbox()) renderInbox();
});

Vacía la bandeja de entrada cuando el usuario cierre sesión, para que la siguiente persona en este teléfono no vea sus mensajes:

async function signOut() {
  await myAuth.signOut();
  if (window.WebToApk && window.WebToApk.clearPushInbox) {
    WebToApk.clearPushInbox();
  }
  document.getElementById('bell-count').textContent = '';
  showLoginScreen();
}

Muestra una fila de ajustes con cuántos mensajes hay guardados, desactivada cuando no hay nada que borrar:

function paintClearRow() {
  const btn = document.getElementById('clear-inbox');
  if (!(window.WebToApk && window.WebToApk.clearPushInbox)) { btn.hidden = true; return; }
  const count = JSON.parse(WebToApk.getPushInbox() || '[]').length;
  btn.textContent = count ? 'Delete ' + count + ' messages' : 'No messages';
  btn.disabled = count === 0;
}

document.getElementById('clear-inbox').addEventListener('click', function () {
  if (WebToApk.clearPushInbox()) paintClearRow();
  else alert('Could not delete the messages. Please try again.');
});

paintClearRow();

Notas: esto es permanente: a diferencia de dismissPushMessage, no se puede deshacer. Las notificaciones de la bandeja y tu historial de envíos en AppMint no se tocan. Los mensajes nuevos siguen llegando.

dismissPushMessage puente#

window.WebToApk.dismissPushMessage(id: String): Boolean

Descarta UN mensaje de la bandeja de entrada: el deslizamiento por fila que necesita una pantalla de bandeja de entrada (clearPushInbox es todo o nada). REVERSIBLE por diseño: la entrada se oculta, no se destruye, así que la interfaz puede ofrecer "Deshacer" durante unos segundos tras deslizar. Solo local: la notificación de la bandeja y el historial del creador no se tocan.

Ejemplo

Oculta un mensaje de la bandeja de entrada de notificaciones push (al deslizarlo). Se puede deshacer con restorePushMessage(id).

Devuelve: true si el mensaje se ocultó; false si el id es desconocido o ya estaba oculto. Requiere: activa AppMint Push en el paso de Integración (Paso 3) al compilar.

Desliza para descartar con un Deshacer de 5 segundos:

function dismissRow(id, rowEl) {
  if (!(window.WebToApk && window.WebToApk.dismissPushMessage)) return;
  if (!WebToApk.dismissPushMessage(id)) return;
  rowEl.remove();

  const bar = document.getElementById('undo-bar');
  bar.hidden = false;
  const timer = setTimeout(function () { bar.hidden = true; }, 5000);
  document.getElementById('undo-btn').onclick = function () {
    clearTimeout(timer);
    bar.hidden = true;
    WebToApk.restorePushMessage(id);         // back in its old place
    renderInbox();
  };
}

Ordena la bandeja de entrada cuando se abre ocultando los mensajes leídos y con más de 30 días:

function hideOldReadMessages() {
  if (!(window.WebToApk && window.WebToApk.dismissPushMessage)) return 0;
  const cutoff = Date.now() - 30 * 24 * 60 * 60 * 1000;
  let hidden = 0;
  JSON.parse(WebToApk.getPushInbox() || '[]').forEach(function (m) {
    if (m.read && m.receivedAt < cutoff && WebToApk.dismissPushMessage(m.id)) hidden++;
  });
  return hidden;
}

if (hideOldReadMessages() > 0) renderInbox();

Descarta una fila con un deslizamiento real del dedo (arrástrala más del 40 % de su ancho):

function makeSwipeable(rowEl, id) {
  let startX = null;
  rowEl.addEventListener('pointerdown', function (e) { startX = e.clientX; rowEl.setPointerCapture(e.pointerId); });
  rowEl.addEventListener('pointermove', function (e) {
    if (startX !== null) rowEl.style.transform = 'translateX(' + (e.clientX - startX) + 'px)';
  });
  rowEl.addEventListener('pointerup', function (e) {
    const dx = startX === null ? 0 : e.clientX - startX;
    startX = null;
    if (Math.abs(dx) > rowEl.offsetWidth * 0.4 && window.WebToApk && WebToApk.dismissPushMessage(id)) {
      rowEl.remove();
    } else {
      rowEl.style.transform = '';            // not far enough: snap back
    }
  });
}

Notas: solo cambia la bandeja de entrada de este teléfono. La notificación de la bandeja y tu historial de envíos en AppMint se conservan. Los mensajes ocultos no los devuelve getPushInbox().

getInAppCampaigns puente#

window.WebToApk.getInAppCampaigns(): String

Mensajes dentro de la app que tiene esta instalación: JSON [{id, name}] ("[]" sin AppMint Push).

Ejemplo

Enumera los mensajes dentro de la app que esta instalación tiene ahora mismo (las campañas del creador del centro de envío de AppMint Push para las que este usuario está en la audiencia) como una cadena JSON [{"id": "...", "name": "..."}].

Devuelve: una cadena de matriz JSON; "[]" cuando no hay ninguno y en una app compilada sin AppMint Push. Requiere: AppMint Push activado en el paso de Integración (Paso 3) al compilar. La lista se actualiza en cada inicio de la app (y aproximadamente cada hora en primer plano).

var list = [];
if (window.WebToApk && window.WebToApk.getInAppCampaigns) {
  try { list = JSON.parse(WebToApk.getInAppCampaigns()); } catch (e) {}
}
console.log('in-app messages on this phone:', list.map(function (c) { return c.name; }));

Muestra una lista de depuración en tu propia pantalla de administración:

function renderInAppDebug(el) {
  var raw = (window.WebToApk && WebToApk.getInAppCampaigns) ? WebToApk.getInAppCampaigns() : '[]';
  var items = JSON.parse(raw);
  el.innerHTML = items.length
    ? items.map(function (c) { return '<li>' + c.name + ' <code>' + c.id + '</code></li>'; }).join('')
    : '<li>No in-app messages for this install</li>';
}
renderInAppDebug(document.getElementById('inapp-debug'));

Omite tu propia sugerencia de bienvenida cuando el creador ya tenga un mensaje activo con ese nombre:

function hasCampaign(name) {
  try { return JSON.parse(WebToApk.getInAppCampaigns()).some(function (c) { return c.name === name; }); }
  catch (e) { return false; }
}
if (!hasCampaign('Welcome tour')) showMyOwnWelcome();

Notas: solo se exponen el id y el nombre; el mensaje en sí llega a la página a través del evento appmint:inapp cuando se muestra (ver setInAppPresentation).

getPushInbox puente#

window.WebToApk.getPushInbox(): String

Bandeja de entrada de AppMint Push (mensajes enviados por el creador, los más nuevos primero, máx. 50): matriz JSON de {id, title, body, imageUrl, link, receivedAt, read}. Siempre es la verdad completa y actual: una app que se monta tarde no pierde nada por haberse perdido los eventos `appmint:push` en vivo.

Ejemplo

Lee la bandeja de entrada dentro de la app de los mensajes push que enviaste con AppMint Push: los más recientes primero, hasta 50, sin los que el usuario descartó.

Devuelve: una cadena JSON, de forma síncrona. Analízala. Cada elemento: { id, title, body, imageUrl, link, receivedAt, read } (receivedAt en epoch ms; imageUrl y link son '' cuando el mensaje no los tiene), más campos de diseño opcionales cuando usaste una plantilla en AppMint: template, accent, iconUrl, buttons: [{label, link}], badge, inapp, countdownAt, progress, lines, collapse. '[]' cuando está vacío. Requiere: activa AppMint Push en el paso de Integración (Paso 3) al compilar; sin él la bandeja de entrada siempre está vacía.

Muestra la bandeja de entrada y actualízala en vivo con appmint:push:

function loadInbox() {
  if (!(window.WebToApk && window.WebToApk.getPushInbox)) return [];
  try { return JSON.parse(WebToApk.getPushInbox() || '[]'); } catch (e) { return []; }
}

function renderInbox() {
  const inbox = loadInbox();
  const unread = inbox.filter(function (m) { return !m.read; }).length;
  document.getElementById('bell-count').textContent = unread ? String(unread) : '';
  const ul = document.getElementById('inbox');
  ul.innerHTML = '';
  inbox.forEach(function (m) {
    const li = document.createElement('li');
    li.className = m.read ? 'read' : 'unread';
    li.textContent = m.title + ' — ' + m.body;
    li.onclick = function () {
      WebToApk.markPushRead(m.id);
      if (m.link) location.href = m.link;
      renderInbox();
    };
    ul.appendChild(li);
  });
}

// While the app is open:
window.addEventListener('appmint:push', function (e) {
  // { type: 'received', message: {id, title, body, ...}, presented: true|false }
  // { type: 'revoked', id }  — you retracted the message
  // presented = the app already showed it on screen (see setPushPresentation)
  if (e.detail.type === 'received' && !e.detail.presented) showBanner(e.detail.message.title);
  renderInbox();
});

renderInbox();

Actualiza el contador de no leídos de tu campana cada vez que el usuario vuelva a la app (los mensajes que llegaron mientras estaba en segundo plano ya están en la bandeja de entrada):

function unreadCount() {
  if (!(window.WebToApk && window.WebToApk.getPushInbox)) return 0;
  try {
    return JSON.parse(WebToApk.getPushInbox() || '[]').filter(function (m) { return !m.read; }).length;
  } catch (e) { return 0; }
}

function paintBell() {
  const n = unreadCount();
  const badge = document.getElementById('bell-count');
  badge.textContent = n > 9 ? '9+' : (n ? String(n) : '');
  badge.hidden = n === 0;
}

document.addEventListener('visibilitychange', function () {
  if (document.visibilityState === 'visible') paintBell();
});
paintBell();

Muestra la imagen de un mensaje y sus botones (solo si lo diseñaste con ellos), junto con la hora a la que llegó:

function renderCard(m) {
  const card = document.createElement('article');
  if (m.accent) card.style.borderLeft = '4px solid ' + m.accent;
  if (m.imageUrl) {
    const img = document.createElement('img');
    img.src = m.imageUrl; img.alt = '';
    card.appendChild(img);
  }
  const h = document.createElement('h3');
  h.textContent = m.title;
  const p = document.createElement('p');
  p.textContent = m.body;
  const time = document.createElement('time');
  time.textContent = new Date(m.receivedAt).toLocaleString();
  card.append(h, p, time);
  (m.buttons || []).forEach(function (b) {
    const btn = document.createElement('button');
    btn.textContent = b.label;
    btn.onclick = function () { WebToApk.markPushRead(m.id); if (b.link) location.href = b.link; };
    card.appendChild(btn);
  });
  return card;
}

if (window.WebToApk && window.WebToApk.getPushInbox) {
  const list = document.getElementById('inbox');
  JSON.parse(WebToApk.getPushInbox() || '[]').forEach(function (m) { list.appendChild(renderCard(m)); });
}

Notas: la bandeja de entrada se guarda en el teléfono, así que léela cuando se abra tu pantalla: los eventos solo llegan mientras la app está en pantalla. Un mensaje que retiras desde AppMint desaparece de la bandeja de entrada y de la bandeja de notificaciones. Los mensajes enviados como "solo push" (bandeja) no se añaden a la bandeja de entrada. El mismo detail también se pasa a window.onAppMintPush(detail) si lo defines.

getPushTags puente#

window.WebToApk.getPushTags(): String

Las etiquetas de esta instalación como una cadena de objeto JSON, p. ej. {"plan":"pro"}.

Ejemplo

Lee las etiquetas de AppMint Push de esta instalación.

Devuelve: una cadena JSON, de forma síncrona: un objeto de valores de texto, p. ej. '{"plan":"pro","cart":"open"}'; '{}' si no hay ninguna. Analízala. Requiere: activar AppMint Push en el paso Integrar (Paso 3) al compilar.

Lee una etiqueta:

function pushTags() {
  if (!(window.WebToApk && window.WebToApk.getPushTags)) return {};
  try { return JSON.parse(WebToApk.getPushTags() || '{}'); } catch (e) { return {}; }
}

const plan = pushTags().plan || 'free';

Establece una etiqueta solo cuando cambie: cada llamada a setPushTag hace que la instalación se comunique con AppMint Push, así que omite las que no cambian nada:

function ensureTag(key, value) {
  if (!(window.WebToApk && window.WebToApk.getPushTags)) return;
  const tags = JSON.parse(WebToApk.getPushTags() || '{}');
  if ((tags[key] || '') !== value) WebToApk.setPushTag(key, value);
}

ensureTag('plan', user.isPro ? 'pro' : 'free');

Enuméralas en una pantalla de depuración mientras pruebas el envío a una etiqueta:

const list = document.getElementById('push-tags');
if (window.WebToApk && window.WebToApk.getPushTags) {
  const tags = JSON.parse(WebToApk.getPushTags() || '{}');
  list.textContent = Object.keys(tags).length
    ? Object.keys(tags).map(function (k) { return k + ' = ' + tags[k]; }).join('\n')
    : 'No tags yet';
}

Notas: esto es lo que guarda el teléfono; el centro de envíos lo ve tras el próximo registro de la instalación, unos segundos después de un cambio si el teléfono tiene conexión.

getPushUser puente#

window.WebToApk.getPushUser(): String

El último ID de usuario establecido con setPushUser ("" si se cerró sesión o nunca se estableció).

Ejemplo

Lee el id de usuario que esta instalación dio por última vez a AppMint Push con setPushUser.

Devuelve: una string, de forma síncrona: el ID guardado, o '' cuando nadie tiene la sesión iniciada o nunca se estableció. Requiere: activar AppMint Push en el paso Integrar (Paso 3) al compilar.

Establece el ID solo cuando cambió (en cada inicio de la app):

function syncPushUser(currentUserId) {
  if (!(window.WebToApk && window.WebToApk.getPushUser)) return;
  const want = currentUserId || '';
  if (WebToApk.getPushUser() !== want) WebToApk.setPushUser(want);
}

syncPushUser(localStorage.getItem('userId'));

Borra un ID obsoleto cuando tu propia sesión caducó mientras la app estaba cerrada:

async function checkSession() {
  const session = await myBackend.currentSession();       // null when expired
  if (!session && window.WebToApk && window.WebToApk.getPushUser && WebToApk.getPushUser() !== '') {
    WebToApk.setPushUser('');                              // stop personal messages to this phone
  }
}

checkSession();

Muéstralo en una pantalla de depuración mientras pruebas el envío a un solo usuario:

const info = document.getElementById('push-debug');
if (window.WebToApk && window.WebToApk.getPushUser) {
  const id = WebToApk.getPushUser();
  info.textContent = id ? 'Push user: ' + id : 'Push user: nobody signed in';
} else {
  info.textContent = 'Not inside the app';
}

Notas: esto es lo que guarda el teléfono. El centro de envíos ve un cambio tras el próximo registro de la instalación, unos segundos después si el teléfono tiene conexión.

markPushRead puente#

window.WebToApk.markPushRead(id: String): Boolean

Marca un mensaje push como leído; pasa "" para marcar todos los mensajes como leídos.

Ejemplo

Marca un mensaje de la bandeja push como leído, o todos cuando pasas ''.

Devuelve: true si un mensaje cambió; false si nada cambió (id desconocido, ya leído, o AppMint Push no habilitado). Requiere: activa AppMint Push en el paso de Integración (Paso 3) al compilar.

function openMessage(id) {
  if (!(window.WebToApk && window.WebToApk.markPushRead)) return;
  WebToApk.markPushRead(id);                 // one message
  updateBellCount();
}

document.getElementById('mark-all-read').addEventListener('click', function () {
  if (!(window.WebToApk && window.WebToApk.markPushRead)) return;
  WebToApk.markPushRead('');                 // every message
  updateBellCount();
});

function updateBellCount() {
  const inbox = JSON.parse(WebToApk.getPushInbox() || '[]');
  const unread = inbox.filter(function (m) { return !m.read; }).length;
  document.getElementById('bell-count').textContent = unread ? String(unread) : '';
}

Marca un mensaje como leído una vez que el usuario realmente lo haya visto en pantalla, no solo cuando lo toque:

if (window.WebToApk && window.WebToApk.markPushRead) {
  const seen = new IntersectionObserver(function (entries) {
    entries.forEach(function (entry) {
      if (!entry.isIntersecting) return;
      const id = entry.target.dataset.msgId;
      seen.unobserve(entry.target);
      if (WebToApk.markPushRead(id)) {       // true only when it was unread
        entry.target.classList.replace('unread', 'read');
        updateBellCount();
      }
    });
  }, { threshold: 0.6 });

  document.querySelectorAll('#inbox li.unread').forEach(function (li) { seen.observe(li); });
}

Borra la insignia cuando se abra la pantalla de la bandeja de entrada, y vuelve a dibujar solo cuando algo realmente estuviera sin leer:

function openInboxScreen() {
  showScreen('inbox');
  if (!(window.WebToApk && window.WebToApk.markPushRead)) return;
  const changed = WebToApk.markPushRead('');  // false: nothing was unread
  if (changed) {
    document.getElementById('bell-count').textContent = '';
    renderInbox();
  }
}

Notas: el estado de lectura se guarda solo en este teléfono. No elimina la notificación de la bandeja.

restorePushMessage puente#

window.WebToApk.restorePushMessage(id: String): Boolean

Deshace un descarte: devuelve el mensaje a su lugar en la bandeja de entrada.

Ejemplo

Deshace dismissPushMessage(id): el mensaje vuelve a la bandeja de entrada push en su lugar anterior.

Devuelve: true si el mensaje se restauró; false si el ID es desconocido o no estaba oculto. Requiere: activar AppMint Push en el paso Integrar (Paso 3) al compilar.

let lastDismissed = null;

function onSwipe(id) {
  if (!(window.WebToApk && window.WebToApk.dismissPushMessage)) return;
  if (WebToApk.dismissPushMessage(id)) {
    lastDismissed = id;
    showUndo();
    renderInbox();
  }
}

document.getElementById('undo-btn').addEventListener('click', function () {
  if (!lastDismissed || !window.WebToApk) return;
  if (WebToApk.restorePushMessage(lastDismissed)) renderInbox();
  lastDismissed = null;
});

Deshaz varios deslizamientos a la vez: recuerda cada mensaje oculto en esta pantalla y devuélvelos todos:

const hiddenThisVisit = [];

function hide(id) {
  if (window.WebToApk && WebToApk.dismissPushMessage(id)) {
    hiddenThisVisit.push(id);
    document.getElementById('undo-all').hidden = false;
    renderInbox();
  }
}

document.getElementById('undo-all').addEventListener('click', function () {
  if (!(window.WebToApk && window.WebToApk.restorePushMessage)) return;
  hiddenThisVisit.splice(0).forEach(function (id) { WebToApk.restorePushMessage(id); });
  this.hidden = true;
  renderInbox();
});

Ofrece una lista de "Ocultos recientemente" desde la que el usuario pueda restaurar más tarde. getPushInbox() no devuelve los mensajes ocultos, así que guarda tú mismo sus IDs y títulos:

function loadHidden() {
  try { return JSON.parse(localStorage.getItem('hiddenMsgs') || '[]'); } catch (e) { return []; }
}

function renderHidden() {
  const ul = document.getElementById('recently-hidden');
  ul.innerHTML = '';
  loadHidden().forEach(function (h) {
    const li = document.createElement('li');
    li.textContent = h.title + ' ';
    const btn = document.createElement('button');
    btn.textContent = 'Restore';
    btn.onclick = function () {
      WebToApk.restorePushMessage(h.id);     // false: retracted, cleared or already back
      const rest = loadHidden().filter(function (x) { return x.id !== h.id; });
      try { localStorage.setItem('hiddenMsgs', JSON.stringify(rest)); } catch (e) {}
      renderHidden();
      renderInbox();
    };
    li.appendChild(btn);
    ul.appendChild(li);
  });
}

Notas: un mensaje borrado con clearPushInbox() o retirado por ti desde AppMint no se puede restaurar.

setInAppPresentation puente#

window.WebToApk.setInAppPresentation(mode: String): Boolean

Presentación de los mensajes dentro de la app: "auto" (por defecto) deja que el shell dibuje el diseño del creador; "none" (persistente) entrega cada mensaje a la página como `appmint:inapp` {type:'shown', presented:false, message} para que lo dibuje ella misma.

Ejemplo

Elige quién dibuja un mensaje dentro de la app (una campaña del centro de envíos de AppMint Push) cuando ocurre su activador: la app ('auto', el valor por defecto: el banner, la tarjeta central, la hoja inferior o el diseño de pantalla completa del creador) o tu propia página ('none').

Devuelve: true cuando se guardó el modo (se queda en el teléfono hasta que se cambie); false para cualquier otro valor y en una app compilada sin AppMint Push. Requiere: AppMint Push activado en el paso de Integración (Paso 3) al compilar.

Cada mensaje dentro de la app lanza el evento appmint:inapp (y llama a window.onAppMintInApp(detail) si lo definiste) con type 'shown', 'clicked', 'dismissed' o 'answered' (una respuesta de estrellas o de puntuación de 0 a 10, con question y value):

window.addEventListener('appmint:inapp', function (e) {
  var d = e.detail;   // { type, id, name, template?, presented?, message?, button?, link?, question?, value? }
  if (d.type === 'shown') analytics('inapp_shown', d.name);
  if (d.type === 'clicked') analytics('inapp_clicked', d.name + ' #' + d.button);
  if (d.type === 'dismissed') analytics('inapp_closed', d.name);
  if (d.type === 'answered') analytics('inapp_answer', d.name + ' ' + d.question + '=' + d.value);
});

Dibuja tú mismo los mensajes; la app entrega cada uno en lugar de mostrarlo:

if (window.WebToApk && WebToApk.setInAppPresentation) WebToApk.setInAppPresentation('none');

window.onAppMintInApp = function (d) {
  if (d.type !== 'shown' || d.presented) return;   // presented = the app already drew it
  var m = d.message;                                // { title, body, imageUrl, link, inapp, accent?, buttons?, emoji?, question?, lines? }
  showMyDialog(m.title, m.body, (m.buttons || []).map(function (b) {
    return { label: b.label, onClick: function () { if (b.link) location.href = b.link; } };
  }));
};

Devuelve la decisión a la app (por ejemplo, desde un interruptor de ajustes):

document.getElementById('native-popups').addEventListener('change', function (e) {
  if (window.WebToApk && WebToApk.setInAppPresentation) {
    WebToApk.setInAppPresentation(e.target.checked ? 'auto' : 'none');
  }
});

Notas: con 'none' un mensaje sigue contando como mostrado (se aplican sus límites de frecuencia) en el momento en que se entrega a la página. Establecer 'none' también cierra un mensaje que la app esté mostrando en ese momento. Los mensajes push tienen su propio interruptor, setPushPresentation.

setPushPresentation puente#

window.WebToApk.setPushPresentation(mode: String): Boolean

Presentación nativa dentro de la app de los mensajes push: "auto" (por defecto) deja que el shell dibuje el banner / modal / hoja / tarjeta de pantalla completa que eligió el creador mientras la app está abierta; "none" lo desactiva para siempre (se guarda), para apps que dibujan los suyos. El evento `appmint:push` y la bandeja de entrada no se ven afectados en ningún caso; la marca `presented` del evento recibido indica si el shell lo mostró.

Ejemplo

Activa ('auto', el valor por defecto) o desactiva ('none') la visualización en pantalla que hace la propia app de los mensajes de AppMint Push, para apps que dibujan su propio banner a partir del evento appmint:push.

Devuelve: true cuando se guardó el modo; false para cualquier valor distinto de 'auto' o 'none'. La elección se guarda en el teléfono y permanece hasta que se cambie. Requiere: activar AppMint Push en el paso Integrar (Paso 3) al compilar.

Dibuja tu propio banner en lugar del del shell:

if (window.WebToApk && window.WebToApk.setPushPresentation) {
  WebToApk.setPushPresentation('none');       // 'auto' to give it back to the shell
}

window.addEventListener('appmint:push', function (e) {
  const d = e.detail;
  // { type: 'received', message: {...}, presented: false } — presented = the shell already showed it
  if (d.type === 'received' && !d.presented) showMyBanner(d.message.title, d.message.body, d.message.link);
  if (d.type === 'revoked') hideMyBanner(d.id);
});

Deja que el usuario desactive las ventanas emergentes en tu pantalla de ajustes. No hay un getter, así que guarda tú tu propia copia de la elección para dibujar el interruptor:

const toggle = document.getElementById('show-popups');
let saved = null;
try { saved = localStorage.getItem('pushPopups'); } catch (e) {}
toggle.checked = saved !== 'none';

toggle.addEventListener('change', function () {
  if (!(window.WebToApk && window.WebToApk.setPushPresentation)) return;
  const mode = toggle.checked ? 'auto' : 'none';
  if (WebToApk.setPushPresentation(mode)) {
    try { localStorage.setItem('pushPopups', mode); } catch (e) {}
  }
});

Con 'auto', averigua qué hizo el usuario con un mensaje que la app mostró en pantalla: opened cuando lo tocó (action es -1 para el mensaje en sí, o si no el índice del botón), closed cuando lo descartó sin tocarlo:

window.addEventListener('appmint:push', function (e) {
  const d = e.detail;
  if (d.type === 'opened') {
    // the message is already marked read in the inbox
    track('push_opened', { id: d.id, button: d.action, link: d.link });
    updateBellCount();
  } else if (d.type === 'closed') {
    track('push_closed', { id: d.id });
  }
});

Notas: con 'auto', un mensaje que enviaste con estilo dentro de la app se muestra sobre la app mientras está abierta (y entonces no se pone también en la bandeja de notificaciones). Con 'none' el shell nunca lo dibuja; la bandeja de entrada (getPushInbox) y el evento appmint:push funcionan igual en ambos casos. Establecer 'none' también cierra un mensaje que el shell esté mostrando en ese momento.

setPushTag puente#

window.WebToApk.setPushTag(key: String, value: String): Boolean

Establece una etiqueta de AppMint Push (clave: letras, dígitos, _ hasta 32; valor hasta 128): el centro de envíos puede dirigirse a "plan = pro", y una automatización puede dispararse un tiempo después de establecer una etiqueta (un carrito abandonado: establece cart=open y bórrala al pagar). Un valor vacío elimina la etiqueta. Hasta 50 etiquetas por instalación.

Ejemplo

Establece una etiqueta de AppMint Push en esta instalación, como plan = pro o city = pune. El centro de envío (Home > Notifications) puede enviar a todos los que tengan una etiqueta, y una automatización de etiquetas puede enviar un mensaje un tiempo determinado después de establecer una etiqueta: un carrito abandonado, un nivel terminado. Un valor vacío elimina la etiqueta.

Devuelve: true cuando se guarda; false cuando la clave no son 1-32 letras, dígitos o _, el valor supera los 128 caracteres, o la instalación tendría más de 50 etiquetas (en ese caso no se guarda nada). Las etiquetas se guardan en el teléfono y se informan a AppMint Push un momento después (o en el próximo inicio si no hay conexión). Requiere: activar AppMint Push en el paso Integrar (Paso 3) al compilar. La segmentación por etiquetas y las automatizaciones llegan a los teléfonos con una app creada con AppMint a partir del 30 de septiembre de 2026.

Etiqueta lo que el usuario compró o eligió, para poder enviar solo a "plan = pro":

function pushTag(key, value) {
  if (!(window.WebToApk && window.WebToApk.setPushTag)) return false;
  return WebToApk.setPushTag(key, value);
}

pushTag('plan', user.isPro ? 'pro' : 'free');
pushTag('city', user.city.toLowerCase());

Carrito abandonado: establece una etiqueta cuando hay artículos en el carrito y bórrala al pagar. En el centro de envíos, añade una automatización por etiqueta en cart con un retraso (por ejemplo, 60 minutos); un teléfono recibe el recordatorio solo si cart sigue establecida cuando se cumple el tiempo:

function onCartChanged(items) {
  if (!(window.WebToApk && window.WebToApk.setPushTag)) return;
  // Setting 'open' again while it is already 'open' does not restart the automation's clock.
  WebToApk.setPushTag('cart', items.length > 0 ? 'open' : '');
}

function onCheckoutComplete() {
  if (window.WebToApk && window.WebToApk.setPushTag) WebToApk.setPushTag('cart', '');   // bought: no reminder
}

Borra las etiquetas específicas del usuario al cerrar sesión, junto con el id de usuario:

function signOutOfPush() {
  if (!(window.WebToApk && window.WebToApk.setPushUser)) return;
  WebToApk.setPushUser('');
  WebToApk.setPushTag('plan', '');
  WebToApk.setPushTag('cart', '');
}

Notas: las etiquetas pertenecen a esta instalación, no al usuario con sesión iniciada. Establecer una etiqueta con el valor que ya tiene no cambia nada en el servidor. Después de eliminar una etiqueta, volver a establecerla permite que una automatización por etiqueta envíe de nuevo. Nunca pongas un correo electrónico, un número de teléfono ni nada privado en una etiqueta.

setPushTags puente#

window.WebToApk.setPushTags(json: String): Boolean

Establece varias etiquetas a la vez desde una cadena de objeto JSON; los valores "" las eliminan.

Ejemplo

Establece varias etiquetas de AppMint Push a la vez a partir de una cadena de objeto JSON, p. ej. '{"plan":"pro","team":"red"}'. Un valor "" elimina esa etiqueta; las etiquetas que no nombras se conservan.

Devuelve: true cuando se guarda; false cuando la cadena no es un objeto JSON, alguna clave no son 1-32 letras, dígitos o _, algún valor supera los 128 caracteres, o la instalación acabaría con más de 50 etiquetas; en ese caso no se guarda nada. Requiere: activar AppMint Push en el paso Integrar (Paso 3) al compilar. La segmentación por etiquetas y las automatizaciones llegan a los teléfonos con una app creada con AppMint a partir del 30 de septiembre de 2026.

Después de iniciar sesión, etiqueta el perfil en una sola llamada:

function tagProfile(profile) {
  if (!(window.WebToApk && window.WebToApk.setPushTags)) return false;
  return WebToApk.setPushTags(JSON.stringify({
    plan: profile.plan,                   // 'free' | 'pro'
    level: String(profile.level),         // values are text: turn numbers into strings
    team: profile.team || ''              // '' removes the tag
  }));
}

Al cerrar sesión, elimínalas todas (lee las etiquetas actuales, envía cada una de vuelta como ''):

function clearPushTags() {
  if (!(window.WebToApk && window.WebToApk.getPushTags)) return;
  const tags = JSON.parse(WebToApk.getPushTags() || '{}');
  Object.keys(tags).forEach(function (k) { tags[k] = ''; });
  WebToApk.setPushTags(JSON.stringify(tags));
  WebToApk.setPushUser('');
}

Terminó un nivel: etiquétalo y deja que una automatización por etiqueta en level_done (por ejemplo, 10 minutos) envíe el siguiente reto:

function onLevelComplete(level, score) {
  if (!(window.WebToApk && window.WebToApk.setPushTags)) return;
  WebToApk.setPushTags(JSON.stringify({
    level_done: String(level),            // a new value each level, so the automation can fire again
    last_score: String(score)
  }));
}

Notas: una llamada es un cambio: se guarda todo o nada. La instalación informa de las nuevas etiquetas a AppMint Push un momento después (o en el próximo inicio si no hay conexión).

setPushUser puente#

window.WebToApk.setPushUser(id: String): Boolean

Audiencia de AppMint Push: le dice al centro de envíos del creador QUIÉN es esta instalación, para que un mensaje pueda llegar a un solo usuario con sesión iniciada ("u_42") o a todos los que tengan una etiqueta. Llámalo después de iniciar sesión con tu propio ID de cuenta estable; pasa "" al cerrar sesión. Letras, dígitos y _ @ . : + - (hasta 128). Devuelve false para cualquier otra cosa, y en una app que no usa AppMint Push (OneSignal / Firebase propio: no se envía nada, 2026-10-03). Nunca pases un correo electrónico ni un número de teléfono: usa el ID de tu base de datos.

Ejemplo

Le dice a AppMint Push cuál de TUS usuarios tiene la sesión iniciada en este teléfono, para que el centro de envíos (Inicio > Notificaciones) pueda enviar un mensaje a ese usuario concreto. Llámalo después de iniciar sesión con tu propio ID de cuenta estable; llámalo con '' al cerrar sesión.

Devuelve: true cuando se guardó el id; false para un id con algo distinto de letras, dígitos y _ @ . : + -, o de más de 128 caracteres (entonces no se guarda nada). El id se conserva en el teléfono hasta que lo cambies, y esta instalación lo informa a AppMint Push un momento después (o en el siguiente inicio si no hay conexión). Requiere: activa AppMint Push en el paso de Integración (Paso 3) al compilar. Enviar a un usuario llega a teléfonos que ejecutan una app compilada con AppMint a partir del 30 Sep 2026; las compilaciones anteriores siguen recibiendo los mensajes enviados a Everyone.

Después de iniciar sesión y al cerrar sesión: usa el ID de tu base de datos, nunca un correo electrónico ni un número de teléfono:

function pushUser(id) {
  if (!(window.WebToApk && window.WebToApk.setPushUser)) return false;   // browser, or an older build
  return WebToApk.setPushUser(id);
}

async function signIn(email, password) {
  const user = await myBackend.signIn(email, password);   // your own sign-in
  pushUser(user.id);                                      // e.g. 'u_42' or a UUID
}

async function signOut() {
  await myBackend.signOut();
  pushUser('');                                           // this phone is nobody's now
}

Supabase: sigue la sesión, para que una sesión restaurada cuente igual que un inicio de sesión nuevo:

supabase.auth.onAuthStateChange(function (event, session) {
  if (!(window.WebToApk && window.WebToApk.setPushUser)) return;
  const id = session ? session.user.id : '';     // the auth UUID: letters, digits and '-'
  if (WebToApk.getPushUser() !== id) WebToApk.setPushUser(id);
});

Haz que un ID sea aceptable cuando el tuyo pueda contener otros caracteres (espacios, /, #), y registra el raro caso que aun así se rechace:

function pushUserIdFrom(rawId) {
  return String(rawId).trim().replace(/[^A-Za-z0-9_@.:+\-]/g, '_').slice(0, 128);
}

if (window.WebToApk && window.WebToApk.setPushUser) {
  const ok = WebToApk.setPushUser(pushUserIdFrom(currentUser.id));
  if (!ok) console.warn('push user id refused', currentUser.id);
}

Notas: el mismo usuario con sesión iniciada en dos teléfonos recibe el mensaje en ambos. El ID pertenece a esta instalación, no a la cuenta: al cerrar sesión hay que borrarlo, o el teléfono seguirá recibiendo los mensajes del usuario anterior. setPushUser('') no borra las etiquetas establecidas con setPushTag; borra también las etiquetas propias del usuario al cerrar sesión.

trackEvent puente#

window.WebToApk.trackEvent(name: String, propsJson: String): Boolean

Mensajes dentro de la app: informa de un evento en el que pueden activarse las campañas del creador (activador "event", mismo nombre). propsJson es JSON opcional. El nombre `appmint:route` con {"path":"/x"} informa de un cambio de vista que la URL no muestra. False para un nombre fuera de [A-Za-z0-9_.:-]{1,64}, y sin AppMint Push.

Ejemplo

Le dice a la app que ocurrió algo ("signed_up", "checkout_done", "level:3"). Un mensaje dentro de la app que el creador hizo en el centro de envíos de AppMint Push con el activador "Cuando ocurre un evento" y el mismo nombre se muestra ahora (o tras la espera que el creador eligió).

Devuelve: true cuando se aceptó el evento; false para un nombre fuera de letras, dígitos y _ . : - (hasta 64), y en una app compilada sin AppMint Push. AppMint.trackEvent(name, props) es la misma llamada con props como objeto. Requiere: AppMint Push activado en el paso de Integración (Paso 3) al compilar. propsJson es opcional ('') y no se guarda.

// After a purchase: the creator's "Thanks, rate us?" message is set to trigger on "purchase_done".
function onPurchaseDone(order) {
  if (window.AppMint && AppMint.trackEvent) {
    AppMint.trackEvent('purchase_done', { total: order.total });
  }
}

El puente directo recibe las propiedades como una cadena JSON (pasa '' si no hay ninguna):

function track(name, props) {
  if (!(window.WebToApk && window.WebToApk.trackEvent)) return false;   // a browser: nothing to show
  return WebToApk.trackEvent(name, props ? JSON.stringify(props) : '');
}
track('level:3');
track('tutorial_skipped', { step: 2 });

Un cambio de pantalla que la dirección no muestra (pestañas, un asistente, una "página" modal) puede informarse como una ruta, para que los mensajes "En una página" del creador lo vean. La página también puede lanzar el evento appmint:route con la ruta; la app lo escucha:

function showTab(name) {
  document.querySelectorAll('.tab').forEach(function (t) { t.hidden = t.id !== name; });
  if (window.AppMint && AppMint.trackEvent) AppMint.trackEvent('appmint:route', { path: '/' + name });
}

// Same thing, without touching the bridge at all:
window.dispatchEvent(new CustomEvent('appmint:route', { detail: { path: '/cart' } }));

Notas: los mensajes por ruta ya siguen por sí solos los cambios reales de URL (cargas de página, rutas history.pushState, #/hash); informa de una ruta solo para vistas en las que la dirección no cambia. Los eventos no se cuentan ni se guardan en ningún sitio; solo deciden si se muestra un mensaje.

Generado a partir del runtime de la app y sus archivos de ejemplo en cada compilación de la documentación. Léelo como Markdown · Todas las familias.

Comprobado con el puente publicado el 2026-10-22.