Buat APK Gratis

API jembatan JavaScript

Bagikan, papan klip, dan cetak

Lembar berbagi Android, papan klip sistem, teks yang dibagikan aplikasi lain ke aplikasi Anda, dan dialog cetak.

AppMint.pdf helper#

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

Contoh

Membuat PDF asli (teks dapat dipilih, grafik vektor) tanpa dialog cetak: fromPage menyimpan halaman seperti tampil di layar, ditata dengan CSS @media print Anda; fromHtml merender HTML yang Anda berikan di halaman tak terlihat pada alamat aplikasi itu sendiri - sehingga gambar, stylesheet, dan font relatif dimuat seperti di halaman Anda - menunggu font dan setiap gambar, lalu menyimpannya. window.print() tetap membuka dialog cetak biasa.

Hasil: Promise berisi {ok: true, fileName, pages, bytes, saved, uri?, base64?} atau {ok: false, code, message} - code adalah busy (satu PDF dalam satu waktu), bad-options, failed, too-large (base64 lebih dari 25 MB) atau permission-denied (penyimpanan ditolak di Android 7-9). Membutuhkan: tidak ada - setiap build memilikinya. Menyimpan ke Downloads tidak membutuhkan izin di Android 10+.

Opsi: fileName (".pdf" ditambahkan; bawaan: judul halaman), pageSize 'A4' (bawaan) | 'Letter' | 'Legal' | 'A3' | 'A5', landscape (true/false), margins dalam milimeter (satu angka, atau {top, right, bottom, left}; jika dihilangkan = aturan @page Anda sendiri), save 'downloads' (bawaan) | 'share' | 'base64'.

Simpan halaman saat ini ke 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);
}

Struk yang dibuat dari HTML, langsung ke lembar berbagi (gambar dan font dimuat sebelum PDF dibuat):

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

Ambil kembali byte-nya untuk Anda unggah sendiri:

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

Panggilan mentah menerima opsi sebagai teks JSON dan id callback; gunakan helper di atas sebagai gantinya:

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

Catatan: Sembunyikan tombol dan menu dari PDF dengan @media print { .no-print { display: none } }. PDF yang diunduh menampilkan "Downloaded <name> · Open" seperti unduhan lainnya. fromHtml menjalankan skrip HTML (grafik yang digambar skrip tampil) tetapi tidak punya akses ke fitur native aplikasi. Halaman yang lebih panjang dari satu lembar dipecah seperti yang dilakukan Chrome; gunakan break-before: page untuk mengatur tempatnya.

navigator.clipboard standar web#

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

Contoh

API Clipboard standar, dijawab oleh papan klip asli ponsel di dalam aplikasi.

Hasil: writeText(text) → Promise yang selesai saat tersalin dan ditolak dengan NotAllowedError jika tidak. readText() → Promise berisi teks papan klip ("" bila kosong). write([item]) / read() → Promise, seperti pada standar. Membutuhkan: tidak ada. Dipasang saat dokumen dimulai, jadi pemeriksaan yang dilakukan saat halaman Anda diurai sudah melihatnya.

Salin:

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

Tempel - dari ketukan:

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

Salin gambar (misalnya kode QR yang digambar di canvas) dengan 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');
  }
}

Catatan: Di aplikasi, writeText/readText memanggil WebToApk.copyToClipboard dan WebToApk.readClipboard. write() hanya mengambil ClipboardItem pertama dan mendukung text/plain, text/html, dan satu gambar (hingga 16 MB; gambar didahulukan daripada teks dalam item yang sama). read() menghasilkan [item] dengan teks, HTML, atau gambar dari papan klip ([] bila kosong). Hanya halaman milik aplikasi sendiri yang dapat membacanya: situs asing yang dibuka di dalam aplikasi ditolak (NotAllowedError). Bacalah dengan ketukan pengguna - Android 12+ menampilkan pemberitahuan "ditempel dari papan klip". Di browser, kode yang sama berfungsi dengan aturan izin browser itu sendiri.

navigator.share standar web#

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

Contoh

Web Share API standar, dibuat berfungsi di dalam aplikasi: teks dan tautan membuka lembar berbagi Android, dan files dibagikan sebagai file asli (WhatsApp, Gmail, Drive...).

Hasil: navigator.share → Promise yang selesai saat lembar terbuka (tidak memberi tahu aplikasi mana yang dipilih). navigator.canShare → true/false. Membutuhkan: tidak ada. Dipasang saat dokumen dimulai, jadi pemeriksaan yang dilakukan saat halaman Anda diurai sudah melihatnya.

Teks dan tautan:

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 */ }
}

File - periksa dengan canShare lebih dulu:

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

Beberapa file yang dipilih pengguna - foto dengan jenis yang sama dibagikan dengan jenis itu:

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

Catatan: Di aplikasi, title menjadi subjek, dan text + url dikirim sebagai satu teks. Dengan files, setiap file dibaca di halaman dan dikirim sebagai base64 (WebToApk.shareFiles), jadi batasi file hingga beberapa MB. Jika lembar berbagi tidak bisa terbuka, file disimpan sebagai unduhan dan promise tetap selesai. canShare mengembalikan true untuk setiap berbagi teks. Aplikasi buatan AI dapat memakai share dari @/lib/appmintNative.

window.print standar web#

window.print()

Contoh

Panggilan cetak standar, dibuat berfungsi di dalam aplikasi: membuka layar cetak Android, tempat pengguna mencetak di kertas atau menyimpan PDF.

Mengembalikan: tidak ada. Membutuhkan: tidak ada.

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

Sembunyikan kontrol aplikasi di atas kertas dengan stylesheet cetak:

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

Cetak label pengiriman tanpa halaman di sekitarnya - iframe srcdoc dengan origin yang sama hanya mencetak dokumennya sendiri:

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

Catatan: window.print() mencetak halaman utama seperti yang tergambar saat ini. <iframe> dengan origin yang sama - iframe tersembunyi yang diisi pustaka cetak dengan struk lalu dipanggil iframe.contentWindow.print(), atau halaman iframe yang memanggil window.print() miliknya sendiri - mencetak dokumen iframe ITU (lihat __printHtml). Iframe lintas origin tidak bisa dicetak dari halaman. Penggantinya sudah ada sebelum skrip pertama halaman. beforeprint tidak bisa dibatalkan (di browser mana pun).

__clipboardRead jembatan#

window.WebToApk.__clipboardRead(): String

navigator.clipboard.read(): `{parts:[{type, text|base64}]}`. Jangkauannya sama dengan readClipboard() di shell ini (yang tidak punya gerbang origin).

Contoh

Transport internal di balik navigator.clipboard.read(). Halaman memakai API standar; jangan pernah memanggil ini langsung - metode __ dapat berubah tanpa pemberitahuan.

Hasil: {parts:[{type, text|base64}]} - jangkauannya sama dengan readClipboard() di aplikasi ini. Membutuhkan: tidak ada yang perlu diaktifkan.

Gunakan API publik:

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

Tempel teks berformat ke editor, mempertahankan format bila papan klip berisi 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');
  }
}

Tempel gambar apa pun yang disalin (PNG, JPEG, WebP...) sebagai foto profil, dan bedakan pembacaan yang ditolak:

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

Catatan: Android 12+ menampilkan pesan "ditempel dari papan klip Anda" sendiri saat aplikasi membaca papan klip.

__clipboardWrite jembatan#

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

navigator.clipboard.write(): [partsJson] adalah `[{type, text}|{type, base64}]` untuk satu ClipboardItem - text/plain, text/html, atau gambar yang disalin sebagai content URI.

Contoh

Transport internal di balik navigator.clipboard.write([ClipboardItem]). Halaman memakai API standar; jangan pernah memanggil ini langsung - metode __ dapat berubah tanpa pemberitahuan.

Hasil: true bila klip berhasil ditempatkan. Membutuhkan: tidak ada yang perlu diaktifkan.

Gunakan API publik:

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

Salin teks berformat dan versi biasanya dalam satu item, agar editor kaya mendapat tabelnya dan kolom biasa mendapat teksnya:

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

Salin gambar yang ditampilkan halaman, seperti kode QR, agar bisa ditempel ke obrolan:

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

Catatan: Teks, HTML, dan satu gambar per item. Gambar disalin sebagai content URI melalui FileProvider aplikasi, sehingga bisa ditempel ke WhatsApp, Gmail, atau Keep.

__printHtml jembatan#

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

Mencetak [html] - dokumen serial dari iframe dengan origin yang sama, dikirim oleh shim `window.print()` ([PrintShim]) - melalui WebView di luar layar pada [baseUrl], karena adaptor cetak WebView utama hanya bisa mencetak seluruh halaman. [title] menamai pekerjaan cetak ("<App name> Document" bila kosong).

Contoh

Transport internal di balik pencetakan iframe: iframe.contentWindow.print() (dan window.print() milik halaman iframe) mengirim dokumen iframe itu ke sini, dan aplikasi mencetaknya lewat layar cetak Android. Halaman memakai panggilan standar; jangan panggil ini secara langsung.

Mengembalikan: tidak ada. Membutuhkan: tidak ada.

Pola struk yang dimungkinkan ini - iframe tersembunyi yang hanya diisi struk:

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

Halaman tiket Anda sendiri, dimuat ke iframe tersembunyi dari origin yang sama - CSS dan gambarnya dimuat, dan <title> menamai pekerjaan cetak:

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

Sesuaikan dokumen iframe tepat sebelum snapshot dengan beforeprint pada window 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
}

Catatan: Argumennya (html, baseUrl, title): dokumen serial iframe, alamat tempat tautan relatifnya diselesaikan (alamat halaman itu sendiri untuk iframe about:blank), dan nama pekerjaan cetak (<title> iframe, atau judul halaman). Snapshot diambil saat print() dipanggil - skrip di dalamnya tidak berjalan lagi - dan beforeprint / afterprint terpicu di window iframe di sekitarnya. Iframe lintas origin tidak bisa dicetak dari halaman.

clearSharedText jembatan#

window.WebToApk.clearSharedText()

Menghapus data berbagi yang tersimpan setelah halaman selesai memakainya.

Contoh

Melupakan teks atau tautan yang dibagikan ke aplikasi, setelah halaman Anda memakainya.

Hasil: tidak ada. Membutuhkan: tidak ada (berbagi itu sendiri membutuhkan Terima Berbagi Dari Aplikasi Lain dengan Teks dan tautan dicentang).

Baca data berbagi yang tersimpan, gunakan, lalu hapus agar tidak diproses lagi setelah dimuat ulang:

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

Tanyakan dulu, dan hapus data berbagi tombol mana pun yang diketuk pengguna:

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

Hapus hanya setelah tersimpan dengan aman, agar unggahan yang gagal bisa dicoba lagi:

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

Catatan: Penghapusan hanya memengaruhi getSharedText(). Berbagi baru menggantikan yang tersimpan dan memicu appmint:shared lagi. File yang dibagikan ke aplikasi dilepas secara terpisah dengan AppMint.releaseOpenedFile().

copyToClipboard jembatan#

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

Gunakan wrapper promise: const r = await AppMint.requestReview(); // {result, openedStore} const r = await AppMint.requestReview({ openStore: true }); // listing jika tidak ada sheet r.result: 'shown' | 'not_from_play' | 'quota' | 'error'. Lihat RatePrompt.

Dijelaskan oleh kelompoknya, Lembar ulasan dalam aplikasi Google Play, bukan sendiri-sendiri.

Contoh

Menyalin teks biasa ke papan klip ponsel. Halaman biasanya memakai navigator.clipboard.writeText(text) standar, yang diarahkan shell ke sini.

Hasil: true bila berhasil, false bila gagal (sinkron). Membutuhkan: tidak ada.

API standar lebih dulu:

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

Panggilan mentah:

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

Tombol "Salin" di setiap blok kode, memakai jawaban sinkron untuk memperbarui labelnya:

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

Catatan: Hanya teks biasa (tanpa gambar atau HTML). Android 13+ menampilkan pratinjau "Tersalin" kecil sendiri, jadi Anda mungkin tidak perlu pesan sendiri di sana.

getSharedText jembatan#

window.WebToApk.getSharedText(): String

Teks atau tautan yang dibagikan aplikasi lain KE aplikasi ini ("Bagikan ke <app>" - video YouTube yang dibagikan dari aplikasi YouTube tiba sebagai tautannya), sebagai JSON `{text, subject, url, receivedAt}` atau "" bila tidak ada yang dibagikan. Disimpan sampai dibaca, jadi aplikasi yang dimuat setelah berbagi tetap melihatnya; berbagi yang tiba saat aplikasi berjalan juga memicu `appmint:shared`. Foto atau video yang dibagikan dengan keterangan mengirim file melalui AppMint.getOpenedFile() dan keterangannya di sini. Membutuhkan opsi build "Terima berbagi dari aplikasi lain" dengan "Teks dan tautan" dicentang, yang mendaftarkan entri lembar berbagi.

Contoh

Teks atau tautan yang dibagikan aplikasi lain KE aplikasi Anda ("Bagikan → aplikasi Anda"), sebagai string JSON, atau "" bila tidak ada yang dibagikan.

Hasil: string JSON {text, subject, url, receivedAt} atau "" (sinkron). url adalah tautan http(s):// pertama yang ditemukan di text (atau ""); receivedAt adalah waktu dalam milidetik. Membutuhkan: Terima Berbagi Dari Aplikasi Lain diaktifkan saat build, dengan Teks dan tautan dicentang - itu menempatkan aplikasi Anda di menu Bagikan aplikasi lain.

Data berbagi disimpan sampai Anda menghapusnya, jadi bacalah saat mulai, dan dengarkan data berbagi yang tiba saat aplikasi berjalan:

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

Hook global menerima objek yang sama, bila Anda lebih suka satu cara:

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

Buka video YouTube yang dibagikan ke aplikasi, dengan memakai kolom 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');
  }
}

Catatan: Video YouTube yang dibagikan dari aplikasi YouTube tiba sebagai tautannya. Foto atau video yang dibagikan DENGAN keterangan mengirim file melalui AppMint.getOpenedFile() dan keterangannya di sini. Hapus data berbagi setelah Anda memakainya, atau Anda akan melihatnya lagi saat mulai berikutnya. Aplikasi buatan AI dapat memakai sharedText() / onShared() dari @/lib/appmintNative.

pdfFromHtml jembatan#

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

Merender [html] di luar layar pada origin aplikasi dan menyimpannya sebagai PDF - gunakan `AppMint.pdf.fromHtml(html, options)`.

Contoh

Didokumentasikan bersama AppMint.pdf - contoh di sana menunjukkan yang ini juga.

Membuat PDF asli (teks dapat dipilih, grafik vektor) tanpa dialog cetak: fromPage menyimpan halaman seperti tampil di layar, ditata dengan CSS @media print Anda; fromHtml merender HTML yang Anda berikan di halaman tak terlihat pada alamat aplikasi itu sendiri - sehingga gambar, stylesheet, dan font relatif dimuat seperti di halaman Anda - menunggu font dan setiap gambar, lalu menyimpannya. window.print() tetap membuka dialog cetak biasa.

Hasil: Promise berisi {ok: true, fileName, pages, bytes, saved, uri?, base64?} atau {ok: false, code, message} - code adalah busy (satu PDF dalam satu waktu), bad-options, failed, too-large (base64 lebih dari 25 MB) atau permission-denied (penyimpanan ditolak di Android 7-9). Membutuhkan: tidak ada - setiap build memilikinya. Menyimpan ke Downloads tidak membutuhkan izin di Android 10+.

Opsi: fileName (".pdf" ditambahkan; bawaan: judul halaman), pageSize 'A4' (bawaan) | 'Letter' | 'Legal' | 'A3' | 'A5', landscape (true/false), margins dalam milimeter (satu angka, atau {top, right, bottom, left}; jika dihilangkan = aturan @page Anda sendiri), save 'downloads' (bawaan) | 'share' | 'base64'.

Simpan halaman saat ini ke 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);
}

Struk yang dibuat dari HTML, langsung ke lembar berbagi (gambar dan font dimuat sebelum PDF dibuat):

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

Ambil kembali byte-nya untuk Anda unggah sendiri:

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

Panggilan mentah menerima opsi sebagai teks JSON dan id callback; gunakan helper di atas sebagai gantinya:

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

Catatan: Sembunyikan tombol dan menu dari PDF dengan @media print { .no-print { display: none } }. PDF yang diunduh menampilkan "Downloaded <name> · Open" seperti unduhan lainnya. fromHtml menjalankan skrip HTML (grafik yang digambar skrip tampil) tetapi tidak punya akses ke fitur native aplikasi. Halaman yang lebih panjang dari satu lembar dipecah seperti yang dilakukan Chrome; gunakan break-before: page untuk mengatur tempatnya.

pdfFromPage jembatan#

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

Menyimpan halaman sebagai PDF tanpa dialog cetak - gunakan `AppMint.pdf.fromPage(options)`. [optionsJson] `{fileName, pageSize, landscape, margins, save}`; menyelesaikan [callbackId].

Contoh

Didokumentasikan bersama AppMint.pdf - contoh di sana menunjukkan yang ini juga.

Membuat PDF asli (teks dapat dipilih, grafik vektor) tanpa dialog cetak: fromPage menyimpan halaman seperti tampil di layar, ditata dengan CSS @media print Anda; fromHtml merender HTML yang Anda berikan di halaman tak terlihat pada alamat aplikasi itu sendiri - sehingga gambar, stylesheet, dan font relatif dimuat seperti di halaman Anda - menunggu font dan setiap gambar, lalu menyimpannya. window.print() tetap membuka dialog cetak biasa.

Hasil: Promise berisi {ok: true, fileName, pages, bytes, saved, uri?, base64?} atau {ok: false, code, message} - code adalah busy (satu PDF dalam satu waktu), bad-options, failed, too-large (base64 lebih dari 25 MB) atau permission-denied (penyimpanan ditolak di Android 7-9). Membutuhkan: tidak ada - setiap build memilikinya. Menyimpan ke Downloads tidak membutuhkan izin di Android 10+.

Opsi: fileName (".pdf" ditambahkan; bawaan: judul halaman), pageSize 'A4' (bawaan) | 'Letter' | 'Legal' | 'A3' | 'A5', landscape (true/false), margins dalam milimeter (satu angka, atau {top, right, bottom, left}; jika dihilangkan = aturan @page Anda sendiri), save 'downloads' (bawaan) | 'share' | 'base64'.

Simpan halaman saat ini ke 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);
}

Struk yang dibuat dari HTML, langsung ke lembar berbagi (gambar dan font dimuat sebelum PDF dibuat):

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

Ambil kembali byte-nya untuk Anda unggah sendiri:

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

Panggilan mentah menerima opsi sebagai teks JSON dan id callback; gunakan helper di atas sebagai gantinya:

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

Catatan: Sembunyikan tombol dan menu dari PDF dengan @media print { .no-print { display: none } }. PDF yang diunduh menampilkan "Downloaded <name> · Open" seperti unduhan lainnya. fromHtml menjalankan skrip HTML (grafik yang digambar skrip tampil) tetapi tidak punya akses ke fitur native aplikasi. Halaman yang lebih panjang dari satu lembar dipecah seperti yang dilakukan Chrome; gunakan break-before: page untuk mengatur tempatnya.

print jembatan#

window.WebToApk.print()

Menyerahkan halaman sebagaimana adanya saat ini ke dialog cetak Android, yang dapat mencetak di kertas atau menyimpan PDF. Tidak ada yang perlu diatur - WebView merender dokumennya.

Dijelaskan oleh grupnya, Pencetakan, bukan secara terpisah.

Contoh

Membuka layar cetak Android untuk halaman seperti tampilannya sekarang - cetak di kertas atau "Simpan sebagai PDF". Halaman biasanya memakai window.print() standar, yang diarahkan shell ke sini.

Mengembalikan: tidak ada. Membutuhkan: tidak ada.

API standar lebih dulu:

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

Panggilan mentah melakukan hal yang sama:

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

Cetak satu faktur dari daftar dengan menandainya untuk stylesheet cetak (biarkan tandanya - layar cetak menata halaman setelah print() selesai):

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

Catatan: Mencetak seluruh WebView - halaman utama. print() milik iframe dengan origin yang sama hanya mencetak iframe itu (lihat window.print). Gunakan stylesheet @media print untuk menyembunyikan tombol dan menu. Pekerjaan dinamai "<App name> Document". Kesalahan hanya dicatat di log.

readClipboard jembatan#

window.WebToApk.readClipboard(): String

Gunakan wrapper promise: const r = await AppMint.requestReview(); // {result, openedStore} const r = await AppMint.requestReview({ openStore: true }); // listing jika tidak ada sheet r.result: 'shown' | 'not_from_play' | 'quota' | 'error'. Lihat RatePrompt.

Dijelaskan oleh kelompoknya, Lembar ulasan dalam aplikasi Google Play, bukan sendiri-sendiri.

Contoh

Membaca teks yang ada di papan klip ponsel saat ini. Halaman biasanya memakai navigator.clipboard.readText() standar, yang diarahkan shell ke sini.

Hasil: teksnya, atau "" bila papan klip kosong atau tidak bisa dibaca (sinkron). Membutuhkan: tidak ada.

API standar lebih dulu - misalnya tombol "Tempel kode":

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

Panggilan mentah:

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

Tombol "Tempel tautan" yang mengambil alamat web pertama dari apa pun yang disalin:

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

Catatan: Hanya halaman aplikasi Anda sendiri yang dapat membacanya: situs asing yang dibuka di dalam aplikasi mendapat "". Android hanya mengizinkan aplikasi membaca papan klip saat aplikasi ada di layar, dan Android 12+ menampilkan pemberitahuan "ditempel dari papan klip" - bacalah dengan ketukan pengguna, bukan saat halaman dimuat.

shareFiles jembatan#

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

Berbagi file native SEJATI untuk navigator.share({files:[...]}). Android WebView tidak punya Web Share API, dan ACTION_SEND text/plain tidak bisa membawa file - jadi sebelumnya gambar yang dibagikan hanya DISIMPAN, bukan dibagikan. filesJson berbentuk [{name, mimeType, base64}, ...]; kami menulis tiap file ke cache, mengeksposnya lewat FileProvider aplikasi, dan memicu ACTION_SEND / ACTION_SEND_MULTIPLE agar lembar berbagi Android asli (WhatsApp, Gmail, ...) terbuka. Mengembalikan true jika lembar terbuka.

Contoh

Membagikan satu atau lebih file asli (gambar, PDF...) melalui lembar berbagi Android. Halaman biasanya memakai navigator.share({ files: [...] }) standar, yang diarahkan shell ke sini.

Hasil: true bila lembar berbagi terbuka, false jika tidak (sinkron). Membutuhkan: tidak ada.

API standar lebih dulu:

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 */ }
}

Panggilan mentah menerima string JSON berisi [{name, mimeType, base64}] (base64 tanpa awalan data:), lalu title dan 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');
}

Ekspor tabel sebagai file CSV (teks dikodekan UTF-8 sebelum 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');
  }
}

Catatan: File ditulis ke cache aplikasi dan dibagikan melalui FileProvider-nya. Karakter tidak aman di name menjadi _. Beberapa file dengan jenis yang sama dibagikan dengan jenis itu; jenis campuran dibagikan sebagai */*. Seluruh file dikirim sebagai base64 melalui bridge, jadi batasi hingga beberapa MB. Bila navigator.share({files}) tidak bisa membuka lembar, shell menyimpan file sebagai unduhan dan promise tetap selesai.

shareNative jembatan#

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

Lembar berbagi Android, papan klip sistem, dan penutupan jendela yang dibuka halaman. Ini padanan web biasa (navigator.share, navigator.clipboard, window.close) yang dijawab secara native agar berperilaku sama di dalam aplikasi.

Dijelaskan oleh grupnya, Bagikan, papan klip, dan jendela, bukan secara terpisah.

Contoh

Membuka lembar berbagi Android dengan judul, teks, dan tautan. Halaman biasanya memakai navigator.share({title, text, url}) standar, yang diarahkan shell ke sini.

Hasil: tidak ada (tidak bisa memberi tahu aplikasi mana yang dipilih pengguna). Membutuhkan: tidak ada.

API standar lebih dulu - ini juga berfungsi di browser seluler:

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

Panggilan mentah, ketiga argumennya string (gunakan '' untuk melewatkan satu):

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

Hanya teks, tanpa tautan - misalnya skor permainan:

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

Catatan: Teks yang dibagikan adalah text + baris baru + url (atau salah satunya saja). title menjadi subjek email dan judul lembar berbagi. Hanya teks dan tautan - untuk membagikan file, gunakan navigator.share({files}) (lihat shareFiles).

Tautan tombol share: di pesan dalam aplikasi. Tombol dengan tautan share:<text> membuka lembar berbagi yang sama dengan teks itu, tanpa kode halaman. Templat Undang teman memakai share:Try {app}: {store}; aplikasi mengisi nama dan alamat Play miliknya sendiri. Halaman Anda dapat mengetahui bahwa itu terjadi:

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

Jika Anda menggambar pesan dalam aplikasi sendiri (setInAppPresentation('none')), jalankan tombol share: dengan cara yang sama:

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

Tautan copy:<text> menyalin alih-alih berbagi, misalnya kode kupon dari pesan promo:

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

Dibuat dari runtime aplikasi dan file contohnya pada setiap build dokumentasi. Baca sebagai Markdown · Semua keluarga.

Diperiksa terhadap jembatan yang dirilis pada 2026-10-22.