API da ponte JavaScript
Compartilhar, área de transferência e impressão
A folha de compartilhamento do Android, a área de transferência do sistema, o texto que outro app compartilhou com o seu e o diálogo de impressão.
AppMint.pdf helper#
AppMint.pdf.fromPage(options) / fromHtml(html, options)
Exemplo
Gera um PDF de verdade (texto selecionável, gráficos vetoriais) sem diálogo de impressão: fromPage salva a página como está na tela, com o layout do seu CSS @media print; fromHtml renderiza o HTML que você passar em uma página invisível no endereço do próprio app, de modo que imagens, folhas de estilo e fontes relativas carregam como na sua página, aguarda as fontes e todas as imagens e então salva. window.print() continua abrindo o diálogo de impressão normal.
Retorna: uma Promise de {ok: true, fileName, pages, bytes, saved, uri?, base64?} ou {ok: false, code, message}: code é busy (um PDF por vez), bad-options, failed, too-large (base64 acima de 25 MB) ou permission-denied (armazenamento recusado no Android 7-9). Requer: nada: todo build o tem. Salvar em Downloads não requer permissão no Android 10+.
Opções: fileName (".pdf" é adicionado; padrão: o título da página), pageSize 'A4' (padrão) | 'Letter' | 'Legal' | 'A3' | 'A5', landscape (true/false), margins em milímetros (um número ou {top, right, bottom, left}; omitido = sua própria regra @page), save 'downloads' (padrão) | 'share' | 'base64'.
Salvar a página atual em Downloads:
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);
}Um recibo montado a partir de HTML, direto para a folha de compartilhamento (imagens e fontes são carregadas antes de o PDF ser gerado):
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);
}Recupere os bytes para enviá-los você mesmo:
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 });
}As chamadas diretas recebem as opções como texto JSON e um id de callback; use o auxiliar acima:
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); });
}Observações: Oculte botões e menus do PDF com @media print { .no-print { display: none } }. Um PDF baixado mostra "Baixado <name> · Abrir" como qualquer download. fromHtml executa os scripts do HTML (gráficos desenhados por script aparecem), mas não tem acesso aos recursos nativos do app. Páginas maiores que uma folha são divididas como o Chrome faria; use break-before: page para controlar onde.
window.print padrão web#
window.print()
Exemplo
A chamada de impressão padrão, adaptada para funcionar dentro do app: abre a tela de impressão do Android, onde o usuário imprime no papel ou salva um PDF.
Retorna: nada. Requer: nada.
document.getElementById('print-receipt').onclick = function () {
window.print();
};Oculte os controles do app no papel com uma folha de estilo de impressão:
<style>
@media print {
nav, .toolbar, button { display: none !important; }
body { background: #fff; color: #000; }
}
</style>Imprima uma etiqueta de envio sem a página ao redor: um iframe srcdoc da mesma origem imprime apenas o próprio documento:
function esc(s) {
return String(s).replace(/[&<>"]/g, function (c) {
return { '&': '&', '<': '<', '>': '>', '"': '"' }[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);
}Observações: window.print() imprime a página principal como ela está desenhada agora. Um <iframe> da mesma origem (o iframe oculto que uma biblioteca de impressão preenche com um recibo e no qual chama iframe.contentWindow.print(), ou uma página em iframe chamando seu próprio window.print()) imprime o documento DESSE iframe (veja __printHtml). Um iframe de origem diferente não pode ser impresso pela página. A substituição existe antes do primeiro script da página. beforeprint não pode ser cancelado (em nenhum navegador).
__clipboardRead ponte#
window.WebToApk.__clipboardRead(): String
navigator.clipboard.read(): `{parts:[{type, text|base64}]}`. Mesmo alcance de readClipboard() neste shell (que não tem verificação de origem).
Exemplo
Transporte interno por trás de navigator.clipboard.read(). As páginas usam a API padrão; nunca chame isso diretamente - os métodos __ podem mudar sem aviso.
Retorna: {parts:[{type, text|base64}]}, com o mesmo alcance de readClipboard() neste app. Requer: nada para ativar.
Use a API pública:
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'));Cole texto formatado em um editor, mantendo a formatação quando a área de transferência tiver 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');
}
}Cole qualquer imagem copiada (PNG, JPEG, WebP…) como foto de perfil e identifique uma leitura recusada:
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');
}
};Observações: O Android 12+ mostra sua própria mensagem "colado da sua área de transferência" quando um app lê a área de transferência.
__clipboardWrite ponte#
window.WebToApk.__clipboardWrite(partsJson: String): Boolean
navigator.clipboard.write(): [partsJson] é `[{type, text}|{type, base64}]` para um ClipboardItem: text/plain, text/html ou uma imagem copiada como URI de conteúdo.
Exemplo
Transporte interno por trás de navigator.clipboard.write([ClipboardItem]). As páginas usam a API padrão; nunca chame isso diretamente - os métodos __ podem mudar sem aviso.
Retorna: true quando o conteúdo foi colocado. Requer: nada para ativar.
Use a API pública:
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'));Copie o texto formatado e a versão simples dele em um único item, para que editores avançados recebam a tabela e campos simples recebam o texto:
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
}
}Copie uma imagem que a página mostra, como um QR code, para poder colá-la em uma conversa:
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');
}
}Observações: Texto, HTML e uma imagem por item. A imagem é copiada como um URI de conteúdo pelo FileProvider do app, então pode ser colada no WhatsApp, no Gmail ou no Keep.
__printHtml ponte#
window.WebToApk.__printHtml(html: String, baseUrl: String, title: String)
Imprime [html] (o documento serializado de um iframe da mesma origem, enviado pelo shim de `window.print()` ([PrintShim])) por meio de uma WebView fora da tela em [baseUrl], porque o adaptador de impressão da WebView principal só consegue imprimir a página inteira. [title] dá nome ao trabalho de impressão ("<App name> Document" quando vazio).
Exemplo
Transporte interno por trás da impressão de um iframe: iframe.contentWindow.print() (e o window.print() da própria página do iframe) envia o documento desse iframe para cá, e o app o imprime pela tela de impressão do Android. As páginas usam as chamadas padrão; nunca chame isto diretamente.
Retorna: nada. Requer: nada.
O padrão de recibo que isso viabiliza: um iframe oculto preenchido apenas com o recibo:
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);
}Uma página de ingresso sua, carregada em um iframe oculto da mesma origem: o CSS e as imagens carregam, e o <title> dela dá nome ao trabalho de impressão:
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);
}Ajuste o documento do iframe logo antes do instantâneo com beforeprint na janela do 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
}Observações: Os argumentos são (html, baseUrl, title): o documento serializado do iframe, o endereço em relação ao qual seus links relativos são resolvidos (o endereço da própria página para um iframe about:blank) e o nome do trabalho de impressão (o <title> do iframe, ou o da página). O instantâneo é tirado quando print() é chamado (os scripts dentro dele não rodam de novo), e beforeprint / afterprint disparam na janela do iframe ao redor dele. Um iframe de origem diferente não pode ser impresso pela página.
copyToClipboard ponte#
window.WebToApk.copyToClipboard(text: String): Boolean
Use o wrapper de promessa: const r = await AppMint.requestReview(); // {result, openedStore} const r = await AppMint.requestReview({ openStore: true }); // página da loja se não houver janela r.result: 'shown' | 'not_from_play' | 'quota' | 'error'. Veja RatePrompt.
Descrito pelo seu grupo, Janela de avaliação no app do Google Play, e não isoladamente.
Exemplo
Copia texto simples para a área de transferência do celular. As páginas normalmente usam o navigator.clipboard.writeText(text) padrão, que o shell encaminha para cá.
Retorna: true em caso de sucesso, false em caso de falha (de forma síncrona). Requer: nada.
Primeiro a API padrão:
document.getElementById('copy-btn').onclick = async function () {
try {
await navigator.clipboard.writeText('PROMO-2026');
showMessage('Copied');
} catch (e) {
showMessage('Could not copy');
}
};A chamada bruta:
if (window.WebToApk && typeof window.WebToApk.copyToClipboard === 'function') {
var ok = window.WebToApk.copyToClipboard('PROMO-2026');
showMessage(ok ? 'Copied' : 'Could not copy');
}Um botão "Copiar" em cada bloco de código, usando a resposta síncrona para atualizar o rótulo:
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);
});Observações: Somente texto simples (sem imagens nem HTML). O Android 13+ mostra a própria pequena prévia "Copiado", então talvez você não precise de uma mensagem sua ali.
pdfFromHtml ponte#
window.WebToApk.pdfFromHtml(html: String, optionsJson: String, callbackId: String)
Renderiza [html] fora da tela na origem do app e o salva como PDF: use `AppMint.pdf.fromHtml(html, options)`.
Exemplo
Documentado junto com AppMint.pdf - o exemplo de lá mostra este também.
Gera um PDF de verdade (texto selecionável, gráficos vetoriais) sem diálogo de impressão: fromPage salva a página como está na tela, com o layout do seu CSS @media print; fromHtml renderiza o HTML que você passar em uma página invisível no endereço do próprio app, de modo que imagens, folhas de estilo e fontes relativas carregam como na sua página, aguarda as fontes e todas as imagens e então salva. window.print() continua abrindo o diálogo de impressão normal.
Retorna: uma Promise de {ok: true, fileName, pages, bytes, saved, uri?, base64?} ou {ok: false, code, message}: code é busy (um PDF por vez), bad-options, failed, too-large (base64 acima de 25 MB) ou permission-denied (armazenamento recusado no Android 7-9). Requer: nada: todo build o tem. Salvar em Downloads não requer permissão no Android 10+.
Opções: fileName (".pdf" é adicionado; padrão: o título da página), pageSize 'A4' (padrão) | 'Letter' | 'Legal' | 'A3' | 'A5', landscape (true/false), margins em milímetros (um número ou {top, right, bottom, left}; omitido = sua própria regra @page), save 'downloads' (padrão) | 'share' | 'base64'.
Salvar a página atual em Downloads:
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);
}Um recibo montado a partir de HTML, direto para a folha de compartilhamento (imagens e fontes são carregadas antes de o PDF ser gerado):
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);
}Recupere os bytes para enviá-los você mesmo:
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 });
}As chamadas diretas recebem as opções como texto JSON e um id de callback; use o auxiliar acima:
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); });
}Observações: Oculte botões e menus do PDF com @media print { .no-print { display: none } }. Um PDF baixado mostra "Baixado <name> · Abrir" como qualquer download. fromHtml executa os scripts do HTML (gráficos desenhados por script aparecem), mas não tem acesso aos recursos nativos do app. Páginas maiores que uma folha são divididas como o Chrome faria; use break-before: page para controlar onde.
pdfFromPage ponte#
window.WebToApk.pdfFromPage(optionsJson: String, callbackId: String)
Salva a página como PDF sem diálogo de impressão: use `AppMint.pdf.fromPage(options)`. [optionsJson] `{fileName, pageSize, landscape, margins, save}`; resolve [callbackId].
Exemplo
Documentado junto com AppMint.pdf - o exemplo de lá mostra este também.
Gera um PDF de verdade (texto selecionável, gráficos vetoriais) sem diálogo de impressão: fromPage salva a página como está na tela, com o layout do seu CSS @media print; fromHtml renderiza o HTML que você passar em uma página invisível no endereço do próprio app, de modo que imagens, folhas de estilo e fontes relativas carregam como na sua página, aguarda as fontes e todas as imagens e então salva. window.print() continua abrindo o diálogo de impressão normal.
Retorna: uma Promise de {ok: true, fileName, pages, bytes, saved, uri?, base64?} ou {ok: false, code, message}: code é busy (um PDF por vez), bad-options, failed, too-large (base64 acima de 25 MB) ou permission-denied (armazenamento recusado no Android 7-9). Requer: nada: todo build o tem. Salvar em Downloads não requer permissão no Android 10+.
Opções: fileName (".pdf" é adicionado; padrão: o título da página), pageSize 'A4' (padrão) | 'Letter' | 'Legal' | 'A3' | 'A5', landscape (true/false), margins em milímetros (um número ou {top, right, bottom, left}; omitido = sua própria regra @page), save 'downloads' (padrão) | 'share' | 'base64'.
Salvar a página atual em Downloads:
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);
}Um recibo montado a partir de HTML, direto para a folha de compartilhamento (imagens e fontes são carregadas antes de o PDF ser gerado):
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);
}Recupere os bytes para enviá-los você mesmo:
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 });
}As chamadas diretas recebem as opções como texto JSON e um id de callback; use o auxiliar acima:
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); });
}Observações: Oculte botões e menus do PDF com @media print { .no-print { display: none } }. Um PDF baixado mostra "Baixado <name> · Abrir" como qualquer download. fromHtml executa os scripts do HTML (gráficos desenhados por script aparecem), mas não tem acesso aos recursos nativos do app. Páginas maiores que uma folha são divididas como o Chrome faria; use break-before: page para controlar onde.
print ponte#
window.WebToApk.print()
Entrega a página como ela está agora ao diálogo de impressão do Android, que pode imprimir no papel ou salvar um PDF. Nada a configurar: a WebView renderiza o documento.
Descrito por seu grupo, Impressão, e não separadamente.
Exemplo
Abre a tela de impressão do Android para a página como ela está agora: imprima no papel ou "Salvar como PDF". As páginas normalmente usam o window.print() padrão, que o shell encaminha para cá.
Retorna: nada. Requer: nada.
Primeiro a API padrão:
document.getElementById('print-btn').onclick = function () {
window.print(); // in the app: the Android print screen
};A chamada direta faz o mesmo:
if (window.WebToApk && typeof window.WebToApk.print === 'function') {
window.WebToApk.print();
}Imprima uma fatura de uma lista marcando-a para uma folha de estilo de impressão (deixe a marca: a tela de impressão monta a página depois que print() retorna):
// 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
}
}Observações: Imprime a WebView inteira, ou seja, a página principal. O print() próprio de um iframe da mesma origem imprime só aquele iframe (veja window.print). Use uma folha de estilo @media print para ocultar botões e menus. O trabalho se chama "<App name> Document". Os erros só são registrados no log.
readClipboard ponte#
window.WebToApk.readClipboard(): String
Use o wrapper de promessa: const r = await AppMint.requestReview(); // {result, openedStore} const r = await AppMint.requestReview({ openStore: true }); // página da loja se não houver janela r.result: 'shown' | 'not_from_play' | 'quota' | 'error'. Veja RatePrompt.
Descrito pelo seu grupo, Janela de avaliação no app do Google Play, e não isoladamente.
Exemplo
Lê o texto que está agora na área de transferência do celular. As páginas normalmente usam o navigator.clipboard.readText() padrão, que o shell encaminha para cá.
Retorna: o texto, ou "" quando a área de transferência está vazia ou não pode ser lida (de forma síncrona). Requer: nada.
Primeiro a API padrão, por exemplo um botão "Colar código":
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');
}
};A chamada bruta:
if (window.WebToApk && typeof window.WebToApk.readClipboard === 'function') {
var text = window.WebToApk.readClipboard();
if (text) document.getElementById('code').value = text;
}Um botão "Colar link" que pega o primeiro endereço web do que foi copiado:
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');
};Observações: Somente as páginas do próprio app podem lê-la: um site de terceiros aberto dentro do app recebe "". O Android só deixa o app ler a área de transferência enquanto ele está na tela, e o Android 12+ mostra um aviso "colado da área de transferência": leia em um toque do usuário, não ao carregar a página.