Créer un APK gratuit

API du pont JavaScript

Partage, presse-papiers et impression

La feuille de partage d'Android, le presse-papiers système, le texte qu'une autre application a partagé vers la vôtre, et la boîte de dialogue d'impression.

AppMint.pdf assistant#

AppMint.pdf.fromPage(options) / fromHtml(html, options)

Exemple

Crée un vrai PDF (texte sélectionnable, graphiques vectoriels) sans boîte de dialogue d'impression : fromPage enregistre la page telle qu'elle est à l'écran, mise en page avec votre CSS @media print ; fromHtml génère le HTML que vous transmettez dans une page invisible à l'adresse de l'application, de sorte que les images, feuilles de style et polices relatives se chargent comme dans votre page, attend les polices et toutes les images, puis l'enregistre. window.print() ouvre toujours la boîte de dialogue d'impression habituelle.

Renvoie : une Promise de {ok: true, fileName, pages, bytes, saved, uri?, base64?} ou {ok: false, code, message} : code vaut busy (un seul PDF à la fois), bad-options, failed, too-large (base64 de plus de 25 Mo) ou permission-denied (stockage refusé sur Android 7-9). Nécessite : rien : toutes les compilations l'ont. L'enregistrement dans Téléchargements ne nécessite aucune autorisation sur Android 10+.

Options : fileName (« .pdf » est ajouté ; par défaut : le titre de la page), pageSize 'A4' (par défaut) | 'Letter' | 'Legal' | 'A3' | 'A5', landscape (true/false), margins en millimètres (un nombre, ou {top, right, bottom, left} ; omis = votre propre règle @page), save 'downloads' (par défaut) | 'share' | 'base64'.

Enregistrer la page actuelle dans Téléchargements :

async function saveInvoice() {
  if (!(window.AppMint && AppMint.pdf)) { window.print(); return; }   // in a browser
  var r = await AppMint.pdf.fromPage({ fileName: 'invoice-1042', pageSize: 'A4', margins: 12 });
  if (r.ok) console.log('Saved ' + r.fileName + ' (' + r.pages + ' pages)');
  else alert('Could not make the PDF: ' + r.message);
}

Un reçu construit en HTML, directement vers la feuille de partage (les images et polices sont chargées avant la création du PDF) :

async function shareReceipt(order) {
  var html = '<style>body{font-family:sans-serif} td{padding:4px 8px}</style>' +
    '<img src="img/logo.png" width="120"><h1>Receipt #' + order.id + '</h1><table>' +
    order.items.map(function (i) { return '<tr><td>' + i.name + '</td><td>' + i.price + '</td></tr>'; }).join('') +
    '</table><p><b>Total ' + order.total + '</b></p>';
  var r = await AppMint.pdf.fromHtml(html, { fileName: 'receipt-' + order.id, pageSize: 'Letter', save: 'share' });
  if (!r.ok) console.warn(r.code, r.message);
}

Récupérer les octets pour les envoyer vous-même :

async function uploadReport() {
  var r = await AppMint.pdf.fromPage({ landscape: true, margins: { top: 10, right: 8, bottom: 10, left: 8 }, save: 'base64' });
  if (!r.ok) return;
  var bin = atob(r.base64), buf = new Uint8Array(bin.length);
  for (var i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i);
  await fetch('/api/reports', { method: 'POST', headers: { 'Content-Type': 'application/pdf' }, body: buf });
}

Les appels bruts prennent les options sous forme de texte JSON et un identifiant de rappel ; utilisez plutôt l'assistant ci-dessus :

if (window.WebToApk && typeof window.WebToApk.pdfFromPage === 'function') {
  // AppMint.pdf.fromPage wraps: WebToApk.pdfFromPage(JSON.stringify(options), callbackId)
  // and AppMint.pdf.fromHtml wraps: WebToApk.pdfFromHtml(html, JSON.stringify(options), callbackId)
  AppMint.pdf.fromPage({ save: 'downloads' }).then(function (r) { console.log(r); });
}

Remarques : Masquez les boutons et menus du PDF avec @media print { .no-print { display: none } }. Un PDF téléchargé affiche « <name> téléchargé · Ouvrir » comme tout téléchargement. fromHtml exécute les scripts du HTML (les graphiques dessinés par script apparaissent) mais n'a aucun accès aux fonctionnalités natives de l'application. Les pages plus longues qu'une feuille sont découpées comme le ferait Chrome ; utilisez break-before: page pour contrôler où.

navigator.clipboard standard web#

navigator.clipboard.writeText / readText (and write / read)

Exemple

L'API Clipboard standard, servie par le vrai presse-papiers du téléphone dans l'application.

Renvoie : writeText(text) → une Promise qui se résout une fois copié et rejette avec une NotAllowedError sinon. readText() → une Promise avec le texte du presse-papiers ("" s'il est vide). write([item]) / read() → des Promises, comme dans le standard. Nécessite : rien. Installé au démarrage du document, donc une vérification faite pendant l'analyse de votre page le voit déjà.

Copier :

async function copyLink(link) {
  if (!(navigator.clipboard && navigator.clipboard.writeText)) { alert('Copy is not available'); return; }
  try {
    await navigator.clipboard.writeText(link);
    showMessage('Link copied');
  } catch (e) {
    showMessage('Could not copy');
  }
}

Coller - depuis une pression :

document.getElementById('paste').onclick = async function () {
  try {
    var text = await navigator.clipboard.readText();
    document.getElementById('input').value = text;
  } catch (e) {
    showMessage('Could not read the clipboard');
  }
};

Copier une image (par exemple un code QR dessiné sur un canvas) avec ClipboardItem:

async function copyCanvas(canvas) {
  if (!(navigator.clipboard && navigator.clipboard.write && window.ClipboardItem)) {
    alert('Copying images is not available here');
    return;
  }
  var blob = await new Promise(function (r) { canvas.toBlob(r, 'image/png'); });
  try {
    await navigator.clipboard.write([new ClipboardItem({ 'image/png': blob })]);
    showMessage('Image copied');
  } catch (e) {
    showMessage('Could not copy the image');
  }
}

Remarques : Dans l'application, writeText/readText appellent WebToApk.copyToClipboard et WebToApk.readClipboard. write() ne prend que le premier ClipboardItem et prend en charge text/plain, text/html et une image (jusqu'à 16 Mo ; une image l'emporte sur le texte dans le même élément). read() se résout en [item] avec le texte, le HTML ou l'image du presse-papiers ([] s'il est vide). Seules les pages de l'application peuvent le lire : un site externe ouvert dans l'application est refusé (NotAllowedError). Lisez-le suite à une pression de l'utilisateur : Android 12+ affiche un avis « collé depuis le presse-papiers ». Dans un navigateur, le même code fonctionne avec les règles d'autorisation propres au navigateur.

navigator.share standard web#

navigator.share(data) / navigator.canShare(data)

Exemple

L'API Web Share standard, adaptée pour fonctionner dans l'application : les textes et liens ouvrent la feuille de partage d'Android, et les files sont partagés comme de vrais fichiers (WhatsApp, Gmail, Drive…).

Renvoie : navigator.share → une Promise qui se résout à l'ouverture de la feuille (elle ne dit pas quelle application a été choisie). navigator.canShare → true/false. Nécessite : rien. Installé au démarrage du document, donc une vérification faite pendant l'analyse de votre page le voit déjà.

Un texte et un lien :

async function shareItem(item) {
  if (!navigator.share) { alert('Sharing is not available here'); return; }
  try {
    await navigator.share({ title: item.name, text: 'Look at this', url: item.link });
  } catch (e) { /* in a browser: AbortError when the user closes the sheet */ }
}

Fichiers - vérifiez d'abord avec canShare :

async function sharePdf(blob) {
  var file = new File([blob], 'invoice.pdf', { type: 'application/pdf' });
  var data = { files: [file], title: 'Invoice', text: 'Invoice for March' };
  if (!(navigator.canShare && navigator.canShare(data))) {
    alert('File sharing is not available here');
    return;
  }
  try {
    await navigator.share(data);
  } catch (e) { console.log('Share failed', e); }
}

Plusieurs fichiers choisis par l'utilisateur : des photos d'un même type se partagent avec ce type :

document.getElementById('photos').onchange = async function (e) {
  var files = Array.from(e.target.files);
  if (!files.length) return;
  var data = { files: files, title: 'Trip photos' };
  if (!(navigator.canShare && navigator.canShare(data))) {
    alert('File sharing is not available here');
    return;
  }
  try {
    await navigator.share(data);
  } catch (err) { console.log('Share failed', err); }
};

Remarques : Dans l'application, title devient l'objet, et text + url sont envoyés comme un seul texte. Avec files, chaque fichier est lu dans la page et envoyé en base64 (WebToApk.shareFiles) ; limitez donc les fichiers à quelques Mo. Si la feuille de partage ne peut pas s'ouvrir, les fichiers sont enregistrés en téléchargements à la place et la promesse se résout quand même. canShare renvoie true pour tout partage de texte. Les applications créées avec l'IA peuvent utiliser share depuis @/lib/appmintNative.

window.print standard web#

window.print()

Exemple

L'appel d'impression standard, adapté pour fonctionner dans l'application : il ouvre l'écran d'impression d'Android, où l'utilisateur imprime sur papier ou enregistre un PDF.

Retourne : rien. Nécessite : rien.

document.getElementById('print-receipt').onclick = function () {
  window.print();
};

Masquez les contrôles de l'application sur papier avec une feuille de style d'impression :

<style>
  @media print {
    nav, .toolbar, button { display: none !important; }
    body { background: #fff; color: #000; }
  }
</style>

Imprimer une étiquette d'expédition sans la page autour : un iframe srcdoc de même origine n'imprime que son propre document :

function esc(s) {
  return String(s).replace(/[&<>"]/g, function (c) {
    return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c];
  });
}
function printLabel(name, address) {
  var frame = document.createElement('iframe');
  frame.style.cssText = 'position:fixed;width:0;height:0;border:0';
  frame.srcdoc = '<title>Label</title><style>body{font:18px sans-serif;margin:24px}</style>' +
                 '<b>' + esc(name) + '</b><br>' + esc(address).replace(/\n/g, '<br>');
  frame.onload = function () {
    frame.contentWindow.print();
    setTimeout(function () { frame.remove(); }, 1000);
  };
  document.body.appendChild(frame);
}

Remarques : window.print() imprime la page principale telle qu'elle est dessinée maintenant. Un <iframe> de même origine, c'est-à-dire l'iframe caché qu'une bibliothèque d'impression remplit avec un reçu et sur lequel elle appelle iframe.contentWindow.print(), ou une page d'iframe appelant son propre window.print(), imprime le document de CET iframe (voir __printHtml). Un iframe d'origine différente ne peut pas être imprimé depuis la page. Le remplacement existe avant le premier script de la page. beforeprint ne peut pas être annulé (dans aucun navigateur).

__clipboardRead pont#

window.WebToApk.__clipboardRead(): String

navigator.clipboard.read() : `{parts:[{type, text|base64}]}`. Même portée que readClipboard() dans ce shell (qui n'a pas de contrôle d'origine).

Exemple

Transport interne derrière navigator.clipboard.read(). Les pages utilisent l'API standard ; n'appelez jamais ceci directement - les méthodes __ peuvent changer sans préavis.

Renvoie : {parts:[{type, text|base64}]} : la même portée que readClipboard() dans cette application. Nécessite : rien à activer.

Utilisez l'API publique :

canvas.toBlob(async (png) => {
  await navigator.clipboard.write([new ClipboardItem({ 'image/png': png })]);
});
const [item] = await navigator.clipboard.read();
if (item && item.types.includes('image/png')) preview(await item.getType('image/png'));

Coller du texte mis en forme dans un éditeur, en conservant la mise en forme quand le presse-papiers contient du HTML :

async function pasteRich(editor) {
  try {
    var items = await navigator.clipboard.read();
    if (!items.length) { showMessage('The clipboard is empty'); return; }
    var item = items[0];
    if (item.types.includes('text/html')) {
      editor.insertHtml(sanitize(await (await item.getType('text/html')).text()));
    } else if (item.types.includes('text/plain')) {
      editor.insertText(await (await item.getType('text/plain')).text());
    }
  } catch (e) {
    showMessage('Could not read the clipboard');
  }
}

Coller n'importe quelle image copiée (PNG, JPEG, WebP…) comme photo de profil, et distinguer une lecture refusée :

document.getElementById('paste-photo').onclick = async function () {
  try {
    var items = await navigator.clipboard.read();
    var item = items[0];
    var type = item && item.types.find(function (t) { return t.indexOf('image/') === 0; });
    if (!type) { showMessage('Copy a picture first'); return; }
    uploadAvatar(await item.getType(type));   // a Blob of that type
  } catch (e) {
    if (e.name === 'NotAllowedError') showMessage('This page cannot read the clipboard');
    else showMessage('Could not paste the picture');
  }
};

Remarques : Android 12+ affiche son propre message « collé depuis votre presse-papiers » quand une application lit le presse-papiers.

__clipboardWrite pont#

window.WebToApk.__clipboardWrite(partsJson: String): Boolean

navigator.clipboard.write() : [partsJson] est `[{type, text}|{type, base64}]` pour un ClipboardItem : text/plain, text/html, ou une image copiée sous forme d'URI de contenu.

Exemple

Transport interne derrière navigator.clipboard.write([ClipboardItem]). Les pages utilisent l'API standard ; n'appelez jamais ceci directement - les méthodes __ peuvent changer sans préavis.

Renvoie : true quand le contenu a été placé. Nécessite : rien à activer.

Utilisez l'API publique :

canvas.toBlob(async (png) => {
  await navigator.clipboard.write([new ClipboardItem({ 'image/png': png })]);
});
const [item] = await navigator.clipboard.read();
if (item && item.types.includes('image/png')) preview(await item.getType('image/png'));

Copier le texte mis en forme et sa version brute dans un seul élément, pour que les éditeurs riches reçoivent le tableau et les champs simples le texte :

async function copyTable(table) {
  if (!(navigator.clipboard && navigator.clipboard.write && window.ClipboardItem)) return;
  try {
    await navigator.clipboard.write([new ClipboardItem({
      'text/html': new Blob([table.outerHTML], { type: 'text/html' }),
      'text/plain': new Blob([table.innerText], { type: 'text/plain' })
    })]);
    showMessage('Table copied');
  } catch (e) {
    showMessage('Could not copy (' + e.name + ')');   // NotAllowedError when the write fails
  }
}

Copier une image affichée par la page, comme un code QR, pour pouvoir la coller dans une conversation :

async function copyImage(img) {
  try {
    var blob = await (await fetch(img.src)).blob();   // an image/* type, up to 16 MB
    await navigator.clipboard.write([new ClipboardItem({ [blob.type]: blob })]);
    showMessage('Image copied');
  } catch (e) {
    showMessage('Could not copy the image');
  }
}

Remarques : Texte, HTML et une image par élément. L'image est copiée sous forme d'URI de contenu via le FileProvider de l'application, ce qui permet de la coller dans WhatsApp, Gmail ou Keep.

__printHtml pont#

window.WebToApk.__printHtml(html: String, baseUrl: String, title: String)

Imprime [html] - le document sérialisé d'un iframe de même origine, envoyé par le shim `window.print()` ([PrintShim]) - via une WebView hors écran à [baseUrl], car l'adaptateur d'impression de la WebView principale ne peut imprimer que la page entière. [title] nomme la tâche d'impression (« <nom de l'application> Document » si vide).

Exemple

Transport interne derrière l'impression d'un iframe : iframe.contentWindow.print() (et le window.print() propre à la page d'un iframe) envoie ici le document de cet iframe, et l'application l'imprime via l'écran d'impression d'Android. Les pages utilisent les appels standard ; ne l'appelez jamais directement.

Retourne : rien. Nécessite : rien.

Le modèle de reçu que cela rend possible : un iframe caché rempli avec le seul reçu :

function printReceipt(order) {
  var frame = document.createElement('iframe');
  frame.style.display = 'none';
  document.body.appendChild(frame);
  var doc = frame.contentWindow.document;
  doc.open();
  doc.write('<html><head><title>Receipt ' + order.id + '</title>' +
            '<style>body{font:14px sans-serif} td{padding:2px 8px}</style></head><body>' +
            '<h2>Receipt ' + order.id + '</h2><table>' +
            order.lines.map(function (l) { return '<tr><td>' + l.name + '</td><td>' + l.price + '</td></tr>'; }).join('') +
            '</table></body></html>');
  doc.close();
  frame.contentWindow.print();   // prints the RECEIPT, not the page behind it
  setTimeout(function () { frame.remove(); }, 1000);
}

Une page de ticket à vous, chargée dans un iframe caché de même origine : son CSS et ses images se chargent, et son <title> nomme la tâche d'impression :

function printTicket(id) {
  var frame = document.createElement('iframe');
  frame.style.cssText = 'position:fixed;width:0;height:0;border:0';
  frame.src = 'ticket.html?id=' + encodeURIComponent(id);
  frame.onload = function () {
    frame.contentWindow.print();   // prints ticket.html's DOM as it stands now
    setTimeout(function () { frame.remove(); }, 1000);
  };
  document.body.appendChild(frame);
}

Ajustez le document de l'iframe juste avant la capture avec beforeprint sur la fenêtre de l'iframe :

function printWithTimestamp(frame) {
  var w = frame.contentWindow;
  w.addEventListener('beforeprint', function () {
    var p = w.document.createElement('p');
    p.textContent = 'Printed ' + new Date().toLocaleString();
    w.document.body.appendChild(p);
  }, { once: true });
  w.print();   // the printed copy includes the line added above
}

Remarques : Les arguments sont (html, baseUrl, title) : le document sérialisé de l'iframe, l'adresse par rapport à laquelle ses liens relatifs sont résolus (l'adresse de la page elle-même pour un iframe about:blank), et le nom de la tâche d'impression (le <title> de l'iframe, sinon celui de la page). La capture est prise quand print() est appelé : les scripts qu'elle contient ne s'exécutent pas à nouveau, et beforeprint / afterprint se déclenchent sur la fenêtre de l'iframe autour d'elle. Un iframe d'origine différente ne peut pas être imprimé depuis la page.

clearSharedText pont#

window.WebToApk.clearSharedText()

Efface le partage conservé une fois que la page l'a traité.

Exemple

Oublie le texte ou le lien qui a été partagé vers l'application, une fois que votre page l'a utilisé.

Renvoie : rien. Nécessite : rien (le partage lui-même nécessite Recevoir les partages d'autres applications avec Texte et liens coché).

Lire le partage conservé, l'utiliser, puis l'effacer pour qu'il ne soit pas traité à nouveau après un rechargement :

if (window.WebToApk && typeof window.WebToApk.getSharedText === 'function') {
  var raw = window.WebToApk.getSharedText();
  if (raw) {
    var shared = JSON.parse(raw);          // { text, subject, url, receivedAt }
    saveNote(shared.subject, shared.text);
    window.WebToApk.clearSharedText();     // getSharedText() now returns ""
  }
}

window.addEventListener('appmint:shared', function (e) {
  saveNote(e.detail.subject, e.detail.text);
  if (window.WebToApk && window.WebToApk.clearSharedText) window.WebToApk.clearSharedText();
});

Demandez d'abord, et effacez le partage quel que soit le bouton touché par l'utilisateur :

function askAboutShare(s) {
  var dialog = document.getElementById('share-dialog');
  document.getElementById('share-preview').textContent = s.text;
  dialog.hidden = false;
  function done() {
    dialog.hidden = true;
    if (window.WebToApk && typeof window.WebToApk.clearSharedText === 'function') {
      window.WebToApk.clearSharedText();
    }
  }
  document.getElementById('share-save').onclick = function () { saveNote(s.subject, s.text); done(); };
  document.getElementById('share-discard').onclick = done;
}

Ne le vider qu'une fois les données bien enregistrées, pour pouvoir réessayer un envoi échoué :

async function importShare() {
  if (!(window.WebToApk && typeof window.WebToApk.getSharedText === 'function')) return;
  var raw = window.WebToApk.getSharedText();
  if (!raw) return;
  var s = JSON.parse(raw);
  try {
    var res = await fetch('/api/bookmarks', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ url: s.url || s.text, title: s.subject })
    });
    if (!res.ok) throw new Error('HTTP ' + res.status);
    window.WebToApk.clearSharedText();
  } catch (e) {
    showMessage('Could not save the link — tap Retry');   // Retry calls importShare() again
  }
}

Remarques : L'effacement n'affecte que getSharedText(). Un nouveau partage remplace celui conservé et déclenche à nouveau appmint:shared. Les fichiers partagés vers l'application sont libérés séparément avec AppMint.releaseOpenedFile().

copyToClipboard pont#

window.WebToApk.copyToClipboard(text: String): Boolean

Utilisez l'encapsulation à base de promesse : const r = await AppMint.requestReview(); // {result, openedStore} const r = await AppMint.requestReview({ openStore: true }); // fiche de l'application s'il n'y a pas de fenêtre r.result : 'shown' | 'not_from_play' | 'quota' | 'error'. Voir RatePrompt.

Décrit par son groupe, Fenêtre d'avis intégrée de Google Play, plutôt que seul.

Exemple

Copie du texte brut dans le presse-papiers du téléphone. Les pages utilisent normalement le navigator.clipboard.writeText(text) standard, que le shell redirige ici.

Renvoie : true en cas de réussite, false en cas d'échec (de façon synchrone). Nécessite : rien.

L'API standard d'abord :

document.getElementById('copy-btn').onclick = async function () {
  try {
    await navigator.clipboard.writeText('PROMO-2026');
    showMessage('Copied');
  } catch (e) {
    showMessage('Could not copy');
  }
};

L'appel brut :

if (window.WebToApk && typeof window.WebToApk.copyToClipboard === 'function') {
  var ok = window.WebToApk.copyToClipboard('PROMO-2026');
  showMessage(ok ? 'Copied' : 'Could not copy');
}

Un bouton « Copier » sur chaque bloc de code, en utilisant la réponse synchrone pour mettre à jour le libellé :

document.querySelectorAll('pre').forEach(function (pre) {
  var btn = document.createElement('button');
  btn.textContent = 'Copy';
  btn.onclick = function () {
    var ok = !!(window.WebToApk && typeof window.WebToApk.copyToClipboard === 'function' &&
                window.WebToApk.copyToClipboard(pre.innerText));
    btn.textContent = ok ? 'Copied' : 'Copy failed';
    setTimeout(function () { btn.textContent = 'Copy'; }, 1500);
  };
  pre.parentNode.insertBefore(btn, pre);
});

Remarques : Texte brut uniquement (ni images ni HTML). Android 13+ affiche son propre petit aperçu « Copié », vous n'avez donc peut-être pas besoin de votre propre message.

getSharedText pont#

window.WebToApk.getSharedText(): String

Texte ou lien qu'une autre application a partagé VERS celle-ci (« Partager vers <app> » : une vidéo YouTube partagée depuis l'application YouTube arrive sous forme de lien), sous forme de JSON `{text, subject, url, receivedAt}` ou "" quand rien n'a été partagé. Conservé jusqu'à sa lecture, donc une application qui se monte après le partage le voit quand même ; un partage arrivant pendant que l'application tourne déclenche aussi `appmint:shared`. Une photo ou vidéo partagée avec une légende transmet le fichier via AppMint.getOpenedFile() et la légende ici. Nécessite l'option de compilation « Recevoir les partages d'autres applications » avec « Texte et liens » coché, qui enregistre l'entrée de la feuille de partage.

Exemple

Texte ou lien qu'une autre application a partagé VERS votre application (« Partager → votre application »), sous forme de chaîne JSON, ou "" quand rien n'a été partagé.

Renvoie : une chaîne JSON {text, subject, url, receivedAt} ou "" (de façon synchrone). url est le premier lien http(s):// trouvé dans text (ou "") ; receivedAt est une heure en millisecondes. Nécessite : Recevoir les partages d'autres applications activé lors de la compilation, avec Texte et liens coché : cela place votre application dans le menu Partager des autres applications.

Le partage est conservé jusqu'à ce que vous l'effaciez ; lisez-le donc au démarrage, et écoutez les partages qui arrivent pendant que l'application tourne :

function handleShare(s) {
  addBookmark(s.url || s.text, s.subject);
  if (window.WebToApk && window.WebToApk.clearSharedText) window.WebToApk.clearSharedText();
}

// 1. On start (the app may have been opened by the share).
if (window.WebToApk && typeof window.WebToApk.getSharedText === 'function') {
  var raw = window.WebToApk.getSharedText();
  if (raw) handleShare(JSON.parse(raw));
}

// 2. While running: detail has the same keys { text, subject, url, receivedAt }.
window.addEventListener('appmint:shared', function (e) {
  handleShare(e.detail);
});

Un hook global reçoit le même objet, si vous préférez :

window.onAppMintShared = function (s) { handleShare(s); };

Ouvrir une vidéo YouTube partagée dans l'application, avec le champ url :

function openSharedVideo() {
  if (!(window.WebToApk && typeof window.WebToApk.getSharedText === 'function')) return;
  var raw = window.WebToApk.getSharedText();
  if (!raw) return;
  var s = JSON.parse(raw);
  var m = /(?:youtu\.be\/|[?&]v=)([\w-]{11})/.exec(s.url || s.text);
  if (m) {
    showVideo(m[1]);
    window.WebToApk.clearSharedText();
  } else {
    showMessage('That share is not a video link');
  }
}

Remarques : Une vidéo YouTube partagée depuis l'application YouTube arrive sous forme de lien. Une photo ou vidéo partagée AVEC une légende transmet le fichier via AppMint.getOpenedFile() et la légende ici. Effacez le partage après l'avoir utilisé, sinon vous le reverrez au prochain démarrage. Les applications créées avec l'IA peuvent utiliser sharedText() / onShared() depuis @/lib/appmintNative.

pdfFromHtml pont#

window.WebToApk.pdfFromHtml(html: String, optionsJson: String, callbackId: String)

Génère [html] hors écran à l'origine de l'application et l'enregistre en PDF : utilisez `AppMint.pdf.fromHtml(html, options)`.

Exemple

Documenté avec AppMint.pdf : l'exemple qui s'y trouve illustre aussi celui-ci.

Crée un vrai PDF (texte sélectionnable, graphiques vectoriels) sans boîte de dialogue d'impression : fromPage enregistre la page telle qu'elle est à l'écran, mise en page avec votre CSS @media print ; fromHtml génère le HTML que vous transmettez dans une page invisible à l'adresse de l'application, de sorte que les images, feuilles de style et polices relatives se chargent comme dans votre page, attend les polices et toutes les images, puis l'enregistre. window.print() ouvre toujours la boîte de dialogue d'impression habituelle.

Renvoie : une Promise de {ok: true, fileName, pages, bytes, saved, uri?, base64?} ou {ok: false, code, message} : code vaut busy (un seul PDF à la fois), bad-options, failed, too-large (base64 de plus de 25 Mo) ou permission-denied (stockage refusé sur Android 7-9). Nécessite : rien : toutes les compilations l'ont. L'enregistrement dans Téléchargements ne nécessite aucune autorisation sur Android 10+.

Options : fileName (« .pdf » est ajouté ; par défaut : le titre de la page), pageSize 'A4' (par défaut) | 'Letter' | 'Legal' | 'A3' | 'A5', landscape (true/false), margins en millimètres (un nombre, ou {top, right, bottom, left} ; omis = votre propre règle @page), save 'downloads' (par défaut) | 'share' | 'base64'.

Enregistrer la page actuelle dans Téléchargements :

async function saveInvoice() {
  if (!(window.AppMint && AppMint.pdf)) { window.print(); return; }   // in a browser
  var r = await AppMint.pdf.fromPage({ fileName: 'invoice-1042', pageSize: 'A4', margins: 12 });
  if (r.ok) console.log('Saved ' + r.fileName + ' (' + r.pages + ' pages)');
  else alert('Could not make the PDF: ' + r.message);
}

Un reçu construit en HTML, directement vers la feuille de partage (les images et polices sont chargées avant la création du PDF) :

async function shareReceipt(order) {
  var html = '<style>body{font-family:sans-serif} td{padding:4px 8px}</style>' +
    '<img src="img/logo.png" width="120"><h1>Receipt #' + order.id + '</h1><table>' +
    order.items.map(function (i) { return '<tr><td>' + i.name + '</td><td>' + i.price + '</td></tr>'; }).join('') +
    '</table><p><b>Total ' + order.total + '</b></p>';
  var r = await AppMint.pdf.fromHtml(html, { fileName: 'receipt-' + order.id, pageSize: 'Letter', save: 'share' });
  if (!r.ok) console.warn(r.code, r.message);
}

Récupérer les octets pour les envoyer vous-même :

async function uploadReport() {
  var r = await AppMint.pdf.fromPage({ landscape: true, margins: { top: 10, right: 8, bottom: 10, left: 8 }, save: 'base64' });
  if (!r.ok) return;
  var bin = atob(r.base64), buf = new Uint8Array(bin.length);
  for (var i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i);
  await fetch('/api/reports', { method: 'POST', headers: { 'Content-Type': 'application/pdf' }, body: buf });
}

Les appels bruts prennent les options sous forme de texte JSON et un identifiant de rappel ; utilisez plutôt l'assistant ci-dessus :

if (window.WebToApk && typeof window.WebToApk.pdfFromPage === 'function') {
  // AppMint.pdf.fromPage wraps: WebToApk.pdfFromPage(JSON.stringify(options), callbackId)
  // and AppMint.pdf.fromHtml wraps: WebToApk.pdfFromHtml(html, JSON.stringify(options), callbackId)
  AppMint.pdf.fromPage({ save: 'downloads' }).then(function (r) { console.log(r); });
}

Remarques : Masquez les boutons et menus du PDF avec @media print { .no-print { display: none } }. Un PDF téléchargé affiche « <name> téléchargé · Ouvrir » comme tout téléchargement. fromHtml exécute les scripts du HTML (les graphiques dessinés par script apparaissent) mais n'a aucun accès aux fonctionnalités natives de l'application. Les pages plus longues qu'une feuille sont découpées comme le ferait Chrome ; utilisez break-before: page pour contrôler où.

pdfFromPage pont#

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

Enregistre la page en PDF sans boîte de dialogue d'impression : utilisez `AppMint.pdf.fromPage(options)`. [optionsJson] `{fileName, pageSize, landscape, margins, save}` ; résout [callbackId].

Exemple

Documenté avec AppMint.pdf : l'exemple qui s'y trouve illustre aussi celui-ci.

Crée un vrai PDF (texte sélectionnable, graphiques vectoriels) sans boîte de dialogue d'impression : fromPage enregistre la page telle qu'elle est à l'écran, mise en page avec votre CSS @media print ; fromHtml génère le HTML que vous transmettez dans une page invisible à l'adresse de l'application, de sorte que les images, feuilles de style et polices relatives se chargent comme dans votre page, attend les polices et toutes les images, puis l'enregistre. window.print() ouvre toujours la boîte de dialogue d'impression habituelle.

Renvoie : une Promise de {ok: true, fileName, pages, bytes, saved, uri?, base64?} ou {ok: false, code, message} : code vaut busy (un seul PDF à la fois), bad-options, failed, too-large (base64 de plus de 25 Mo) ou permission-denied (stockage refusé sur Android 7-9). Nécessite : rien : toutes les compilations l'ont. L'enregistrement dans Téléchargements ne nécessite aucune autorisation sur Android 10+.

Options : fileName (« .pdf » est ajouté ; par défaut : le titre de la page), pageSize 'A4' (par défaut) | 'Letter' | 'Legal' | 'A3' | 'A5', landscape (true/false), margins en millimètres (un nombre, ou {top, right, bottom, left} ; omis = votre propre règle @page), save 'downloads' (par défaut) | 'share' | 'base64'.

Enregistrer la page actuelle dans Téléchargements :

async function saveInvoice() {
  if (!(window.AppMint && AppMint.pdf)) { window.print(); return; }   // in a browser
  var r = await AppMint.pdf.fromPage({ fileName: 'invoice-1042', pageSize: 'A4', margins: 12 });
  if (r.ok) console.log('Saved ' + r.fileName + ' (' + r.pages + ' pages)');
  else alert('Could not make the PDF: ' + r.message);
}

Un reçu construit en HTML, directement vers la feuille de partage (les images et polices sont chargées avant la création du PDF) :

async function shareReceipt(order) {
  var html = '<style>body{font-family:sans-serif} td{padding:4px 8px}</style>' +
    '<img src="img/logo.png" width="120"><h1>Receipt #' + order.id + '</h1><table>' +
    order.items.map(function (i) { return '<tr><td>' + i.name + '</td><td>' + i.price + '</td></tr>'; }).join('') +
    '</table><p><b>Total ' + order.total + '</b></p>';
  var r = await AppMint.pdf.fromHtml(html, { fileName: 'receipt-' + order.id, pageSize: 'Letter', save: 'share' });
  if (!r.ok) console.warn(r.code, r.message);
}

Récupérer les octets pour les envoyer vous-même :

async function uploadReport() {
  var r = await AppMint.pdf.fromPage({ landscape: true, margins: { top: 10, right: 8, bottom: 10, left: 8 }, save: 'base64' });
  if (!r.ok) return;
  var bin = atob(r.base64), buf = new Uint8Array(bin.length);
  for (var i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i);
  await fetch('/api/reports', { method: 'POST', headers: { 'Content-Type': 'application/pdf' }, body: buf });
}

Les appels bruts prennent les options sous forme de texte JSON et un identifiant de rappel ; utilisez plutôt l'assistant ci-dessus :

if (window.WebToApk && typeof window.WebToApk.pdfFromPage === 'function') {
  // AppMint.pdf.fromPage wraps: WebToApk.pdfFromPage(JSON.stringify(options), callbackId)
  // and AppMint.pdf.fromHtml wraps: WebToApk.pdfFromHtml(html, JSON.stringify(options), callbackId)
  AppMint.pdf.fromPage({ save: 'downloads' }).then(function (r) { console.log(r); });
}

Remarques : Masquez les boutons et menus du PDF avec @media print { .no-print { display: none } }. Un PDF téléchargé affiche « <name> téléchargé · Ouvrir » comme tout téléchargement. fromHtml exécute les scripts du HTML (les graphiques dessinés par script apparaissent) mais n'a aucun accès aux fonctionnalités natives de l'application. Les pages plus longues qu'une feuille sont découpées comme le ferait Chrome ; utilisez break-before: page pour contrôler où.

print pont#

window.WebToApk.print()

Transmet la page telle qu'elle est actuellement à la boîte de dialogue d'impression d'Android, qui peut imprimer sur papier ou enregistrer un PDF. Rien à configurer : la WebView génère le document.

Décrit par son groupe, Impression, plutôt que seul.

Exemple

Ouvre l'écran d'impression d'Android pour la page telle qu'elle apparaît maintenant : imprimer sur papier ou « Enregistrer au format PDF ». Les pages utilisent normalement le window.print() standard, que le shell redirige ici.

Retourne : rien. Nécessite : rien.

L'API standard d'abord :

document.getElementById('print-btn').onclick = function () {
  window.print();   // in the app: the Android print screen
};

L'appel brut fait la même chose :

if (window.WebToApk && typeof window.WebToApk.print === 'function') {
  window.WebToApk.print();
}

Imprimer une seule facture d'une liste en la marquant pour une feuille de style d'impression (laissez le marquage : l'écran d'impression met la page en forme après le retour de print()) :

// CSS: @media print { .invoice:not(.print-me), nav, button { display: none !important; } }
function printInvoice(id) {
  document.querySelectorAll('.invoice.print-me').forEach(function (el) {
    el.classList.remove('print-me');
  });
  document.getElementById('invoice-' + id).classList.add('print-me');
  if (window.WebToApk && typeof window.WebToApk.print === 'function') {
    window.WebToApk.print();
  } else {
    window.print();   // a normal browser
  }
}

Remarques : Elle imprime toute la WebView, c'est-à-dire la page principale. Le print() propre à un iframe de même origine imprime uniquement cet iframe (voir window.print). Utilisez une feuille de style @media print pour masquer les boutons et menus. La tâche est nommée « <nom de l'application> Document ». Les erreurs sont seulement journalisées.

readClipboard pont#

window.WebToApk.readClipboard(): String

Utilisez l'encapsulation à base de promesse : const r = await AppMint.requestReview(); // {result, openedStore} const r = await AppMint.requestReview({ openStore: true }); // fiche de l'application s'il n'y a pas de fenêtre r.result : 'shown' | 'not_from_play' | 'quota' | 'error'. Voir RatePrompt.

Décrit par son groupe, Fenêtre d'avis intégrée de Google Play, plutôt que seul.

Exemple

Lit le texte qui se trouve maintenant dans le presse-papiers du téléphone. Les pages utilisent normalement le navigator.clipboard.readText() standard, que le shell redirige ici.

Renvoie : le texte, ou "" quand le presse-papiers est vide ou illisible (de façon synchrone). Nécessite : rien.

L'API standard d'abord, par exemple pour un bouton « Coller le code » :

document.getElementById('paste-btn').onclick = async function () {
  try {
    var text = await navigator.clipboard.readText();
    if (text) document.getElementById('code').value = text.trim();
    else showMessage('The clipboard is empty');
  } catch (e) {
    showMessage('Could not read the clipboard');
  }
};

L'appel brut :

if (window.WebToApk && typeof window.WebToApk.readClipboard === 'function') {
  var text = window.WebToApk.readClipboard();
  if (text) document.getElementById('code').value = text;
}

Un bouton « Coller le lien » qui extrait la première adresse web de ce qui a été copié :

document.getElementById('paste-link').onclick = function () {
  if (!(window.WebToApk && typeof window.WebToApk.readClipboard === 'function')) return;
  var text = window.WebToApk.readClipboard();
  var m = /https?:\/\/\S+/.exec(text);
  if (m) document.getElementById('link').value = m[0];
  else showMessage('There is no link on the clipboard');
};

Remarques : Seules les pages de votre propre application peuvent le lire : un site externe ouvert dans l'application obtient "". Android ne laisse l'application lire le presse-papiers que lorsqu'elle est à l'écran, et Android 12+ affiche un avis « collé depuis le presse-papiers » : lisez-le suite à une pression de l'utilisateur, pas au chargement de la page.

shareFiles pont#

window.WebToApk.shareFiles(filesJson: String, title: String, text: String): Boolean

VRAI partage natif de fichiers pour navigator.share({files:[...]}). La WebView Android n'a pas l'API Web Share, et un ACTION_SEND text/plain ne peut pas transporter de fichier : auparavant, une image partagée était simplement ENREGISTRÉE, pas partagée. filesJson est [{name, mimeType, base64}, ...] ; nous écrivons chacun dans le cache, l'exposons via le FileProvider de l'application et déclenchons ACTION_SEND / ACTION_SEND_MULTIPLE afin que la vraie feuille de partage Android (WhatsApp, Gmail, …) s'ouvre. Renvoie true si la feuille s'est ouverte.

Exemple

Partage un ou plusieurs vrais fichiers (image, PDF…) via la feuille de partage d'Android. Les pages utilisent normalement le navigator.share({ files: [...] }) standard, que le shell redirige ici.

Renvoie : true si la feuille de partage s'est ouverte, false sinon (de façon synchrone). Nécessite : rien.

L'API standard d'abord :

async function shareCanvas(canvas) {
  var blob = await new Promise(function (r) { canvas.toBlob(r, 'image/png'); });
  var file = new File([blob], 'drawing.png', { type: 'image/png' });
  if (!(navigator.canShare && navigator.canShare({ files: [file] }))) {
    alert('File sharing is not available here');
    return;
  }
  try {
    await navigator.share({ files: [file], title: 'My drawing', text: 'Made in my app' });
  } catch (e) { /* in a browser: the user closed the sheet */ }
}

L'appel brut prend une chaîne JSON de [{name, mimeType, base64}] (base64 sans le préfixe data:), puis title et text:

function shareBase64Png(base64) {
  if (!(window.WebToApk && typeof window.WebToApk.shareFiles === 'function')) return false;
  var files = [{ name: 'receipt.png', mimeType: 'image/png', base64: base64 }];
  return window.WebToApk.shareFiles(JSON.stringify(files), 'Receipt', 'Your receipt');
}

Exporter un tableau en fichier CSV (le texte est encodé en UTF-8 avant le base64) :

function shareCsv(rows) {
  if (!(window.WebToApk && typeof window.WebToApk.shareFiles === 'function')) return;
  var csv = rows.map(function (r) {
    return r.map(function (c) { return '"' + String(c).replace(/"/g, '""') + '"'; }).join(',');
  }).join('\n');
  var base64 = btoa(unescape(encodeURIComponent(csv)));
  var files = [{ name: 'expenses.csv', mimeType: 'text/csv', base64: base64 }];
  if (!window.WebToApk.shareFiles(JSON.stringify(files), 'Expenses', '')) {
    showMessage('Could not open the share sheet');
  }
}

Remarques : Les fichiers sont écrits dans le cache de l'application et partagés via son FileProvider. Les caractères non sûrs dans name deviennent _. Plusieurs fichiers d'un même type se partagent avec ce type ; les types mixtes se partagent en */*. Le fichier entier transite en base64 par le pont ; limitez-le donc à quelques Mo. Quand navigator.share({files}) ne peut pas ouvrir la feuille, le shell enregistre les fichiers en téléchargements à la place et la promesse se résout quand même.

shareNative pont#

window.WebToApk.shareNative(title: String, text: String, url: String)

La feuille de partage d'Android, le presse-papiers système, et la fermeture d'une fenêtre ouverte par la page. Ce sont les équivalents du web standard (navigator.share, navigator.clipboard, window.close) traités nativement pour qu'ils se comportent de la même façon dans l'application.

Décrit par son groupe, Partage, presse-papiers et fenêtre, plutôt que seul.

Exemple

Ouvre la feuille de partage d'Android avec un titre, un texte et un lien. Les pages utilisent normalement le navigator.share({title, text, url}) standard, que le shell redirige ici.

Renvoie : rien (il ne peut pas dire quelle application l'utilisateur a choisie). Nécessite : rien.

L'API standard d'abord : elle fonctionne aussi dans un navigateur mobile :

document.getElementById('share-btn').onclick = async function () {
  if (!navigator.share) { alert('Sharing is not available here'); return; }
  try {
    await navigator.share({ title: 'My app', text: 'Look at this', url: 'https://mysite.com/item/42' });
  } catch (e) {
    // in a browser: AbortError when the user closes the sheet
  }
};

L'appel brut, les trois arguments sont des chaînes (utilisez '' pour en omettre un) :

if (window.WebToApk && typeof window.WebToApk.shareNative === 'function') {
  window.WebToApk.shareNative('My app', 'Look at this', 'https://mysite.com/item/42');
}

Texte seul, sans lien, par exemple un score de jeu :

function shareScore(score) {
  if (!(window.WebToApk && typeof window.WebToApk.shareNative === 'function')) return;
  window.WebToApk.shareNative('My score', 'I scored ' + score + ' points. Can you beat it?', '');
}

Remarques : Le texte partagé est text + un saut de ligne + url (ou seulement l'un des deux). title devient l'objet de l'e-mail et le titre de la feuille de partage. Texte et liens uniquement : pour partager un fichier, utilisez navigator.share({files}) (voir shareFiles).

Boutons share: dans les messages intégrés à l'application. Un bouton dont le lien est share:<text> ouvre cette même feuille de partage avec ce texte, sans code de page. Le modèle Inviter des amis utilise share:Try {app}: {store} ; l'application remplit son propre nom et son adresse Play. Votre page peut savoir que cela s'est produit :

window.addEventListener('appmint:inapp', function (e) {
  var d = e.detail;
  if (d.type === 'clicked' && d.link && d.link.indexOf('share:') === 0) analytics('invite_shared', d.name);
});

Si vous dessinez vous-même les messages intégrés (setInAppPresentation('none')), exécutez un bouton share: de la même façon :

function runInAppButton(link) {
  if (link.indexOf('share:') === 0 && window.WebToApk && WebToApk.shareNative) {
    WebToApk.shareNative('', link.slice(6), '');   // text only
  }
}

Un lien copy:<text> copie au lieu de partager, par exemple un code promo issu d'un message promotionnel :

window.addEventListener('appmint:inapp', function (e) {
  var d = e.detail;
  if (d.type === 'clicked' && d.link === 'copy:SAVE20') showToast('Code SAVE20 copied');
});

Généré à partir de l'environnement d'exécution de l'application et de ses fichiers d'exemple à chaque compilation de la documentation. Lire en Markdown · Toutes les familles.

Vérifié par rapport au pont publié le 22/10/2026.