Mulai di sini
Menulis HTML untuk aplikasi Anda
Apa yang disediakan runtime aplikasi untuk halaman Anda - kontak, SMS, notifikasi, info perangkat, biometrik - dan aturan memanggilnya dengan benar
1Aturan 1 - selalu periksa dulu#
window.WebToApk hanya ada di dalam aplikasi yang sudah Anda build. Di browser tidak ada.
Jadi selalu periksa sebelum memanggil. Jika tidak, halaman Anda rusak di mana pun kecuali di dalam aplikasi.
Beberapa hal tidak perlu diperiksa sama sekali: navigator.vibrate(), speechSynthesis dan Notification sudah berfungsi - aplikasi menghubungkannya untuk Anda. Cukup pakai kode web biasa.
// GOOD — safe everywhere
if (window.WebToApk) {
WebToApk.playClick();
}
// BAD — this breaks your page in a browser
WebToApk.playClick();2Aturan 2 - sebagian jawaban datang belakangan#
Membaca kontak, SMS, atau log panggilan butuh waktu. Jadi ini tidak menjawab langsung. Jika langsung, aplikasi Anda akan membeku.
Anda memberi panggilan sebuah nama (id). Jawabannya tiba nanti sebagai peristiwa. Anda mendengarkan peristiwa itu.
Nama peristiwa: appmint:contacts, appmint:calllog, appmint:sms, appmint:sms-received, appmint:notification-action.
// 1. Listen for the answer
window.addEventListener('appmint:contacts', function (e) {
if (e.detail.error) {
alert('Problem: ' + e.detail.error);
return;
}
console.log(e.detail.contacts);
});
// 2. Ask the question ('my1' is any name you choose)
WebToApk.listContacts('my1', 50, 0);3Aturan 3 - dua sakelar harus AKTIF#
Fitur ponsel memerlukan DUA hal:
- Anda menyalakannya di Langkah 4 (Access) saat membuat aplikasi. Jika tidak, Anda mendapat kesalahan 'not_enabled' dan pengguna tidak melihat apa-apa.
- Pengguna menjawab Ya di ponsel. Jika mereka menjawab Tidak, Anda mendapat kesalahan 'permission_denied'.
Selalu tangani kedua kesalahan agar pengguna tahu apa yang terjadi.
Cara lebih mudah: pickContact() dan composeSms() sama sekali TIDAK memerlukan izin. Gunakan saat cocok - hasilnya sama dengan lebih sedikit repot.
window.addEventListener('appmint:contacts', function (e) {
if (e.detail.error === 'not_enabled') {
alert('Turn on Contacts when you build the app');
} else if (e.detail.error === 'permission_denied') {
alert('Please allow contacts access');
} else {
showContacts(e.detail.contacts);
}
});4Notifikasi dengan gambar dan tombol#
notify() menerima daftar opsi. Anda bisa menambahkan gambar besar, ikon, tombol, dan bilah progres.
channel bisa berupa: urgent, default, quiet, atau ongoing.
Gunakan ongoing:true untuk notifikasi yang tidak bisa digeser pengguna. Catatan: mereka tetap bisa menghapusnya dari pengaturan Android. Tidak ada aplikasi yang bisa membuat notifikasi yang mustahil dihapus.
Gunakan tag untuk memberinya nama. Mengirim lagi dengan tag yang sama menggantikan yang lama alih-alih menambah yang baru.
WebToApk.notify(JSON.stringify({
title: 'Order shipped',
body: 'Arriving Tuesday',
channel: 'urgent',
image: 'https://mysite.com/box.jpg',
actions: [{ id: 'track', label: 'Track' }],
tag: 'order-482'
}));
// Know which button the user pressed
window.addEventListener('appmint:notification-action', function (e) {
if (e.detail.actionId === 'track') showTracking();
});5Informasi ponsel dan sidik jari#
getDeviceInfo() tidak memerlukan izin. Ia memberi Anda versi Android, ID versi (buildId), model ponsel, ukuran layar, level baterai, dan lainnya.
Tentang ID perangkat: TIDAK ADA IMEI atau nomor seri. Android memblokirnya untuk semua aplikasi sejak Android 10. Gunakan getInstallId() - ID tetap untuk instalasi ini yang tetap sama setelah pembaruan.
var info = JSON.parse(WebToApk.getDeviceInfo());
info.android.release; // "14"
info.android.buildId; // "TQ3A.230805.001" <- version ID
info.hardware.model; // "Pixel 7"
info.runtime.batteryLevel; // 82
// Fingerprint
window.__webToApkAuth = window.__webToApkAuth || {};
window.__webToApkAuth['unlock'] = function (json) {
var r = JSON.parse(json);
if (r.ok) showMyApp();
};
WebToApk.authenticateBiometricEx('unlock', JSON.stringify({
title: 'Unlock',
allowDeviceCredential: true
}));6Buat halaman Anda memenuhi layar#
Saat Anda menyalakan Fullscreen, aplikasi menyembunyikan bilah Android untuk Anda. Tetapi tambahkan CSS ini agar konten Anda tidak tersembunyi di bawah notch ponsel.
Penting: Fullscreen menyembunyikan bilah ANDROID (jam, baterai, tombol kembali). Bilah berwarna aplikasi Anda di atas adalah sakelar lain bernama 'Show top bar'. Jika Anda masih melihat bilah setelah menyalakan Fullscreen, itulah yang perlu dimatikan.
Juga: uji aplikasi Anda saat diputar. Notch berpindah ke sisi dalam mode lanskap.
body {
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
min-height: 100vh; /* old phones */
min-height: 100dvh; /* correct when bars are hidden */
}7Unduhan mempertahankan nama file yang Anda pilih#
Kode unduhan biasa Anda sudah berfungsi. Saat halaman Anda menyimpan file - laporan PDF, ekspor CSV, cadangan - aplikasi menangkapnya dan membuka lembar 'Save as…' Android dengan nama file ANDA sudah terisi.
Ini mencakup semua cara yang umum: <a download="...">, a.click() dari kode, html2pdf / jsPDF, FileSaver.js saveAs(), dan window.open() pada blob URL. Objek File membawa namanya sendiri.
Jika Anda lebih suka meminta langsung daripada membuat tag <a>, gunakan AppMint.downloadFile().
Satu hal yang perlu diketahui: nama hanya ada di JavaScript halaman Anda - Android tidak pernah melihatnya sendiri. Jadi selalu setel download= (atau berikan nama), atau file disimpan sebagai 'download'.
// The usual way — saves as Site_Report_2026-08.pdf
const blob = await html2pdf().from(el).outputPdf('blob');
const a = document.createElement('a');
a.download = 'Site_Report_2026-08.pdf';
a.href = URL.createObjectURL(blob);
a.click();
// Or ask directly
AppMint.downloadFile(base64String, 'Ledger_Q3.csv', 'text/csv');
AppMint.saveBlob(myBlob, 'Backup.json');8Buat tombol Kembali melakukan yang DIINGINKAN aplikasi Anda#
Jika aplikasi Anda berganti layar dengan menampilkan dan menyembunyikan elemen (tanpa perubahan URL, tanpa history.pushState), tombol Kembali Android tidak bisa melihat layar-layar itu - riwayatnya kosong, jadi Kembali keluar dari aplikasi dari mana saja.
Daftarkan handler kembali dan putuskan sendiri: kembalikan true saat Anda sudah menangani tekanan (menutup menu, kembali satu layar), kembalikan false agar perilaku normal berjalan - kembali di riwayat halaman, lalu konfirmasi keluar, lalu keluar.
Aplikasi yang memakai history.pushState untuk setiap layar tidak memerlukan ini: Kembali sudah menelusuri riwayatnya. Dan jangan khawatir aplikasi membeku - jika handler Anda macet, tombol Kembali ponsel tetap berfungsi secara native setelah beberapa saat.
AppMint.setBackHandler(() => {
if (isMenuOpen) { closeMenu(); return true; } // consumed
if (screen !== 'home') { goTo('home'); return true; }
return false; // nothing open — normal exit behaviour
});
// Or listen instead: e.preventDefault() consumes the press
window.addEventListener('appmint:back', e => {
if (closeTopmost()) e.preventDefault();
});9Terima yang dibagikan orang ke aplikasi Anda - tautan, foto, video, file#
Nyalakan 'Receive shares from other apps' di wizard build dan centang apa yang diterima aplikasi Anda: teks dan tautan, file data (JSON, CSV, TXT, XML, Markdown, GPX, TCX, FIT), foto, video, audio, dokumen (PDF, Word, Excel, PowerPoint). Aplikasi Anda lalu muncul di menu Bagikan setiap aplikasi lain untuk jenis itu saja - aplikasi catatan untuk teks, pemutar untuk video.
Tautan atau teks (membagikan video YouTube dari aplikasi YouTube mengirim tautannya) dibaca dengan WebToApk.getSharedText() dan diumumkan sebagai appmint:shared. File diminta dengan AppMint.getOpenedFile() - minta kapan pun Anda siap, file menunggu Anda. Ini penting untuk aplikasi React, Vue, dan Angular: mereka selesai mulai SETELAH halaman dimuat, sehingga aplikasi yang hanya mendengarkan peristiwa dulu melewatkan file dan hanya menampilkan layar utamanya.
f.kind memberi tahu apa yang tiba: image, video, audio, document, atau data. Foto, video, dan audio datang sebagai f.url - alamat yang bisa di-stream dan di-seek yang langsung Anda taruh di <video src>, <img src> atau <audio src>, sehingga klip 300 MB tidak perlu muat di memori; f.getFile() mengambil File saat Anda benar-benar membutuhkan byte-nya. File data dan dokumen juga datang dengan f.file, ditambah f.text untuk format teks dan f.base64 untuk biner kecil sebagai jalan pintas. Foto yang dibagikan dengan keterangan juga mengirim keterangannya sebagai teks yang dibagikan.
// A link or text someone shared
const shared = JSON.parse(WebToApk.getSharedText() || 'null');
if (shared) saveLink(shared.url || shared.text);
window.addEventListener('appmint:shared', e => saveLink(e.detail.url || e.detail.text));
// A photo, video, audio clip, document or data file — ask on startup, however late
const f = await AppMint.getOpenedFile(); // null if opened normally
if (f) {
if (f.kind === 'video') player.src = f.url; // streams, seekable
else if (f.kind === 'image') img.src = f.url;
else if (f.kind === 'document') await upload(await f.getFile()); // a real File
else importActivity(f.text ?? await f.file.text()); // data files
}
// Or listen, if you prefer
window.addEventListener('appmint:fileopen', e => handle(e.detail));10Sensor Bluetooth - Web Bluetooth standar#
Sabuk detak jantung, sensor irama dan kecepatan, power meter, smart trainer, timbangan - apa pun yang menggunakan Bluetooth LE.
Gunakan navigator.bluetooth, kode yang persis sama seperti yang Anda tulis untuk Chrome di desktop. AppMint menyediakannya di dalam aplikasi; Android WebView biasa tidak punya, itulah sebabnya kode ini tidak berfungsi di pembuat aplikasi lain.
Pemilih perangkat digambar oleh aplikasi, seperti di browser - halaman Anda hanya bisa menjangkau perangkat yang dipilih pengguna.
Nyalakan izin Bluetooth di Langkah 4 (Access). Jika kode Anda menyebut navigator.bluetooth, AppMint menyalakannya untuk Anda saat Anda memilih ZIP.
Tidak tersedia: getDevices(), watchAdvertisements() dan requestLEScan() - semuanya ditolak dengan NotSupportedError, jadi periksa dulu sebelum memakainya.
const device = await navigator.bluetooth.requestDevice({
filters: [{ services: ['heart_rate'] }]
});
const server = await device.gatt.connect();
const service = await server.getPrimaryService('heart_rate');
const chr = await service.getCharacteristic('heart_rate_measurement');
chr.addEventListener('characteristicvaluechanged', e => {
const v = e.target.value; // a DataView
const bpm = (v.getUint8(0) & 1) ? v.getUint16(1, true) : v.getUint8(1);
document.getElementById('bpm').textContent = bpm;
});
await chr.startNotifications();
device.addEventListener('gattserverdisconnected', () => showReconnect());11Unggah foto - pemilih foto Android, tanpa izin#
Gunakan input file biasa. Tidak ada yang perlu ditambahkan.
Di aplikasi, <input type="file" accept="image/*"> membuka pemilih foto Android: foto pengguna dalam kisi, dan halaman Anda hanya mendapat yang mereka pilih. Tanpa izin penyimpanan, tanpa popup 'Allow access to photos?'. Juga berfungsi di ponsel lama - Google Play services memasang pemilihnya di sana.
- accept="image/*" - hanya foto
- accept="video/*" - hanya video
- accept="image/*,video/*" - keduanya
- tambahkan multiple - pengguna bisa memilih beberapa
- tambahkan capture="environment" - membuka kamera sebagai gantinya (perlu Camera dicentang di Langkah 4 (Access))
Campurkan file lain (accept="image/*,.pdf") dan pemilih file biasa yang terbuka, sehingga PDF juga bisa dipilih.
<input type="file" id="photos" accept="image/*" multiple>
<script>
document.getElementById('photos').onchange = function (e) {
for (const file of e.target.files) {
const img = document.createElement('img');
img.src = URL.createObjectURL(file);
document.body.appendChild(img);
}
};
</script>12Pindai kode QR atau barcode - satu baris#
AppMint.scanCode() membuka layar pemindai Google. Pengguna mengarahkan kamera, dan Anda mendapat kodenya kembali.
Tanpa izin kamera. Tanpa elemen video. Tidak ada yang perlu digambar. Pemindai memperbesar sendiri untuk kode kecil. Pertama kali di sebuah ponsel, Google Play services mengunduh pemindai (beberapa detik).
Jawabannya memiliki value (teks dalam kode) dan format (qr_code, ean_13, …). Untuk kode QR umum Anda juga mendapat bagian-bagiannya siap pakai: url, wifi (ssid, password), phone, email, sms, geo, contact.
Jika ok bernilai false, code memberi tahu alasannya: cancelled (pengguna menutupnya), unavailable (tidak ada Google Play services, atau unduhan gagal), busy (pemindaian sudah terbuka).
AppMint.scanCode hanya ada di dalam aplikasi - periksa dulu keberadaannya.
async function scan() {
if (!window.AppMint || !AppMint.scanCode) return; // in a browser
const r = await AppMint.scanCode({ formats: ['qr_code'] });
if (!r.ok) return; // closed, or no scanner
console.log(r.value); // the text inside the code
if (r.url) location.href = r.url.url;
}
// Any code type: AppMint.scanCode()
// Let the user type it when it will not scan: AppMint.scanCode({ manualInput: true })13Passkey - masuk dengan sidik jari atau wajah, tanpa kata sandi#
Jika situs web Anda sudah punya passkey, kini passkey itu berfungsi di dalam aplikasi juga. Android WebView biasa tidak bisa passkey; AppMint menghubungkan navigator.credentials ke pengelola passkey Android, sehingga pustaka seperti SimpleWebAuthn, Hanko, Corbado, atau Auth0 berfungsi tanpa perubahan.
Anda memerlukan server yang membuat opsi passkey dan memeriksa jawabannya (misalnya SimpleWebAuthn di backend Anda). Passkey tidak bisa diperiksa di dalam halaman.
Dua hal yang perlu diatur sekali:
- Situs web Anda harus menyatakan mempercayai aplikasi. Taruh file dari
AppMint.passkey.assetLinks() di https://YOUR-DOMAIN/.well-known/assetlinks.json. Ambil dari aplikasi yang dipasang DARI Google Play - Play menandatangani aplikasi Anda dengan kuncinya sendiri, jadi file dari APK uji tidak akan cocok untuk pengguna Play. Domain harus persis rpID server Anda (www dan tanpa www berbeda).
- Server Anda harus menerima origin aplikasi. Jawaban dari aplikasi berisi origin 'android:apk-key-hash:…' bukan https://… - ambil nilainya dari
AppMint.passkey.origin() dan tambahkan ke origin yang diizinkan server Anda.
Kesalahan: NotAllowedError = pengguna membatalkan atau tidak punya passkey di ponsel ini. InvalidStateError = passkey ini sudah ada. SecurityError = assetlinks.json tidak mencantumkan aplikasi.
Passkey memerlukan Android 9 atau lebih baru dengan Google Play services - AppMint.passkey.isAvailable() memberi tahu Anda. Pengisian otomatis passkey di kolom teks (mediation: 'conditional') tidak tersedia di aplikasi; mulai masuk dari sebuah tombol.
// Your normal passkey code works as it is:
const cred = await navigator.credentials.get({ publicKey: options });
// Or with your server's JSON options (SimpleWebAuthn style):
const options = await (await fetch('/passkey/login-options')).json();
const answer = await AppMint.passkey.get(options);
await fetch('/passkey/login-verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(answer)
});
// Once, on the Play-installed app — copy these to your server setup:
console.log(JSON.stringify(AppMint.passkey.assetLinks(), null, 2));
console.log(AppMint.passkey.origin());14Widget layar utama - tampilkan data Anda di layar utama#
Aplikasi Anda punya widget layar utama. Pengguna menambahkannya dari daftar widget ponsel (tekan dan tahan layar utama, lalu Widgets), atau Anda membuka lembar Add dengan AppMint.widget.requestPin().
Widget tetap kosong ("Nothing to show yet") sampai halaman Anda mengisinya. Ini kartu Android kecil, bukan halaman web, jadi tidak bisa menampilkan HTML Anda. Anda memberinya judul, satu nilai besar, hingga enam baris pendek, dan warna.
Panggil AppMint.widget.set() saat aplikasi dibuka, dan lagi setiap kali data yang ditampilkan berubah. Widget menyimpan kartu terakhir, bahkan setelah restart. route adalah tujuan aplikasi Anda saat widget diketuk.
function updateWidget() {
if (!window.AppMint || !AppMint.widget) return; // in a browser
AppMint.widget.set({
title: 'Today',
value: '3 events',
lines: ['09:00 Dentist', '13:00 Lunch with Sam', '18:30 Gym'],
route: '/',
bg: '#0E7C86', ink: '#FFFFFF', accent: '#FFE08A'
});
}
updateWidget(); // on start-up, and after every change
// An "Add to home screen" button:
async function addWidget() {
if ((await AppMint.widget.placedCount()) > 0) return;
await AppMint.widget.requestPin();
}15Perlindungan salin dan menu tekan-tahan#
Dua sakelar di Langkah 3 (Integrate), di bawah Display Options. Keduanya mati sampai Anda menyalakannya.
- Menu tekan-tahan pada tautan dan gambar: tekan dan tahan tautan atau gambar untuk membuka, menyalin, membagikan, atau menyimpannya. Nonaktif secara default, jadi tekan-tahan pada tautan tidak melakukan apa-apa. Halaman tetap bisa menolak menu pada satu elemen dengan membatalkan peristiwa contextmenu.
- Perlindungan salin: tidak ada yang bisa memilih, menyalin, atau memotong teks di aplikasi Anda. Mengetik di formulir tetap berfungsi. Ini juga mematikan menu tekan-tahan.
Halaman Anda bisa tahu: AppMint.copyProtection bernilai true saat perlindungan aktif, dan tidak ada saat nonaktif (dan di browser). Hanya-baca. Sembunyikan tombol Salin milik Anda saat aktif, karena tidak akan menyalin apa pun.
const protectedApp = !!(window.AppMint && window.AppMint.copyProtection === true);
// A Copy button would copy nothing, so hide it
document.querySelectorAll('[data-copy-button]').forEach(btn => {
btn.hidden = protectedApp;
});16{exampleCount} contoh siap pakai - buka di sini#
Kode yang bisa disalin: kirim SMS, baca kontak, tampilkan notifikasi dengan gambar, kunci sidik jari, informasi ponsel, menyimpan file, sensor Bluetooth, dan lainnya. Masing-masing singkat dan dijelaskan dengan kata-kata sederhana.
Terbuka di dalam AppMint. Anda bisa mencarinya, dan setiap blok kode punya tombol Copy.
Layar yang sama juga memiliki 'All methods' - semua {methodCount} hal yang bisa dipanggil aplikasi Anda, dan masing-masing disertai contoh yang berfungsi dan bisa disalin. Daftar itu dibangun dari runtime aplikasi itu sendiri, jadi selalu sesuai persis dengan kemampuan aplikasi Anda.
17Simpan contoh ke ponsel atau komputer Anda#
Menyimpan tiga file ke Downloads/AppMint/Guides:
- Contoh - {exampleCount} contoh di atas
- Daftar metode - semua {methodCount} metode
- index.html - halaman uji siap pakai
Halaman uji punya tombol untuk info perangkat, getaran, notifikasi, dan pemilih kontak. Build sebagai aplikasi untuk melihat semuanya berfungsi, lalu ubah menjadi aplikasi Anda sendiri. Halaman ini juga terbuka normal di browser biasa - tidak ada yang rusak, hanya menyatakan bahwa ia tidak berada di dalam aplikasi.
Di aplikasi, tombol langkah ini menyimpannya ke ponsel Anda. Di sini berupa unduhan langsung.
AppMint-examples.md AppMint-all-methods.md index.html18Alarm yang berdering di atas layar kunci#
Centang Alarm clock di langkah Access. scheduleNotificationEx dengan alarm: true berdering dengan suara Anda sampai pengguna menutup atau menunda, bahkan saat aplikasi ditutup. Pengulangan bisa harian, mingguan, hari kerja, bulanan, atau tahunan, atau pilih hari dalam seminggu.
Sebelum menjadwalkan, tanyakan getAlarmSupport(). Jawabannya 'ready', 'not_enabled', 'needs_exact_alarm' atau 'needs_notification_permission'. Lalu stopAlarm(id), snoozeAlarm(id, minutes) dan isAlarmRinging(id) mengendalikan alarm yang berdering.
const B = window.WebToApk;
if (B && B.getAlarmSupport && B.getAlarmSupport() === 'ready') {
B.scheduleNotificationEx('wake', JSON.stringify({
at: firstAtMs, alarm: true, title: 'Wake up', repeat: 'weekdays', sound: '/audio/alarm.mp3'
}));
}
document.getElementById('snooze').onclick = () => B.snoozeAlarm('wake', 10);19Volume sistem#
getVolume(stream) membaca volume media, alarm, dering, notifikasi, atau panggilan sebagai JSON. setVolume(stream, percent, showUi) mengubahnya. watchVolume(true) mengirim peristiwa appmint:volume pada setiap perubahan. Membisukan volume dering memerlukan akses Do Not Disturb: requestDndAccess().
if (window.WebToApk && WebToApk.getVolume) {
const v = JSON.parse(WebToApk.getVolume('alarm'));
if (v.percent === 0) alert('Alarm volume is off');
window.addEventListener('appmint:volume', (e) => console.log(e.detail.stream, e.detail.percent));
WebToApk.watchVolume(true);
}20Layanan latar belakang, lokasi latar belakang, geofence, dan tugas#
startBackgroundService menjaga halaman, audio, dan timer Anda tetap berjalan saat pengguna pergi, dengan notifikasi. requestBackgroundLocation meminta 'Allow all the time'. addGeofence memicu enter, exit, atau dwell saat aplikasi ditutup. AppMint.background.register menjalankan kode halaman Anda sendiri setiap 15 menit atau lebih. Semuanya mulai lagi setelah ponsel dihidupkan ulang.
Ini memerlukan sakelarnya di wizard (langkah Access); panggilan menjawab { ok: false, reason: 'not_enabled' } tanpanya.
const r = JSON.parse(WebToApk.startBackgroundService(JSON.stringify({ title: 'Syncing', text: 'Keeping data fresh' })));
if (!r.ok) console.warn(r.reason);
if (AppMint.background.isBackgroundRun()) {
window.addEventListener('appmint:background', async (e) => {
await refreshData();
AppMint.background.done(e.detail.runId, { ok: true });
});
} else {
AppMint.background.register('refresh', { intervalMinutes: 60 });
}21Laporan crash#
Centang Crash reports di langkah Integrate. Kesalahan yang tidak tertangani dicatat untuk Anda. logError(message, stack) mencatat yang Anda tangkap, setCrashUserId(id) menandai laporan dengan ID pengguna Anda sendiri (jangan pernah email), dan getLastCrash() mengembalikan crash terbaru sebagai JSON, atau string kosong. Baca laporannya di Update the App, lalu aplikasi Anda, lalu Crash reports.
if (window.WebToApk && WebToApk.logError) {
try { risky(); } catch (err) { WebToApk.logError(err.message, err.stack || ''); }
WebToApk.setCrashUserId('u_42');
const last = WebToApk.getLastCrash(); // '' when none
}22Integritas perangkat dan Play Integrity#
Centang Device integrity checks di langkah Integrate. getDeviceIntegrity() mengembalikan tanda root, emulator, dan debugger sebagai JSON; ini peringatan, bukan bukti. Untuk putusan yang bisa dipercaya, panggil requestIntegrityToken(nonce, '') dan kirim token dari peristiwa appmint:integrity ke server ANDA, yang meminta putusan dari Google Play.
const d = JSON.parse(WebToApk.getDeviceIntegrity());
if (d.rooted || d.emulator) alert('This phone is modified');
window.addEventListener('appmint:integrity', (e) => sendToServer(e.detail.token));
WebToApk.requestIntegrityToken(serverNonceBase64, '');23Ikon aplikasi alternatif dan TV#
Tambahkan hingga 4 ikon alternatif di langkah Basic. setAppIcon(name) mengganti ikon peluncur ('default' untuk kembali), getAppIcon() menyebut yang sedang dipakai dan getAvailableIcons() mencantumkannya. isTv() memberi tahu bahwa aplikasi berjalan di televisi, sehingga Anda bisa menampilkan tata letak yang ramah remote.
if (window.WebToApk && WebToApk.setAppIcon) WebToApk.setAppIcon('dark');
if (window.WebToApk && WebToApk.isTv && WebToApk.isTv()) {
document.documentElement.classList.add('tv');
}24Masuk dengan Facebook, analitik, dan RevenueCat#
Masuk dengan Facebook didukung. Di langkah Integrate masukkan Facebook App ID dan Client Token Anda; login terbuka di tab browser dan kembali ke aplikasi. Panggil AppMint.facebook.login(['public_profile', 'email']) dan kirim token ke server Anda. AppMint.analytics (Firebase) dan AppMint.facebook.logEvent (Meta App Events) hanya mencatat setelah pengguna setuju. AppMint.revenuecat menangani langganan dengan kunci Android publik Anda.
const r = await AppMint.facebook.login(['public_profile', 'email']);
if (r.ok) await fetch('/api/login/facebook', { method: 'POST', body: JSON.stringify({ token: r.accessToken }) });
AppMint.analytics.log('share', { method: 'whatsapp' });
const offerings = await AppMint.revenuecat.getOfferings();25Teks dari foto, PDF, dan widget#
AppMint.textRecognition.recognize(image, { script }) membaca teks dalam Latin, Devanagari, Mandarin, Jepang, atau Korea. AppMint.pdf.fromPage() dan fromHtml(html, options) membuat PDF sungguhan tanpa dialog cetak. AppMint.widget.set(card) mengisi widget layar utama.
const r = await AppMint.textRecognition.recognize(file, { script: 'devanagari' });
const pdf = await AppMint.pdf.fromHtml('<h1>Invoice</h1>', { fileName: 'invoice', save: 'share' });
await AppMint.widget.set({ title: 'Today', value: '3 events', route: '/calendar' });26Data kesehatan dan beacon Bluetooth#
AppMint.health membaca dan menulis langkah, detak jantung, tidur, berat badan, dan olahraga lewat Health Connect; centang Health data dan jenisnya di langkah Access. AppMint.beacons.startScan() menemukan beacon iBeacon dan Eddystone dan mengirim peristiwa appmint:beacon.
const a = await AppMint.health.isAvailable();
if (a.available) {
await AppMint.health.requestPermissions({ read: ['steps'] });
const steps = await AppMint.health.read('steps', { start: new Date(Date.now() - 864e5), end: new Date(), aggregate: true });
}
window.addEventListener('appmint:beacon', (e) => console.log(e.detail));
await AppMint.beacons.startScan();27Plugin siap pakai: SQLite, notifikasi, push, pemindai, kontak#
Di halaman yang disajikan aplikasi sendiri, window.Capacitor.Plugins memuat CapacitorSQLite (database pribadi), LocalNotifications, PushNotifications, CapacitorBarcodeScanner, dan Contacts. Periksa dulu apakah plugin ada: aplikasi mode Website hanya punya window.Capacitor di halaman situsnya sendiri, tidak pernah di domain lain.
const P = window.Capacitor && window.Capacitor.Plugins;
if (P && P.CapacitorBarcodeScanner) {
const s = await P.CapacitorBarcodeScanner.scanBarcode({ hint: 17 });
console.log(s.ScanResult);
}
if (P && P.LocalNotifications) await P.LocalNotifications.requestPermissions();