मुफ़्त APK बनाएँ

JavaScript ब्रिज API

पुश इनबॉक्स और ऑडियंस

क्रिएटर के डैशबोर्ड से भेजे मैसेज, डिवाइस पर रखे हुए, ताकि पेज सिर्फ़ ट्रे पॉप-अप नहीं बल्कि पूरा इतिहास दिखा सके - और साइन-इन यूज़र id व टैग, जिनसे सेंड सेंटर किसी एक यूज़र या टैग को टारगेट कर सकता है और छोड़ी हुई कार्ट के रिमाइंडर जैसे ऑटोमेशन चला सकता है।

AppMint.trackEvent हेल्पर#

window.AppMint.trackEvent

उदाहरण

WebToApk.trackEvent के साथ दस्तावेज़ित - वहाँ का उदाहरण इसे भी दिखाता है।

ऐप को बताता है कि कुछ हुआ है ("signed_up", "checkout_done", "level:3")। क्रिएटर ने AppMint Push सेंड सेंटर में ट्रिगर "जब कोई इवेंट हो" और वही नाम रखकर जो इन-ऐप मैसेज बनाया है, वह अभी दिखता है (या क्रिएटर के चुने इंतज़ार के बाद)।

लौटाता है: इवेंट लिया गया तो true; ऐसे नाम पर false जिसमें अक्षरों, अंकों और _ . : - (64 तक) के बाहर कुछ हो, और AppMint Push के बिना बने ऐप में भी। AppMint.trackEvent(name, props) वही कॉल है जिसमें props एक ऑब्जेक्ट है। ज़रूरत: बिल्ड करते समय इंटीग्रेट चरण (चरण 3) में AppMint Push चालू हो। propsJson वैकल्पिक है ('') और कहीं सेव नहीं होता।

// 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 });
  }
}

सीधा ब्रिज props को JSON स्ट्रिंग के रूप में लेता है (कुछ न हो तो '' दें):

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 });

ऐसा स्क्रीन बदलाव जो पते में नहीं दिखता (टैब, विज़ार्ड, मॉडल "पेज") रूट के रूप में बताया जा सकता है, ताकि क्रिएटर के "किसी पेज पर" मैसेज उसे देख सकें। पेज पाथ के साथ appmint:route इवेंट भी भेज सकता है; ऐप उसे सुनता है:

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' } }));

ध्यान दें: रूट वाले मैसेज असली URL बदलावों (पेज लोड, history.pushState, #/hash रूट) को अपने आप फ़ॉलो करते हैं; रूट सिर्फ़ उन व्यू के लिए बताएँ जिनमें पता नहीं बदलता। इवेंट कहीं गिने या सेव नहीं होते; वे सिर्फ़ तय करते हैं कि कोई मैसेज दिखे या नहीं।

clearPushInbox ब्रिज#

window.WebToApk.clearPushInbox(): Boolean

पुश इनबॉक्स ख़ाली करता है (ट्रे और सर्वर का इतिहास नहीं छुआ जाता)।

उदाहरण

इस फ़ोन पर पुश इनबॉक्स ख़ाली करता है।

लौटाता है: काम हो जाने पर true; अंदरूनी त्रुटि पर false। ज़रूरत: बिल्ड करते समय इंटीग्रेट चरण (चरण 3) में AppMint Push चालू करें।

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();
});

यूज़र के साइन-आउट करने पर इनबॉक्स ख़ाली करें, ताकि इस फ़ोन पर अगला व्यक्ति उनके मैसेज न देखे:

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

सेटिंग्स की एक पंक्ति दिखाएँ कि कितने मैसेज सेव हैं, और हटाने को कुछ न हो तो उसे बंद रखें:

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();

ध्यान दें: यह स्थायी है - dismissPushMessage के उलट, इसे पलटा नहीं जा सकता। ट्रे के नोटिफ़िकेशन और AppMint में आपका भेजने का इतिहास नहीं छुए जाते। नए मैसेज फिर भी आते रहते हैं।

dismissPushMessage ब्रिज#

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

इनबॉक्स से एक मैसेज हटाता है - इनबॉक्स स्क्रीन को जो हर पंक्ति का स्वाइप चाहिए (clearPushInbox सब या कुछ नहीं है)। जान-बूझकर पलटने लायक: एंट्री छिपाई जाती है, मिटाई नहीं जाती, इसलिए UI स्वाइप के बाद कुछ सेकंड "पूर्ववत करें" दे सकता है। सिर्फ़ लोकल: ट्रे का नोटिफ़िकेशन और क्रिएटर का इतिहास नहीं छुआ जाता।

उदाहरण

पुश इनबॉक्स से एक मैसेज छिपाता है (स्वाइप करके हटाना)। इसे पलटा जा सकता है restorePushMessage(id).

लौटाता है: मैसेज छिपाया गया तो true; id अनजान हो या पहले से छिपा हो तो false। ज़रूरत: बिल्ड करते समय इंटीग्रेट चरण (चरण 3) में AppMint Push चालू करें।

5 सेकंड के "पूर्ववत करें" के साथ स्वाइप करके हटाएँ:

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();
  };
}

इनबॉक्स खुलते समय उसे साफ़ रखें, उन मैसेज को छिपाकर जो पढ़े जा चुके हैं और 30 दिन से पुराने हैं:

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();

असली उँगली की स्वाइप से एक पंक्ति हटाएँ (उसे उसकी चौड़ाई के 40% से ज़्यादा खींचें):

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
    }
  });
}

ध्यान दें: सिर्फ़ इस फ़ोन का इनबॉक्स बदलता है। ट्रे का नोटिफ़िकेशन और AppMint में आपका भेजने का इतिहास बना रहता है। छिपाए गए मैसेज इससे नहीं लौटते getPushInbox().

getInAppCampaigns ब्रिज#

window.WebToApk.getInAppCampaigns(): String

इस इंस्टॉल के पास मौजूद इन-ऐप मैसेज: JSON [{id, name}] (AppMint Push के बिना "[]")।

उदाहरण

वे इन-ऐप मैसेज दिखाता है जो यह इंस्टॉल अभी रखता है (AppMint Push सेंड सेंटर के क्रिएटर के कैंपेन, जिनकी ऑडियंस में यह यूज़र है), JSON स्ट्रिंग के रूप में [{"id": "...", "name": "..."}].

लौटाता है: एक JSON ऐरे स्ट्रिंग; कोई न हो तब और AppMint Push के बिना बने ऐप में "[]"। ज़रूरत: बिल्ड करते समय इंटीग्रेट चरण (चरण 3) में AppMint Push चालू हो। सूची हर ऐप शुरू होने पर (और फ़ोरग्राउंड में लगभग हर घंटे) रिफ़्रेश होती है।

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; }));

अपनी एडमिन स्क्रीन में डीबग सूची दिखाएँ:

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'));

अपना स्वागत संकेत तब छोड़ दें जब क्रिएटर उसी नाम का मैसेज पहले से चला रहा हो:

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();

ध्यान दें: सिर्फ़ id और नाम बाहर दिखते हैं; मैसेज ख़ुद पेज तक appmint:inapp इवेंट से पहुँचता है जब वह दिखता है (देखें setInAppPresentation).

getPushInbox ब्रिज#

window.WebToApk.getPushInbox(): String

AppMint Push इनबॉक्स (क्रिएटर के भेजे मैसेज, सबसे नए पहले, ज़्यादा से ज़्यादा 50): {id, title, body, imageUrl, link, receivedAt, read} का JSON ऐरे। हमेशा पूरी मौजूदा सच्चाई - जो ऐप देर से माउंट होता है उसने लाइव `appmint:push` इवेंट छोड़े हों तो भी कुछ नहीं खोता।

उदाहरण

AppMint Push से भेजे पुश मैसेज का इन-ऐप इनबॉक्स पढ़ता है: सबसे नए पहले, 50 तक, यूज़र के हटाए हुए मैसेज के बिना।

लौटाता है: एक JSON स्ट्रिंग, तुरंत। इसे पार्स करें। हर आइटम: { id, title, body, imageUrl, link, receivedAt, read } (receivedAt epoch ms में; मैसेज में न हों तो imageUrl और link की वैल्यू '' होती है), साथ में AppMint में टेम्पलेट इस्तेमाल करने पर वैकल्पिक डिज़ाइन फ़ील्ड: template, accent, iconUrl, buttons: [{label, link}], badge, inapp, countdownAt, progress, lines, collapse। ख़ाली होने पर '[]'। ज़रूरत: बिल्ड करते समय इंटीग्रेट चरण (चरण 3) में AppMint Push चालू करें; इसके बिना इनबॉक्स हमेशा ख़ाली रहता है।

इनबॉक्स दिखाएँ और उसे 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();

जब भी यूज़र ऐप में लौटे, अपनी बेल पर अनपढ़ी गिनती अपडेट करें (बैकग्राउंड में आए मैसेज पहले से इनबॉक्स में हैं):

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();

मैसेज की तस्वीर और उसके बटन दिखाएँ (सिर्फ़ तब जब आपने उन्हें डिज़ाइन में रखा हो), साथ में वह समय जब वह आया:

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)); });
}

ध्यान दें: इनबॉक्स फ़ोन पर रखा जाता है, इसलिए अपनी स्क्रीन खुलते समय उसे पढ़ें - इवेंट सिर्फ़ तब आते हैं जब ऐप स्क्रीन पर हो। AppMint से वापस लिया गया मैसेज इनबॉक्स और ट्रे से ग़ायब हो जाता है। "सिर्फ़ पुश" (ट्रे) के रूप में भेजे मैसेज इनबॉक्स में नहीं जुड़ते। यही जानकारी window.onAppMintPush(detail) को भी दी जाती है अगर आपने उसे बनाया हो।

getPushTags ब्रिज#

window.WebToApk.getPushTags(): String

इस इंस्टॉल के टैग JSON ऑब्जेक्ट स्ट्रिंग के रूप में, जैसे {"plan":"pro"}।

उदाहरण

इस इंस्टॉल के AppMint Push टैग पढ़ता है।

लौटाता है: एक JSON स्ट्रिंग, तुरंत - टेक्स्ट वैल्यू का ऑब्जेक्ट, जैसे '{"plan":"pro","cart":"open"}'; कोई न हो तो '{}'। इसे पार्स करें। ज़रूरत: बिल्ड करते समय इंटीग्रेट चरण (चरण 3) में AppMint Push चालू करें।

एक टैग पढ़ें:

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

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

टैग तभी सेट करें जब वह बदले - हर setPushTag कॉल इंस्टॉल को AppMint Push से चेक-इन कराती है, इसलिए जिनसे कुछ नहीं बदलता उन्हें छोड़ दें:

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');

किसी टैग को भेजने का परीक्षण करते समय उन्हें डीबग स्क्रीन पर सूचीबद्ध करें:

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';
}

ध्यान दें: यह वही है जो फ़ोन के पास है; सेंड सेंटर इसे इंस्टॉल के अगले चेक-इन के बाद देखता है, फ़ोन ऑनलाइन हो तो बदलाव के कुछ सेकंड बाद।

getPushUser ब्रिज#

window.WebToApk.getPushUser(): String

setPushUser से आख़िरी बार सेट की गई यूज़र id (साइन-आउट होने पर या कभी सेट न होने पर "")।

उदाहरण

वह यूज़र id पढ़ता है जो इस इंस्टॉल ने आख़िरी बार AppMint Push को दी थी setPushUser.

लौटाता है: एक string, तुरंत - सेव की हुई id, या '' अगर कोई साइन-इन नहीं है या वह कभी सेट नहीं हुई। ज़रूरत: बिल्ड करते समय इंटीग्रेट चरण (चरण 3) में AppMint Push चालू करें।

id तभी सेट करें जब वह बदली हो (हर ऐप शुरू होने पर):

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

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

पुरानी id साफ़ करें जब आपका अपना सेशन ऐप बंद रहने के दौरान ख़त्म हो गया हो:

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();

किसी एक यूज़र को भेजने का परीक्षण करते समय इसे डीबग स्क्रीन पर दिखाएँ:

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';
}

ध्यान दें: यह वही है जो फ़ोन के पास है। सेंड सेंटर बदलाव को इंस्टॉल के अगले चेक-इन के बाद देखता है, फ़ोन ऑनलाइन हो तो कुछ सेकंड बाद।

markPushRead ब्रिज#

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

एक पुश मैसेज पढ़ा हुआ मार्क करता है; सभी मैसेज पढ़े हुए मार्क करने के लिए "" दें।

उदाहरण

पुश इनबॉक्स का एक मैसेज पढ़ा हुआ मार्क करता है, या सब, जब आप यह दें ''.

लौटाता है: मैसेज बदला तो true; कुछ नहीं बदला तो false (अनजान id, पहले से पढ़ा हुआ, या AppMint Push चालू नहीं)। ज़रूरत: बिल्ड करते समय इंटीग्रेट चरण (चरण 3) में AppMint Push चालू करें।

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) : '';
}

मैसेज को पढ़ा हुआ तब मार्क करें जब यूज़र ने उसे सचमुच स्क्रीन पर देख लिया हो, सिर्फ़ टैप करने पर नहीं:

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); });
}

इनबॉक्स स्क्रीन खुलने पर बैज साफ़ करें, और दोबारा तभी बनाएँ जब सचमुच कुछ अनपढ़ा रहा हो:

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();
  }
}

ध्यान दें: पढ़े जाने की स्थिति सिर्फ़ इसी फ़ोन पर सेव होती है। इससे ट्रे का नोटिफ़िकेशन नहीं हटता।

restorePushMessage ब्रिज#

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

छिपाना पलटें: मैसेज को इनबॉक्स में उसकी जगह पर वापस रख देता है।

उदाहरण

dismissPushMessage(id) को पलटता है: मैसेज पुश इनबॉक्स में अपनी पुरानी जगह पर लौट आता है।

लौटाता है: मैसेज बहाल हुआ तो true; id अनजान हो या मैसेज छिपा न हो तो false। ज़रूरत: बिल्ड करते समय इंटीग्रेट चरण (चरण 3) में AppMint Push चालू करें।

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;
});

कई स्वाइप एक साथ पलटें: इस स्क्रीन पर छिपाए हर मैसेज को याद रखें और सबको वापस ले आएँ:

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();
});

"हाल में छिपाए गए" की एक सूची दें जिससे यूज़र बाद में वापस ला सके। getPushInbox() छिपाए गए मैसेज नहीं लौटाता, इसलिए उनकी id और शीर्षक ख़ुद सँभालकर रखें:

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);
  });
}

ध्यान दें: clearPushInbox() से साफ़ किया गया या AppMint से आपके वापस लिया गया मैसेज बहाल नहीं हो सकता।

setInAppPresentation ब्रिज#

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

इन-ऐप मैसेज की प्रस्तुति: "auto" (डिफ़ॉल्ट) में शेल क्रिएटर का डिज़ाइन बनाता है; "none" (सेव रहता है) हर मैसेज पेज को `appmint:inapp` {type:'shown', presented:false, message} के रूप में सौंप देता है ताकि वह ख़ुद बनाए।

उदाहरण

चुनता है कि इन-ऐप मैसेज (AppMint Push सेंड सेंटर का कैंपेन) को ट्रिगर होने पर कौन बनाए: ऐप ('auto', डिफ़ॉल्ट: क्रिएटर का बैनर, सेंटर कार्ड, बॉटम शीट या फ़ुल-स्क्रीन डिज़ाइन) या आपका अपना पेज ('none').

लौटाता है: मोड सेव हुआ तो true (बदलने तक फ़ोन पर रहता है); किसी और वैल्यू पर और AppMint Push के बिना बने ऐप में false। ज़रूरत: बिल्ड करते समय इंटीग्रेट चरण (चरण 3) में AppMint Push चालू हो।

हर इन-ऐप मैसेज appmint:inapp इवेंट उठाता है (और window.onAppMintInApp(detail) को कॉल करता है अगर आपने उसे बनाया हो) type 'shown', 'clicked', 'dismissed' या 'answered' के साथ (स्टार या 0-10 स्कोर वाला जवाब, question और 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);
});

मैसेज ख़ुद बनाएँ; ऐप हर एक को दिखाने के बजाय आपको सौंप देता है:

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; } };
  }));
};

चुनाव ऐप को वापस दे दें (जैसे किसी सेटिंग्स स्विच से):

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

ध्यान दें: 'none' के साथ, मैसेज पेज को सौंपे जाते ही दिखा हुआ गिना जाता है (उसकी फ़्रीक्वेंसी सीमाएँ लागू होती हैं)। 'none' सेट करने से वह मैसेज भी बंद हो जाता है जिसे ऐप अभी दिखा रहा है। पुश मैसेज का अपना स्विच है, setPushPresentation.

setPushPresentation ब्रिज#

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

पुश मैसेज की नेटिव इन-ऐप प्रस्तुति: "auto" (डिफ़ॉल्ट) में ऐप खुला होने पर शेल क्रिएटर का चुना बैनर / मोडल / शीट / फ़ुल-स्क्रीन कार्ड बनाता है; "none" इसे हमेशा के लिए बंद कर देता है (सेव रहता है) - उन ऐप के लिए जो अपना बनाते हैं। `appmint:push` इवेंट और इनबॉक्स दोनों हाल में अप्रभावित रहते हैं; मिले इवेंट का `presented` फ़्लैग बताता है कि शेल ने उसे दिखाया या नहीं।

उदाहरण

ऐप में AppMint Push मैसेज की ऑन-स्क्रीन प्रदर्शनी को चालू ('auto', डिफ़ॉल्ट) या बंद ('none') करता है - उन ऐप के लिए जो appmint:push इवेंट से अपना बैनर ख़ुद बनाते हैं।

लौटाता है: मोड सेव हुआ तो true; 'auto' या 'none' के अलावा किसी भी वैल्यू पर false। चुनाव फ़ोन पर सेव होता है और बदलने तक रहता है। ज़रूरत: बिल्ड करते समय इंटीग्रेट चरण (चरण 3) में AppMint Push चालू करें।

शेल के बैनर की जगह अपना बैनर बनाएँ:

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);
});

यूज़र को अपनी सेटिंग्स स्क्रीन में पॉप-अप बंद करने दें। इसे पढ़ने का कोई तरीका नहीं है, इसलिए स्विच बनाने के लिए चुनाव की अपनी कॉपी रखें:

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) {}
  }
});

'auto' के साथ जानें कि ऐप के स्क्रीन पर दिखाए मैसेज के साथ यूज़र ने क्या किया: टैप करने पर opened (action मैसेज के लिए -1 है, वरना बटन का इंडेक्स), टैप किए बिना हटाने पर closed:

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 });
  }
});

ध्यान दें: 'auto' के साथ, इन-ऐप स्टाइल में भेजा मैसेज ऐप खुला होने पर उसके ऊपर दिखता है (और तब ट्रे में नहीं डाला जाता)। 'none' के साथ शेल उसे कभी नहीं बनाता; इनबॉक्स (getPushInbox) और appmint:push इवेंट दोनों हाल में एक जैसे काम करते हैं। 'none' सेट करने से वह मैसेज भी बंद हो जाता है जिसे शेल अभी दिखा रहा है।

setPushTag ब्रिज#

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

AppMint Push का एक टैग सेट करता है (key: अक्षर, अंक, _ 32 तक; वैल्यू 128 तक) - सेंड सेंटर "plan = pro" को टारगेट कर सकता है, और ऑटोमेशन टैग सेट होने के कुछ समय बाद चल सकता है (छोड़ी हुई कार्ट: cart=open सेट करें, चेकआउट पर हटा दें)। ख़ाली वैल्यू टैग हटा देती है। हर इंस्टॉल पर 50 टैग तक।

उदाहरण

इस इंस्टॉल पर AppMint Push का एक टैग सेट करता है, जैसे plan = pro या city = pune। सेंड सेंटर (होम > नोटिफ़िकेशन) किसी टैग वाले सभी लोगों को भेज सकता है, और टैग ऑटोमेशन टैग सेट होने के कुछ समय बाद मैसेज भेज सकता है - छोड़ी हुई कार्ट, पूरा हुआ लेवल। ख़ाली वैल्यू टैग हटा देती है।

लौटाता है: सेव होने पर true; false तब जब key 1-32 अक्षरों, अंकों या _ की न हो, वैल्यू 128 अक्षरों से लंबी हो, या इंस्टॉल पर 50 से ज़्यादा टैग हो जाएँ (तब कुछ सेव नहीं होता)। टैग फ़ोन पर रखे जाते हैं और थोड़ी देर बाद AppMint Push को बताए जाते हैं (ऑफ़लाइन होने पर अगली बार ऐप खुलने पर)। ज़रूरत: बिल्ड करते समय इंटीग्रेट चरण (चरण 3) में AppMint Push चालू करें। टैग टारगेटिंग और ऑटोमेशन 30 Sep 2026 से AppMint से बने ऐप चलाने वाले फ़ोन तक पहुँचते हैं।

टैग करें कि यूज़र ने क्या ख़रीदा या चुना, ताकि आप सिर्फ़ "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());

छोड़ी हुई कार्ट: कार्ट में आइटम होने पर टैग सेट करें और चेकआउट पर हटा दें। सेंड सेंटर में cart पर देरी (मान लें 60 मिनट) के साथ टैग ऑटोमेशन जोड़ें; फ़ोन को रिमाइंडर तभी मिलेगा जब समय पूरा होने पर cart अब भी सेट हो:

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
}

साइन-आउट पर यूज़र के अपने टैग साफ़ करें, यूज़र id के साथ:

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

ध्यान दें: टैग इस इंस्टॉल के हैं, साइन-इन यूज़र के नहीं। किसी टैग को वही वैल्यू देने से सर्वर पर कुछ नहीं बदलता। टैग हटाने के बाद उसे दोबारा सेट करने पर टैग ऑटोमेशन एक बार फिर भेज सकता है। टैग में कभी ईमेल पता, फ़ोन नंबर या कुछ भी निजी न रखें।

setPushTags ब्रिज#

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

JSON ऑब्जेक्ट स्ट्रिंग से एक साथ कई टैग सेट करता है; "" वाली वैल्यू हट जाती हैं।

उदाहरण

JSON ऑब्जेक्ट स्ट्रिंग से एक साथ कई AppMint Push टैग सेट करता है, जैसे '{"plan":"pro","team":"red"}'। "" वैल्यू उस टैग को हटा देती है; जिन टैग का आप नाम नहीं लेते वे बने रहते हैं।

लौटाता है: सेव होने पर true; false तब जब स्ट्रिंग JSON ऑब्जेक्ट न हो, कोई key 1-32 अक्षरों, अंकों या _ की न हो, कोई वैल्यू 128 अक्षरों से लंबी हो, या इंस्टॉल पर 50 से ज़्यादा टैग हो जाएँ - तब कुछ भी सेव नहीं होता। ज़रूरत: बिल्ड करते समय इंटीग्रेट चरण (चरण 3) में AppMint Push चालू करें। टैग टारगेटिंग और ऑटोमेशन 30 Sep 2026 से AppMint से बने ऐप चलाने वाले फ़ोन तक पहुँचते हैं।

साइन-इन के बाद, एक ही कॉल में प्रोफ़ाइल को टैग करें:

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
  }));
}

साइन-आउट पर, सबको हटा दें (मौजूदा टैग पढ़ें, हर एक को वापस भेजें ''):

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('');
}

लेवल पूरा हुआ: उसे टैग करें, और level_done पर टैग ऑटोमेशन (मान लें 10 मिनट) अगली चुनौती भेजने दें:

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)
  }));
}

ध्यान दें: एक कॉल एक बदलाव है: या तो सब सेव होता है या कुछ नहीं। इंस्टॉल नए टैग थोड़ी देर बाद AppMint Push को बताता है (ऑफ़लाइन होने पर अगली बार ऐप खुलने पर)।

setPushUser ब्रिज#

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

AppMint Push ऑडियंस: क्रिएटर के सेंड सेंटर को बताता है कि यह इंस्टॉल कौन है, ताकि मैसेज किसी एक साइन-इन यूज़र ("u_42") को या किसी टैग वाले सभी को जा सके। साइन-इन के बाद अपनी स्थिर अकाउंट id के साथ इसे कॉल करें; साइन-आउट पर "" दें। अक्षर, अंक और _ @ . : + - (128 तक)। इसके अलावा कुछ भी हो तो false लौटाता है, और उस ऐप में भी जो AppMint Push इस्तेमाल नहीं करता (OneSignal / अपना Firebase: कुछ नहीं भेजा जाता, 2026-10-03)। कभी ईमेल पता या फ़ोन नंबर न दें - अपने डेटाबेस की id इस्तेमाल करें।

उदाहरण

AppMint Push को बताता है कि इस फ़ोन पर आपका कौन सा यूज़र साइन-इन है, ताकि सेंड सेंटर (होम > नोटिफ़िकेशन) उसी एक यूज़र को मैसेज भेज सके। साइन-इन के बाद अपनी स्थिर अकाउंट id के साथ कॉल करें; साइन-आउट पर '' के साथ कॉल करें।

लौटाता है: id सेव होने पर true; ऐसी id पर false जिसमें अक्षरों, अंकों और _ @ . : + - के अलावा कुछ और हो, या जो 128 अक्षरों से लंबी हो (तब कुछ सेव नहीं होता)। id फ़ोन पर तब तक रहती है जब तक आप उसे बदल न दें, और यह इंस्टॉल उसे थोड़ी देर बाद AppMint Push को बताता है (ऑफ़लाइन होने पर अगली बार ऐप खुलने पर)। ज़रूरत: बिल्ड करते समय इंटीग्रेट चरण (चरण 3) में AppMint Push चालू करें। किसी यूज़र को भेजना 30 Sep 2026 से AppMint से बने ऐप चलाने वाले फ़ोन तक पहुँचता है; पुराने बिल्ड को अब भी सिर्फ़ "सभी" को भेजे मैसेज मिलते हैं।

साइन-इन के बाद और साइन-आउट पर - अपने डेटाबेस की id इस्तेमाल करें, कभी ईमेल पता या फ़ोन नंबर नहीं:

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: सेशन को फ़ॉलो करें, ताकि बहाल किया सेशन भी नए साइन-इन की तरह गिना जाए:

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);
});

id को स्वीकार्य बनाएँ जब आपकी id में दूसरे अक्षर हो सकते हों (स्पेस, /, #), और जो कभी-कभार फिर भी नामंज़ूर हो उसे लॉग करें:

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);
}

ध्यान दें: दो फ़ोन पर साइन-इन एक ही यूज़र दोनों पर पहुँचा जाता है। id इस इंस्टॉल की है, अकाउंट की नहीं - साइन-आउट पर उसे साफ़ करना ज़रूरी है, वरना फ़ोन पिछले यूज़र के मैसेज पाता रहेगा। setPushUser('') उन टैग को साफ़ नहीं करता जो setPushTag से सेट हुए हैं; साइन-आउट पर यूज़र के अपने टैग भी साफ़ करें।

trackEvent ब्रिज#

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

इन-ऐप मैसेज: एक ऐसा इवेंट बताता है जिस पर क्रिएटर के कैंपेन ट्रिगर हो सकते हैं ("event" ट्रिगर, वही नाम)। propsJson वैकल्पिक JSON है। {"path":"/x"} के साथ नाम `appmint:route` ऐसा व्यू बदलाव बताता है जो URL में नहीं दिखता। [A-Za-z0-9_.:-]{1,64} से बाहर के नाम पर, और AppMint Push के बिना, False।

उदाहरण

ऐप को बताता है कि कुछ हुआ है ("signed_up", "checkout_done", "level:3")। क्रिएटर ने AppMint Push सेंड सेंटर में ट्रिगर "जब कोई इवेंट हो" और वही नाम रखकर जो इन-ऐप मैसेज बनाया है, वह अभी दिखता है (या क्रिएटर के चुने इंतज़ार के बाद)।

लौटाता है: इवेंट लिया गया तो true; ऐसे नाम पर false जिसमें अक्षरों, अंकों और _ . : - (64 तक) के बाहर कुछ हो, और AppMint Push के बिना बने ऐप में भी। AppMint.trackEvent(name, props) वही कॉल है जिसमें props एक ऑब्जेक्ट है। ज़रूरत: बिल्ड करते समय इंटीग्रेट चरण (चरण 3) में AppMint Push चालू हो। propsJson वैकल्पिक है ('') और कहीं सेव नहीं होता।

// 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 });
  }
}

सीधा ब्रिज props को JSON स्ट्रिंग के रूप में लेता है (कुछ न हो तो '' दें):

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 });

ऐसा स्क्रीन बदलाव जो पते में नहीं दिखता (टैब, विज़ार्ड, मॉडल "पेज") रूट के रूप में बताया जा सकता है, ताकि क्रिएटर के "किसी पेज पर" मैसेज उसे देख सकें। पेज पाथ के साथ appmint:route इवेंट भी भेज सकता है; ऐप उसे सुनता है:

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' } }));

ध्यान दें: रूट वाले मैसेज असली URL बदलावों (पेज लोड, history.pushState, #/hash रूट) को अपने आप फ़ॉलो करते हैं; रूट सिर्फ़ उन व्यू के लिए बताएँ जिनमें पता नहीं बदलता। इवेंट कहीं गिने या सेव नहीं होते; वे सिर्फ़ तय करते हैं कि कोई मैसेज दिखे या नहीं।

हर डॉक्स बिल्ड पर ऐप रनटाइम और उसकी उदाहरण फ़ाइलों से बनाया जाता है। Markdown में पढ़ें · सभी फ़ैमिली.

2026-10-03 को शिप किए गए ब्रिज से मिलाकर जाँचा गया।