Crea APK gratis

API del bridge JavaScript

Avvio, scorciatoie e tasto indietro

Come è stata aperta l'app, le scorciatoie con pressione prolungata sull'icona, la richiesta di recensione in-app e come dire alla shell che la pagina vuole gestire il tasto indietro.

AppMint.requestReview helper#

AppMint.requestReview(options)

Esempio

Chiede a Google Play di mostrare la sua scheda di valutazione dentro l'app (Play In-App Review) e ti dice cosa è successo.

Restituisce: una Promise che si risolve sempre {result, openedStore, message?}. result è 'shown' (Play ha mostrato la sua schermata, ma non dice mai se l'utente ha lasciato una valutazione), 'not_from_play' (questa installazione non proviene da Google Play: un APK installato manualmente o un'installazione di test, dove Play non mostra mai la schermata), 'quota' (Play ha scelto di non mostrarla ora: la sua quota per questo utente, oppure ha già lasciato una recensione) o 'error' (non è stato possibile interpellare Play: nessun Play Store, offline). Con {openStore: true} la scheda dell'app su Play si apre quando la schermata non è stata mostrata, e openedStore è true. Richiede: nulla da attivare.

Qualsiasi codice:

// A "Rate us" button: the sheet when Play shows it, the Play listing otherwise.
document.getElementById('rate-btn').onclick = async function () {
  if (!(window.AppMint && AppMint.requestReview)) { location.href = 'https://play.google.com/store/apps/details?id=com.example.app'; return; }
  var r = await AppMint.requestReview({ openStore: true });
  if (r.result === 'shown' || r.openedStore) showToast('Thank you!');
};

Chiedi dopo un momento di successo invece che da un pulsante, senza mai uscire dall'app:

async function onOrderDelivered(count) {
  if (count !== 3 || !(window.AppMint && AppMint.requestReview)) return;
  var r = await AppMint.requestReview();      // no openStore: nothing opens if Play says no
  if (r.result === 'not_from_play') console.log('Test install: Play only shows the sheet for Play installs');
}

Quando il creatore ha attivato Chiedi agli utenti di valutare l'app (passaggio Visualizzazione), l'app lo chiede da sola in un momento tranquillo e dice alla pagina cosa è successo:

window.addEventListener('appmint:review', function (e) {
  // e.detail = { result, openedStore: false, source: 'auto' }
  analytics.track('rate_prompt', { result: e.detail.result });
});

Note: Google Play limita la frequenza del pannello e decide da solo se compare; non premiare mai una recensione né promettere il pannello su un pulsante. Provalo con un'installazione da Play su una traccia di test interno - un APK installato a mano risponde sempre not_from_play.

Senza codice: il link appmint://review. Un pulsante o un link con questo indirizzo chiede lo stesso pannello (e apre la scheda su Play quando Play non lo mostra, perché l'utente ha chiesto di valutare). In un messaggio in-app, mettilo su un pulsante nel centro di invio (lo fa il modello Valutaci); in una pagina, usalo come semplice link:

<a href="appmint://review" class="rate-link">Rate us on Google Play</a>

Da script, per esempio dopo il terzo ordine completato:

function maybeAskForRating(ordersDone) {
  if (ordersDone === 3) location.href = 'appmint://review';   // the app runs it; nothing is loaded
}

Scopri cosa ha scelto l'utente in un messaggio in-app «Valutaci» prima che il pannello si apra:

window.addEventListener('appmint:inapp', function (e) {
  var d = e.detail;
  if (d.type === 'answered' && d.question === 'stars' && d.value <= 3) showFeedbackForm();
  if (d.type === 'clicked' && d.link === 'appmint://review') console.log('Opening the Play review sheet');
});

AppMint.setBackHandler helper#

AppMint.setBackHandler(handler)

Esempio

Dà alla tua pagina la prima parola quando l'utente preme il tasto Indietro del telefono (o usa il gesto indietro). Serve alle app che cambiano schermata mostrando e nascondendo elementi, dove la cronologia di Android è vuota e Indietro farebbe uscire dall'app.

Restituisce: niente. Il tuo handler deve restituire true (gestito, resta qui) oppure false (lascia che l'app torni indietro / esca). Richiede: niente. Installato all'avvio del documento, quindi puoi registrarlo nel tuo primo script.

if (window.AppMint && AppMint.setBackHandler) {
  AppMint.setBackHandler(function () {
    if (isMenuOpen)               { closeMenu();  return true; }   // consumed
    if (currentScreen !== 'home') { goTo('home'); return true; }
    return false;   // nothing to undo: normal Back (history back, exit dialog, exit)
  });
}

// Remove it again, for example when the screen that needed it closes:
// AppMint.setBackHandler(null);

L'evento appmint:back - annullabile. Chiama e.preventDefault() per consumare la pressione. Viene eseguito prima del gestore, e qualsiasi numero di listener può usarlo:

window.addEventListener('appmint:back', function (e) {
  var sheet = document.querySelector('.bottom-sheet.open');
  if (sheet) {
    sheet.classList.remove('open');
    e.preventDefault();   // consumed: the handler and the shell do nothing more
  }
});

Evita di perdere una nota scritta a metà: Indietro mostra la tua barra «Scartare le modifiche?» invece di uscire (un confirm() bloccante mancherebbe la finestra di risposta di 350 ms, quindi la shell tornerebbe indietro comunque):

if (window.AppMint && AppMint.setBackHandler) {
  var noteDirty = false;
  document.getElementById('note').addEventListener('input', function () { noteDirty = true; });

  AppMint.setBackHandler(function () {
    if (!noteDirty) return false;        // nothing to lose: normal Back
    showDiscardBar();                    // your in-page "Discard changes? / Keep editing" bar
    return true;                         // stay here while the user decides
  });

  document.getElementById('discard-btn').onclick = function () {
    noteDirty = false;                   // the next Back press passes straight through
    hideDiscardBar();
    closeEditor();
  };
}

Note: La risposta deve essere sincrona: restituire una Promise conta come «non gestito». Rispondi in fretta - se la pagina non risponde entro circa 350 ms, la shell torna indietro da sola. Ordine a ogni pressione: un menu laterale aperto (il drawer dell'app) si chiude per primo e la pagina non viene interrogata; poi i listener appmint:back → il tuo gestore → il chiuditore di dialoghi integrato della shell (chiude un <dialog> aperto, un dialogo ARIA o un modale a schermo intero) → indietro nella cronologia / conferma di uscita / uscita. Le app che usano history.pushState per ogni schermata (React Router e simili) non ne hanno bisogno. Le app create con l'AI possono usare onBackGesture da @/lib/appmintNative.

__pullRefreshEligible bridge#

window.WebToApk.__pullRefreshEligible(eligible: Boolean)

Vedi [pullPageEligible] / [pullProbeJs]. Chiamata a ogni touchstart.

Esempio

Meccanismo interno dietro il pull-to-refresh: la sonda tattile della shell lo chiama a ogni tocco per sapere se un trascinamento verso il basso in quel punto deve aggiornare la pagina. Le pagine non lo chiamano mai - controllano il pull-to-refresh con CSS e gli eventi touch standard.

Restituisce: niente. Richiede: Abilita il pull-to-refresh attivato nel Passaggio 3 (Integrazione), sotto Opzioni di visualizzazione, quando crei l'app (senza, la sonda non viene installata).

Il modo pubblico per impedire che il tira-per-aggiornare agisca su una parte della tua pagina: rivendica il gesto:

<style>
  /* A map, drawing canvas or slider: this element owns vertical drags. */
  #map, #canvas { touch-action: none; }
  /* A horizontal carousel: pan-x also tells the shell "not a refresh". */
  .carousel { touch-action: pan-x; }
</style>

Oppure rivendicalo da un gestore del tocco, nel modo standard:

document.getElementById('canvas').addEventListener('touchstart', function (e) {
  e.preventDefault();   // the page took this gesture: no pull-to-refresh
}, { passive: false });

Impedisci a una superficie con pan e zoom di aggiornare la pagina rivendicando i trascinamenti verticali solo con CSS:

<div id="board" style="touch-action: none; height: 60vh"></div>
<script>
  // Dragging on #board moves the board; a pull from the top of the rest of the page still refreshes.
  document.getElementById('board').addEventListener('pointermove', function (e) { moveBoard(e); });
</script>

Note: Un trascinamento aggiorna solo quando il box scorrevole più vicino sotto il dito (o la pagina stessa) è scorso in cima, c'è un solo dito appoggiato e nessuna delle richieste sopra si applica. Un tocco dentro un iframe di un'altra origine non aggiorna mai. Non chiamare tu stesso questo metodo.

getAppIcon bridge#

window.WebToApk.getAppIcon(): String

L'icona del launcher in uso: "default" o uno dei nomi di getAvailableIcons().

Esempio

L'icona del launcher in uso: 'default' o uno dei nomi di getAvailableIcons().

Restituisce: una stringa. 'default' in una build senza icone alternative.

if (window.WebToApk && WebToApk.getAppIcon) {
  const current = WebToApk.getAppIcon();          // 'default', 'Dark', …
  document.querySelectorAll('[data-icon]').forEach(el => {
    el.classList.toggle('selected', el.dataset.icon === current);
  });
}

Passa all'icona successiva da una schermata di impostazioni:

function nextIcon() {
  if (!(window.WebToApk && WebToApk.getAvailableIcons && WebToApk.setAppIcon)) return;
  const names = JSON.parse(WebToApk.getAvailableIcons());
  if (names.length < 2) return;                                  // no alternate icons in this build
  const next = names[(names.indexOf(WebToApk.getAppIcon()) + 1) % names.length];
  if (!WebToApk.setAppIcon(next)) alert('Could not change the icon.');
}

Mostra il nome dell'icona in un'etichetta, oppure nascondilo fuori dall'app:

const label = document.getElementById('icon-label');
if (window.WebToApk && WebToApk.getAppIcon) {
  const name = WebToApk.getAppIcon();
  label.textContent = name === 'default' ? 'Classic icon' : name + ' icon';
} else {
  label.hidden = true;           // in a browser there is no launcher icon
}

getAvailableIcons bridge#

window.WebToApk.getAvailableIcons(): String

Array JSON dei nomi di icona che setAppIcon accetta: prima "default", poi le alternative della build.

Esempio

I nomi di icona che setAppIcon accetta, come stringa di array JSON: prima 'default', poi le icone alternative della procedura guidata di build nell'ordine in cui le hai aggiunte.

Restituisce: '["default","Dark","Gold"]', oppure '["default"]' in una build senza icone alternative.

Crea un selettore di icone:

function iconPicker(container) {
  if (!(window.WebToApk && WebToApk.getAvailableIcons)) return;
  const names = JSON.parse(WebToApk.getAvailableIcons());
  if (names.length < 2) { container.hidden = true; return; }   // nothing to choose
  const current = WebToApk.getAppIcon();
  container.innerHTML = '';
  names.forEach(name => {
    const b = document.createElement('button');
    b.textContent = name === 'default' ? 'Classic' : name;
    b.className = name === current ? 'selected' : '';
    b.onclick = () => { if (WebToApk.setAppIcon(name)) iconPicker(container); };
    container.appendChild(b);
  });
}
iconPicker(document.querySelector('#iconPicker'));

Nascondi il selettore in una build senza icone alternative:

const picker = document.getElementById('iconPicker');
let names = ['default'];
if (window.WebToApk && WebToApk.getAvailableIcons) names = JSON.parse(WebToApk.getAvailableIcons());
picker.hidden = names.length < 2;      // only 'default' means there is nothing to choose

Cambia l'icona con il tema:

function matchIconToTheme(dark) {
  if (!(window.WebToApk && WebToApk.getAvailableIcons && WebToApk.setAppIcon)) return;
  const names = JSON.parse(WebToApk.getAvailableIcons());
  const wanted = dark ? 'Dark' : 'default';
  if (names.includes(wanted) && WebToApk.getAppIcon() !== wanted) WebToApk.setAppIcon(wanted);
}
matchIconToTheme(matchMedia('(prefers-color-scheme: dark)').matches);

getLaunchUrl bridge#

window.WebToApk.getLaunchUrl(): String

Il deep link che ha avviato o riaperto l'app, oppure "" se è stata aperta normalmente. Leggilo ogni volta che la tua app viene montata e indirizza tu stesso: const u = window.WebToApk?.getLaunchUrl?.(); if (u) router.navigate(new URL(u).pathname); Il valore viene CONSERVATO, non consumato, quindi un'app montata in ritardo lo vede comunque; un link successivo che arriva mentre l'app è in esecuzione lo sostituisce e fa scattare anche 'appmint:deep-link'.

Esempio

Il deep link che ha aperto (o riaperto) l'app, come stringa, oppure "" quando l'app è stata aperta normalmente.

Restituisce: una stringa, in modo sincrono. Richiede: niente. Il valore viene conservato, non consumato, quindi è sicuro leggerlo ogni volta che la tua app viene montata.

Un link può arrivare in tre forme: https://yoursite.com/path, il appmint-shortcut://<package>/<route> proprio della shell (scorciatoie del launcher, widget della schermata iniziale), oppure il tuo schema personalizzato myapp://segment/path. Questa funzione le trasforma tutte e tre in una route:

function routeOf(link) {
  var m = /^([a-z][a-z0-9+.-]*):\/\/([^\/?#]*)([^#]*)/i.exec(link || '');
  if (!m) return '/';
  var scheme = m[1].toLowerCase(), host = m[2], rest = m[3] || '';
  if (scheme === 'http' || scheme === 'https' || scheme === 'appmint-shortcut') return rest || '/';
  return '/' + host + rest;               // myapp://product/42 -> /product/42
}

// 1. On start: the link that launched the app.
if (window.WebToApk && typeof window.WebToApk.getLaunchUrl === 'function') {
  var link = window.WebToApk.getLaunchUrl();
  if (link) goTo(routeOf(link));
}

// 2. While running: a new link replaces the old one and fires 'appmint:deep-link'.
window.addEventListener('appmint:deep-link', function (e) {
  goTo(routeOf(e.detail.url));            // detail: { url }
});

Lo stesso annuncio viene passato anche a un hook globale, se ne preferisci uno solo:

window.onAppMintDeepLink = function (detail) { goTo(routeOf(detail.url)); };

Leggi un codice di invito da un link come https://yoursite.com/invite?code=AB12 o myapp://invite?code=AB12, una sola volta per link (usa routeOf da sopra):

function applyInvite(link) {
  if (!link) return;
  var done = '';
  try { done = sessionStorage.getItem('handledLink') || ''; } catch (e) {}
  if (link === done) return;                      // the same url is announced again after a reload
  try { sessionStorage.setItem('handledLink', link); } catch (e) {}
  var code = null;
  try { code = new URL(link).searchParams.get('code'); } catch (e) { return; }
  if (code && routeOf(link).indexOf('/invite') === 0) showInviteBanner(code);
}

if (window.WebToApk && typeof window.WebToApk.getLaunchUrl === 'function') {
  applyInvite(window.WebToApk.getLaunchUrl());
  window.addEventListener('appmint:deep-link', function (e) { applyInvite(e.detail.url); });
}

Note: appmint:deep-link viene lanciato anche dopo ogni caricamento di pagina finché un link viene conservato, quindi lo stesso url può arrivare più di una volta. Ignora un link che hai già gestito.

Le app in modalità sito web sono diverse: la shell stessa carica un link https:// in arrivo (all'avvio da zero e mentre è in esecuzione), e un link con schema personalizzato myapp://product/42 viene prima riscritto sull'indirizzo del tuo sito (https://yoursite.com/product/42), quindi getLaunchUrl() restituisce la forma https:// e la tua pagina di solito non ha nulla da indirizzare. Una scorciatoia del launcher o un tocco su un widget apre la sua route sul tuo sito (/today carica https://yoursite.com/today), e getLaunchUrl() restituisce comunque la forma appmint-shortcut:// (vedi setAppShortcuts). Nelle app HTML, ZIP e create con l'AI (servite dall'interno dell'app) la shell non naviga mai: la tua pagina riceve il link e lo indirizza. Un link con schema personalizzato resta com'è arrivato lì, perché non c'è un indirizzo del sito su cui mapparlo. Le app create con l'AI possono usare launchUrl() da @/lib/appmintNative.

rateApp bridge#

window.WebToApk.rateApp(): String

Apre il flusso di valutazione della scheda Play. `rateApp()` esisteva già ma solo la voce del drawer nativo poteva raggiungerla, quindi un'app che disegna una propria interfaccia - ogni build con AI, dove il drawer è disattivato - non aveva modo di chiedere una valutazione. È l'unica azione dello store che una pagina non può davvero eseguire da sola: `market://` è un intent, non un URL navigabile. Controllata dall'interruttore «Pulsante Valuta l'app» del creatore, esattamente come la voce del drawer e la voce Condividi della navigazione in basso: disattivare Valuta deve significare nessuna superficie di valutazione da nessuna parte, altrimenti l'interruttore sembra rotto.

Esempio

Apre la pagina dell'app su Google Play così l'utente può valutarla.

Restituisce: 'opened' quando la scheda è stata aperta, 'off' quando il creatore ha disattivato Valuta l'app (allora non succede nulla). Richiede: l'interruttore Pulsante Valuta l'app nel Passaggio 5 (Menu) quando crei l'app (è attivo per impostazione predefinita; aggiunge anche una voce «Valuta l'app» al menu laterale). Se è disattivato, la chiamata non fa nulla e restituisce 'off'. Per il pannello di valutazione in-app di Google Play usa AppMint.requestReview().

var rateBtn = document.getElementById('rate-btn');
if (window.WebToApk && typeof window.WebToApk.rateApp === 'function') {
  rateBtn.onclick = function () { window.WebToApk.rateApp(); };
} else {
  rateBtn.hidden = true;   // in a browser
}

Offri la valutazione una sola volta, dopo che l'utente ha finito cinque allenamenti, da una scheda che tocca:

function maybeOfferRating(completedCount) {
  if (!window.WebToApk || typeof window.WebToApk.rateApp !== 'function') return;
  var asked = false;
  try { asked = localStorage.getItem('rateAsked') === '1'; } catch (e) {}
  if (asked || completedCount < 5) return;

  var card = document.getElementById('rate-card');   // "Enjoying the app? Rate it on Google Play"
  card.hidden = false;
  card.querySelector('.rate-yes').onclick = function () {
    window.WebToApk.rateApp();                         // opens the Play listing
    try { localStorage.setItem('rateAsked', '1'); } catch (e) {}
    card.hidden = true;
  };
  card.querySelector('.rate-later').onclick = function () { card.hidden = true; };
}

Una riga «Valutaci» nella tua schermata delle impostazioni che dice grazie quando l'utente torna da Google Play (il ritorno della pagina in primo piano è l'unico segnale che l'utente è tornato):

document.getElementById('settings-rate').onclick = function () {
  if (!window.WebToApk || typeof window.WebToApk.rateApp !== 'function') return;
  window.WebToApk.rateApp();
  document.addEventListener('visibilitychange', function onBack() {
    if (document.visibilityState !== 'visible') return;
    document.removeEventListener('visibilitychange', onBack);
    showToast('Thanks for taking a look!');           // your own toast; the user may not have rated
  });
};

Note: Apre la scheda su Play Store (market://details?id=<package>), oppure il sito di Play quando l'app Play Store non è presente. Non è la scheda di recensione dentro l'app. Una pagina non può aprire market:// da sola: è un intent Android, non un indirizzo web. Chiedi solo dopo che l'utente ha fatto qualcosa che gli è piaciuto, e a partire da un tocco.

requestReview bridge#

window.WebToApk.requestReview(optionsJson: String, callbackId: String)

Chiede a Play la sua schermata di recensione; [optionsJson] `{openStore?}`. Si risolve AppMint.requestReview [callbackId].

Esempio

Meccanismo interno dietro AppMint.requestReview() - le pagine usano quell'helper basato su Promise, che chiede a Google Play la sua scheda di recensione in-app e si risolve con quello che è successo.

Restituisce: niente direttamente; l'esito risolve la promise di AppMint.requestReview(). Richiede: niente da attivare. Il pannello compare solo per un'app installata da Google Play.

L'API pubblica:

async function askForRating() {
  if (!(window.AppMint && AppMint.requestReview)) return;          // a browser: no store here
  var r = await AppMint.requestReview();
  console.log(r.result);   // 'shown' | 'not_from_play' | 'quota' | 'error'
}

Chiedi dopo un buon momento e chiedi la pagina dello store quando il pannello non compare:

async function afterHappyMoment() {
  if (!(window.AppMint && AppMint.requestReview)) return;
  const r = await AppMint.requestReview({ openStore: true });   // {result, openedStore, message?}
  if (r.result === 'shown') thankUser();
  else if (r.openedStore) console.log('Opened the Play listing instead');
}

Ascolta la richiesta automatica e segnala un errore:

window.addEventListener('appmint:review', (e) => {
  if (e.detail.source === 'auto') console.log('Rate prompt result:', e.detail.result);
});

AppMint.requestReview().then((r) => {
  if (r.result === 'error') console.warn(r.message);
  if (r.result === 'not_from_play') showMessage('Rating is available once the app is installed from Google Play.');
});

setAppIcon bridge#

window.WebToApk.setAppIcon(name: String): Boolean

Cambia l'icona del launcher dell'app con una delle icone alternative aggiunte nella procedura guidata di build, con il nome indicato lì («default» = l'icona normale). Restituisce false per un nome che questa build non ha. Il launcher ridisegna i suoi tempi (alcuni secondi su certi telefoni), e alcuni launcher chiudono l'app o spostano la sua icona nella schermata iniziale quando cambia - cambia da una schermata di impostazioni, non nel mezzo di un'attività.

Esempio

Cambia l'icona del launcher dell'app con una delle icone alternative aggiunte nella procedura guidata di build (passaggio Base, «Icone alternative dell'app»), con il nome che le hai dato lì. 'default' è la tua icona normale.

Restituisce: true quando il cambio è avvenuto (o è già quell'icona), false per un nome che questa build non ha. Richiede: icone alternative aggiunte nella procedura guidata (fino a 4). Alcuni launcher impiegano qualche secondo per ridisegnare l'icona, e alcuni chiudono l'app o spostano la sua scorciatoia nella schermata iniziale quando cambia: cambia da una schermata di impostazioni, non nel mezzo di un'attività. Le tue scorciatoie del launcher (setAppShortcuts) vengono ripubblicate automaticamente con la nuova icona.

function useIcon(name) {
  if (!(window.WebToApk && window.WebToApk.setAppIcon)) return false;
  const ok = WebToApk.setAppIcon(name);
  if (!ok) console.warn('no icon called', name);
  return ok;
}

document.querySelector('#darkIcon').addEventListener('click', () => useIcon('Dark'));
document.querySelector('#normalIcon').addEventListener('click', () => useIcon('default'));

Crea il selettore dalle icone che ha questa build:

if (window.WebToApk && WebToApk.getAvailableIcons) {
  const names = JSON.parse(WebToApk.getAvailableIcons());   // 'default' first, then your alternates
  const current = WebToApk.getAppIcon();
  names.forEach((n) => addRadio('icon', n, n === current, () => WebToApk.setAppIcon(n)));
}

Controlla la risposta per un nome che la build non ha:

function pickIcon(name) {
  if (!(window.WebToApk && WebToApk.setAppIcon)) return showMessage('Icons can be changed in the app only');
  if (!WebToApk.setAppIcon(name)) {
    showMessage('Unknown icon "' + name + '". Choose one of: ' + JSON.parse(WebToApk.getAvailableIcons()).join(', '));
  } else {
    showMessage('Done. Your launcher may take a few seconds to redraw the icon.');
  }
}

Note: il primo aggiornamento che AGGIUNGE icone alternative sposta la voce del launcher su un nuovo componente, quindi una scorciatoia della schermata iniziale creata prima di quell'aggiornamento potrebbe dover essere rimessa.

setAppShortcuts bridge#

window.WebToApk.setAppShortcuts(itemsJson: String)

Scorciatoie del launcher (pressione prolungata sull'icona dell'app). Fino a quattro voci: `[{id, title, route}]`, dove `route` è un percorso nell'app ('/new-note'). Un tocco apre l'app con quella route come deep link di avvio (`appmint-shortcut://<package><route>`), che la pagina legge tramite `getLaunchUrl()` e indirizza esattamente come qualsiasi altro deep link. In un'app in modalità sito web è la shell stessa ad aprire la route sul sito (`/new-note` → `https://<site>/new-note`). Passa `[]` per rimuoverle. Android 7.1+; nessun effetto sotto.

Esempio

Imposta le scorciatoie del launcher che compaiono quando l'utente tiene premuta l'icona dell'app.

Restituisce: niente. Richiede: niente. Android 7.1+ (nessun effetto sotto).

itemsJson è una stringa JSON: un array di fino a quattro oggetti {id, title, route}. route è un percorso dentro la tua app. Un tocco apre l'app con appmint-shortcut://<package><route> come link di avvio:

if (window.WebToApk && typeof window.WebToApk.setAppShortcuts === 'function') {
  window.WebToApk.setAppShortcuts(JSON.stringify([
    { id: 'new-note', title: 'New note', route: '/new-note' },
    { id: 'search',   title: 'Search',   route: '/search' }
  ]));
}

Leggi il tocco come qualsiasi altro deep link, all'avvio e mentre l'app è in esecuzione:

function shortcutRoute(link) {
  var m = /^appmint-shortcut:\/\/[^\/?#]*([^#]*)/i.exec(link || '');
  return m ? (m[1] || '/') : null;
}
if (window.WebToApk && window.WebToApk.getLaunchUrl) {
  var r = shortcutRoute(window.WebToApk.getLaunchUrl());
  if (r) goTo(r);
}
window.addEventListener('appmint:deep-link', function (e) {
  var r = shortcutRoute(e.detail.url);
  if (r) goTo(r);
});

Rimuovi tutte le scorciatoie:

if (window.WebToApk && window.WebToApk.setAppShortcuts) window.WebToApk.setAppShortcuts('[]');

Note: Ogni chiamata sostituisce l'intero elenco. Le voci senza title vengono saltate; l'etichetta viene tagliata a 25 caratteri (50 per quella lunga). id per impostazione predefinita è appmint-<index>. Un percorso senza / iniziale ne riceve uno. L'icona è quella dell'app. Un elenco malformato viene ignorato (registrato nel log), mai generato come errore. Le app create con l'AI possono usare shortcuts da @/lib/appmintNative. App in modalità sito web: un tocco apre il percorso sul tuo sito: /new-note carica https://<your site>/new-note e getLaunchUrl() restituisce comunque il link appmint-shortcut://, così una pagina che gestisce da sola i percorsi continua a funzionare.

Generato dal runtime dell'app e dai suoi file di esempio a ogni build della documentazione. Leggilo in Markdown · Tutte le famiglie.

Verificato rispetto al bridge distribuito il 22/10/2026.