API del puente de JavaScript
Plugins de Capacitor
Los plugins de Capacitor que aloja la app. Una pĂĄgina escrita a mano accede a ellos como window.Capacitor.Plugins.<Name>; una app creada con IA usa el wrapper @/lib/appmintNative que indica cada ejemplo.
Capacitor.ActionSheet Capacitor#
Capacitor.Plugins.ActionSheet — showActions({ title, message, options })
Ejemplo
Muestra una hoja inferior nativa con una lista de opciones y te dice cuĂĄl se tocĂł (@capacitor/action-sheet 8.1.1).
Devuelve: Promise { index, canceled }: index es la opciĂłn tocada; cuando la hoja se descarta, canceled es true y index queda fuera de la lista (-1). Requisitos: no hay que activar nada: todas las apps incluyen el plugin. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
Cada opciĂłn es { title, style? } con style 'DEFAULT', 'DESTRUCTIVE' o 'CANCEL'.
var ActionSheet = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ActionSheet;
async function photoMenu() {
if (!ActionSheet) return;
var opts = [
{ title: 'Share', style: 'DEFAULT' },
{ title: 'Edit', style: 'DEFAULT' },
{ title: 'Delete', style: 'DESTRUCTIVE' }
];
var r = await ActionSheet.showActions({ title: 'Photo', message: 'Choose an action', options: opts });
if (r.canceled || r.index < 0 || r.index >= opts.length) return; // dismissed
if (opts[r.index].title === 'Delete') deletePhoto();
}En una app creada con IA el wrapper con forma Capacitor devuelve { index: -1 } al descartar; la forma corta actionSheet() devuelve null:
import { ActionSheet, actionSheet } from '@/lib/appmintNative';
const { index } = await ActionSheet.showActions({
title: 'Photo',
options: [{ title: 'Share' }, { title: 'Delete', destructive: true }],
});
if (index === 1) deletePhoto();
const i = await actionSheet('Sort by', [{ title: 'Name' }, { title: 'Date' }]); // number | nullConfirmaciĂłn de borrado que tambiĂŠn funciona en un navegador normal:
async function confirmDelete(name) {
const AS = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ActionSheet;
if (!AS) return window.confirm('Delete ' + name + '?');
const r = await AS.showActions({
title: 'Delete ' + name + '?',
options: [{ title: 'Delete', style: 'DESTRUCTIVE' }, { title: 'Keep it', style: 'CANCEL' }]
});
return !r.canceled && r.index === 0;
}Notas: Comprueba siempre el lĂmite del Ăndice: nunca trates cualquier Ăndice como una opciĂłn real. La forma de opciĂłn del wrapper es { title, destructive? }; asigna destructive al estilo 'DESTRUCTIVE' del plugin.
Capacitor.App Capacitor#
Capacitor.Plugins.App — getInfo(), getState(), exitApp(), minimizeApp(), addListener(...)
Ejemplo
Identidad y ciclo de vida de la app: nombre, id del paquete, versiĂłn, si la app estĂĄ en primer plano, y eventos de pausa/reanudaciĂłn (@capacitor/app 8.1.0).
Devuelve: getInfo() → { name, id, build, version }; getState() → { isActive }; getLaunchUrl() → { url } o nada; getAppLanguage() → { value }; exitApp() / minimizeApp() → void. addListener() → una Promesa de un identificador con remove(), como en la API propia de Capacitor: usa await con él o encadena .then(); el valor devuelto también tiene remove() por sí mismo. Requiere: nada que activar: todas las apps alojan el plugin. window.Capacitor existe en las páginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app en modo Sitio web, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que abra la app. Detecta la función.
var App = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.App;
if (App) {
App.getInfo().then(function (i) {
document.getElementById('about').textContent = i.name + ' ' + i.version + ' (' + i.build + ')';
});
}Pausar y reanudar: guarda un borrador cuando el usuario se va y actualiza cuando vuelve:
if (App) {
App.addListener('appStateChange', function (s) {
if (!s.isActive) saveDraft(); // went to the background
else refreshInbox(); // back in front
});
App.addListener('pause', function () { console.log('paused'); });
App.addListener('resume', function () { console.log('resumed'); });
}En una app creada con IA:
import { App } from '@/lib/appmintNative';
const info = await App.getInfo(); // { name, id, build, version }
App.exitApp(); // closes the app on AndroidNotas: El evento backButton nunca se dispara: la app conserva el botĂłn atrĂĄs (el plugin se ejecuta con disableBackButtonHandler). Gestiona el botĂłn atrĂĄs con AppMint.setBackHandler(fn) o el wrapper onBackGesture. Para enlaces profundos usa WebToApk.getLaunchUrl() / el evento appmint:deep-link (o launchUrl() / onDeepLink() en apps creadas con IA). minimizeApp() es solo para Android. Nunca hagas que un botĂłn Salir sea la Ăşnica forma de avanzar.
Capacitor.AppLauncher Capacitor#
Capacitor.Plugins.AppLauncher — canOpenUrl({ url }), openUrl({ url })
Ejemplo
Abre otra app mediante un enlace (whatsapp://send?text=…, tel:, geo:, un enlace https) y pregunta si alguna puede gestionarlo (@capacitor/app-launcher 8.0.1).
Devuelve: canOpenUrl() → Promise { value: boolean }. openUrl() → Promise { completed: boolean } (false cuando ninguna app aceptĂł el enlace). Requisitos: no hay que activar nada: todas las apps incluyen el plugin. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
var AL = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppLauncher;
async function chatOnWhatsApp(text) {
if (!AL) return;
var url = 'whatsapp://send?text=' + encodeURIComponent(text);
var can = await AL.canOpenUrl({ url: url });
if (!can.value) { alert('WhatsApp is not installed'); return; }
var r = await AL.openUrl({ url: url });
if (!r.completed) alert('Could not open WhatsApp');
}En una app creada con IA:
import { appLauncher } from '@/lib/appmintNative';
if (await appLauncher.canOpen('tel:+15551234567')) await appLauncher.open('tel:+15551234567');Abre un enlace de mapa sin preguntar antes:
async function openMap(query) {
const AL = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppLauncher;
if (!AL) { window.open('https://maps.google.com/?q=' + encodeURIComponent(query)); return; }
const r = await AL.openUrl({ url: 'geo:0,0?q=' + encodeURIComponent(query) });
if (!r.completed) alert('No maps app could open this');
}Notas: En Android 11+ una app solo puede "ver" otras apps que declare. Las apps generadas declaran enlaces https, geo, google.navigation, tel, mailto, sms, whatsapp, intent y upi, asĂ que canOpenUrl responde false para otros esquemas (por ejemplo spotify:) aunque la app estĂŠ instalada. openUrl sigue funcionando con ellos: llĂĄmalo y comprueba completed. En Android canOpenUrl tambiĂŠn acepta un nombre de paquete ('com.whatsapp'), con el mismo lĂmite de visibilidad.
Capacitor.AppUpdate Capacitor#
Capacitor.Plugins.AppUpdate — getAppUpdateInfo(), performImmediateUpdate(), startFlexibleUpdate(), completeFlexibleUpdate(), openAppStore()
Ejemplo
Comprueba en Google Play si hay una versiĂłn mĂĄs nueva de la app e inicia la actualizaciĂłn dentro de la app de Play. Incluido @capawesome/capacitor-app-update (template/plugins/app-update).
Devuelve: getAppUpdateInfo() → { currentVersionName, currentVersionCode, availableVersionCode, updateAvailability, updatePriority, immediateUpdateAllowed, flexibleUpdateAllowed, clientVersionStalenessDays?, installStatus } (los cĂłdigos de versiĂłn son cadenas; updateAvailability 2 = hay una actualizaciĂłn disponible). performImmediateUpdate() / startFlexibleUpdate() → { code }: 0 correcto, 1 cancelado, 2 fallido, 3 no disponible, 4 no permitido, 5 llama primero a getAppUpdateInfo(). openAppStore() → void. Requisitos: no hay que activar nada; la app debe estar instalada desde Google Play. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
var AU = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppUpdate;
async function checkForUpdate() {
if (!AU) return;
try {
var info = await AU.getAppUpdateInfo(); // must come first
if (info.updateAvailability !== 2) return; // up to date
if (info.immediateUpdateAllowed) {
var r = await AU.performImmediateUpdate(); // Play's full-screen update
if (r.code === 1) console.log('user said not now');
} else {
await AU.openAppStore(); // the Play listing
}
} catch (e) {
console.log('Play update check failed:', e.message); // e.g. no Play services
}
}ActualizaciĂłn flexible: descarga en segundo plano y luego reinicia cuando el usuario acepte:
async function flexibleUpdate() {
if (!AU) return;
var info = await AU.getAppUpdateInfo();
if (info.updateAvailability !== 2 || !info.flexibleUpdateAllowed) return;
await AU.addListener('onFlexibleUpdateStateChange', function (s) {
if (s.installStatus === 2) console.log(s.bytesDownloaded + ' / ' + s.totalBytesToDownload);
if (s.installStatus === 11) showRestartButton(); // 11 = DOWNLOADED
});
await AU.startFlexibleUpdate();
}
function restartNow() { if (AU) AU.completeFlexibleUpdate(); }En una app creada con IA:
import { appUpdate } from '@/lib/appmintNative';
const info = await appUpdate.check(); // null on the web / without Play
if (info?.inPlace) await appUpdate.start(); // Android: immediate updateNotas: Usa updateAvailability === 2 como Ăşnica prueba de "actualizaciĂłn disponible". El check() del wrapper compara currentVersionName con availableVersionCode, que nunca son iguales en Android, asĂ que su updateAvailable no es fiable allĂ: comprueba inPlace en su lugar. start() se resuelve true incluso cuando el usuario cancela.
Capacitor.AppwrightDocScanner Capacitor#
Capacitor.Plugins.AppwrightDocScanner — scan({ pageLimit, pdf, quality }), isSupported()
Ejemplo
Abre el escĂĄner de documentos de Google ML Kit: el usuario fotografĂa una o mĂĄs pĂĄginas (o las importa), se detectan y enderezan los bordes, y las pĂĄginas vuelven como imĂĄgenes JPEG. Plugin propio de Appwright (AppwrightDocScannerPlugin.kt).
Devuelve: scan() → Promise que siempre SE RESUELVE: { ok: true, pages: string[] (JPEG data URLs), pdfDataUrl?, pdfPath?, pdfError? } si todo va bien, { ok: false, cancelled: true } cuando el usuario retrocede, { ok: false, error } cuando el escĂĄner no puede iniciarse. isSupported() → { value: boolean } (Google Play services presente). Requisitos: no hay que activar nada ni se necesita permiso de cĂĄmara (el escĂĄner se ejecuta dentro de Play services, que descarga su modelo la primera vez).
var Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightDocScanner;
async function scanReceipt() {
if (!Scanner) { alert('Scanning is not available here'); return; }
var s = await Scanner.isSupported();
if (!s.value) { alert('This phone has no Google Play services'); return; }
var r = await Scanner.scan({ pageLimit: 1, pdf: false, quality: 0.8 });
if (r.cancelled) return;
if (!r.ok) { alert('Scanner error: ' + r.error); return; }
document.getElementById('preview').src = r.pages[0];
}pageLimit 0 = sin lĂmite. quality es 0.1-1 para el JPEG. Con pdf: true el escĂĄner tambiĂŠn escribe un PDF: pdfDataUrl es ese PDF como URL data:application/pdf;base64,… que la pĂĄgina puede descargar, subir o mostrar, y pdfPath es su copia en la carpeta de cachĂŠ de la app. Si no se pudo leer el PDF, las pĂĄginas igualmente se devuelven y pdfError explica el motivo.
En una app creada con IA (null al cancelar, ante un error o en la web):
import { docScanner, can } from '@/lib/appmintNative';
if (can('docScanner') !== 'none') {
const res = await docScanner.scan({ pageLimit: 5, pdf: true });
if (res) setPages(res.pages); // res.pdfPath when pdf: true
}Escanea varias pĂĄginas y ofrece el PDF:
async function scanContract() {
const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightDocScanner;
if (!Scanner) return;
const r = await Scanner.scan({ pageLimit: 0, pdf: true, quality: 0.9 });
if (!r.ok) { if (!r.cancelled) alert('Scanner error: ' + r.error); return; }
if (r.pdfDataUrl) {
const a = document.createElement('a');
a.href = r.pdfDataUrl; a.download = 'contract.pdf'; a.click();
} else if (r.pdfError) console.warn('PDF not made:', r.pdfError);
console.log(r.pages.length + ' pages scanned');
}Notas: Las pĂĄginas son data URLs completas y pueden ser grandes: reduce su tamaĂąo antes de guardar muchas en localStorage. Usa pdfDataUrl, no pdfPath: la ruta de un archivo del dispositivo no es una URL que la pĂĄgina pueda cargar. Una pĂĄgina que no se pueda leer se omite; el resto sigue devolviĂŠndose.
Capacitor.AppwrightGallery Capacitor#
Capacitor.Plugins.AppwrightGallery — save({ source, fileName, album, kind })
Ejemplo
Guarda una foto o un vĂdeo en la galerĂa del telĂŠfono (Pictures/<album> o Movies/<album>). Plugin propio de la app (AppwrightGalleryPlugin.kt).
Devuelve: Promise de { uri } del elemento guardado. Se rechaza con un code: bad-source, download-failed, permission-denied (Android 7-9, almacenamiento denegado) o failed. Requisitos: no hay que activar nada; sin permisos en Android 10+ (Android 7-9 pide almacenamiento la primera vez).
const Gallery = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightGallery;
async function saveCard(canvas) {
const dataUrl = canvas.toDataURL('image/png');
if (!Gallery) { const a = document.createElement('a'); a.href = dataUrl; a.download = 'card.png'; a.click(); return; }
try {
await Gallery.save({ source: dataUrl, fileName: 'birthday-card.png', album: 'Cards' });
toast('Saved to your gallery');
} catch (e) {
toast('Could not save: ' + e.message);
}
}Guarda un vĂdeo de tu servidor en su propio ĂĄlbum, con un mensaje para cada cĂłdigo de fallo:
const Gallery = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightGallery;
async function saveClip(url) {
if (!Gallery) { window.open(url, '_blank'); return; }
try {
await Gallery.save({ source: url, fileName: 'highlight.mp4', album: 'Highlights', kind: 'video' });
toast('Video saved to Movies/Highlights');
} catch (e) {
if (e.code === 'download-failed') toast('Could not download the video. Check your connection.');
else if (e.code === 'permission-denied') toast('Allow storage access to save videos.');
else toast('Could not save: ' + e.message);
}
}Guarda una foto que el usuario editĂł como Blob (por ejemplo desde canvas.toBlob) convirtiĂŠndola primero en una URL data::
const Gallery = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightGallery;
function blobToDataUrl(blob) {
return new Promise((resolve, reject) => {
const r = new FileReader();
r.onload = () => resolve(r.result);
r.onerror = () => reject(r.error);
r.readAsDataURL(blob);
});
}
async function saveEditedPhoto(canvas) {
if (!Gallery) return;
const blob = await new Promise((res) => canvas.toBlob(res, 'image/jpeg', 0.92));
const { uri } = await Gallery.save({ source: await blobToDataUrl(blob), fileName: 'edit-' + Date.now() + '.jpg', album: 'My Edits' });
console.log('saved as', uri);
}Notas: source es una URL data:, una URL http(s) o un URI content:///file://; kind ('image'/'video') se lee del tipo MIME cuando se omite. Las apps creadas con IA usan saveToGallery() de @/lib/appmintNative.
Capacitor.AppwrightHaptics Capacitor#
Capacitor.Plugins.AppwrightHaptics
Ejemplo
Plugin propio de AppMint para patrones de vibraciĂłn avanzados: una lista de pulsos, cada uno con su propio inicio, duraciĂłn e intensidad.
Devuelve: play({ events }) se resuelve { ok: true } o { ok: false, error } ('unsupported' = sin vibrador, 'empty' = sin eventos, o el mensaje del sistema). Nunca se rechaza. isSupported() se resuelve { value: true/false }. Requisitos: no hay que activar nada: todas las apps declaran el permiso de vibraciĂłn, tenga o no marcado Vibrate en el Paso 4 (Access). window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
Cada evento es { at, duration, intensity, sharpness }: at = inicio en ms, duration = duraciĂłn en ms (menos de 20 se convierte en un toque de 30 ms), intensity = 0-1 (por defecto 0.8). sharpness se acepta pero se ignora en Android.
var AH = window.Capacitor && window.Capacitor.Plugins ? window.Capacitor.Plugins.AppwrightHaptics : null;
async function heartbeat() {
if (!AH) return false;
var r = await AH.play({
events: [
{ at: 0, intensity: 0.8 },
{ at: 140, intensity: 0.5 },
{ at: 700, intensity: 0.8 },
{ at: 840, intensity: 0.5 }
]
});
if (!r.ok) console.log('pattern not played:', r.error);
return r.ok;
}
document.getElementById('like').addEventListener('click', heartbeat);Oculta el botĂłn en telĂŠfonos sin vibrador:
(async function () {
var btn = document.getElementById('feel-it');
var ok = false;
if (AH) { try { ok = (await AH.isSupported()).value; } catch (e) {} }
btn.hidden = !ok;
})();Haz un doble toque rĂĄpido ante una acciĂłn exitosa e informa cuando no se pueda reproducir:
async function successBuzz() {
const AH = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightHaptics;
if (!AH) return;
const r = await AH.play({ events: [{ at: 0, duration: 40, intensity: 1 }, { at: 120, duration: 40, intensity: 0.6 }] });
if (!r.ok && r.error === 'unsupported') console.log('this phone has no vibrator');
}Notas: La intensidad solo funciona en telĂŠfonos con control de amplitud; los demĂĄs mantienen el ritmo con una intensidad fija. Si el sistema rechaza la vibraciĂłn, play responde { ok: false, error: '<the system message>' }. En las apps creadas con IA usa hapticPlay de @/lib/appmintNative, que ademĂĄs tiene patrones con nombre.
Capacitor.AppwrightLiveProgress Capacitor#
Capacitor.Plugins.AppwrightLiveProgress — start / update / end
Ejemplo
El plugin de Android propio de AppMint (su nombre en JS es AppwrightLiveProgress) para una notificaciĂłn de estado fija, silenciosa y que se actualiza en vivo (barra de progreso, indicador de carga o reloj en marcha) y que abre una ruta al tocarla.
Devuelve: start(opts) / update(opts) → Promise<{ ok: true, id }>, o { ok: false, error } sin que se publique nada: 'permission' cuando las notificaciones no estĂĄn permitidas (Android 13+: aĂşn no concedido, o desactivado para la app), 'channel_disabled' cuando el usuario desactivĂł la categorĂa "Live status"; end({ id }) → Promise<void>. Requisitos: la app de Android y el permiso de notificaciones (Android 13+). No disponible en la web.
En una app creada con IA usa el wrapper liveProgress de @/lib/appmintNative:
import { liveProgress } from '@/lib/appmintNative';
await liveProgress.start({ id: 'order', title: 'Order #42', text: 'Being prepared', indeterminate: true });
await liveProgress.update({ id: 'order', title: 'Order #42', text: 'On the way', progress: 0.6, route: '/orders/42' });
await liveProgress.end('order');En una pĂĄgina escrita a mano:
async function showDelivery(step, total) {
const P = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightLiveProgress;
if (!P) return; // not in the Android app
if (window.Notification && Notification.permission !== 'granted') {
if (await Notification.requestPermission() !== 'granted') return;
}
const r = await P.update({
id: 'delivery',
title: 'Your delivery',
text: 'Stop ' + step + ' of ' + total,
progress: step / total, // 0–1; or indeterminate: true
route: '/track' // opened when the card is tapped
});
if (!r.ok) console.warn('live card not posted:', r.error);
}
async function deliveryDone() {
const P = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightLiveProgress;
if (P) await P.end({ id: 'delivery' });
}Un temporizador de entrenamiento: startedAt hace que la tarjeta cuente hacia arriba por sĂ sola, asĂ que se publica una vez y se termina cuando acaba el entrenamiento:
const Live = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightLiveProgress;
let workoutStart = 0;
async function startWorkout(name) {
workoutStart = Date.now();
if (!Live) return;
const r = await Live.start({ id: 'workout', title: name, text: 'Workout in progress', startedAt: workoutStart, route: '/workout' });
if (!r.ok && r.error === 'channel_disabled') {
showHint('Turn on "Live status" in this app\'s notification settings to see the timer.');
}
}
async function stopWorkout() {
if (Live) await Live.end({ id: 'workout' });
saveWorkout({ durationMs: Date.now() - workoutStart });
}Opciones: id (por defecto 'live'), title, text, progress (0-1, omĂtelo para no mostrar barra), indeterminate, startedAt (ms de ĂŠpoca, muestra un reloj en marcha), route.
Notas: start y update hacen lo mismo (publicar o reemplazar la tarjeta con ese id). La tarjeta no se puede descartar deslizando: llama siempre a end. Pide primero el permiso: en Android 13+ sin ĂŠl, start responde error: 'permission' y no publica nada.
Capacitor.AppwrightSystemPalette Capacitor#
Capacitor.Plugins.AppwrightSystemPalette — get()
Ejemplo
Devuelve los colores Material You del telĂŠfono (la paleta que Android 12+ genera a partir del fondo de pantalla), para que la app combine con las apps del sistema. Plugin propio de AppMint (AppwrightSystemPalettePlugin.kt).
Devuelve: Promise { available: false } en versiones anteriores a Android 12, y { available: true, accent1, accent2, accent3, neutral1, neutral2 } en las demĂĄs; cada uno es un objeto de tono a color hexadecimal, con tonos '0', '10', '50', '100' … '900', '1000' (p. ej. accent1['600'] === '#3F5F90'). Requisitos: no hay que activar nada: todas las apps incluyen el plugin. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
var Palette = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightSystemPalette;
async function useWallpaperColours() {
if (!Palette) return;
var p = await Palette.get();
if (!p.available) return; // keep the app's own colours
var root = document.documentElement.style;
root.setProperty('--accent', p.accent1['600']);
root.setProperty('--surface', p.neutral1['50']);
}
useWallpaperColours();En una app creada con IA:
import { systemPalette } from '@/lib/appmintNative';
const p = await systemPalette();
if (p.available && p.accent1) document.documentElement.style.setProperty('--accent', p.accent1['600']);Elige tonos claros u oscuros segĂşn el tema del sistema y vuelve a leer la paleta cuando el usuario regrese tras cambiar el fondo de pantalla:
var Palette = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightSystemPalette;
var darkQuery = window.matchMedia('(prefers-color-scheme: dark)');
async function applyPalette() {
if (!Palette) return;
var p = await Palette.get();
if (!p.available) return;
var dark = darkQuery.matches;
var s = document.documentElement.style;
s.setProperty('--accent', p.accent1[dark ? '200' : '600']);
s.setProperty('--on-accent', p.accent1[dark ? '800' : '0']);
s.setProperty('--bg', p.neutral1[dark ? '900' : '10']);
s.setProperty('--text', p.neutral1[dark ? '100' : '900']);
}
darkQuery.addEventListener('change', applyPalette);
document.addEventListener('visibilitychange', function () {
if (document.visibilityState === 'visible') applyPalette();
});
applyPalette();Notas: Comprueba el contraste del texto antes de aplicar los colores de la paleta: no se garantiza que un tono del fondo de pantalla se lea bien sobre tu fondo. Los navegadores no exponen los colores del fondo de pantalla: en la web el wrapper responde { available: false }. Los colores cambian cuando el usuario cambia el fondo de pantalla; vuelve a llamar a get() al reanudar.
Capacitor.AppwrightWidget Capacitor#
Capacitor.Plugins.AppwrightWidget — set(card), clear(), placedCount(), requestPin()
Ejemplo
Rellena el widget de la pantalla de inicio de la app: una tarjeta con tĂtulo, un valor grande, hasta doce lĂneas, tus colores y una ruta al tocar; es la misma tarjeta que acepta AppMint.widget.set(), con todas sus claves. La tarjeta se guarda en el telĂŠfono y se muestra incluso tras reiniciar. Plugin propio de AppMint (AppwrightWidgetPlugin.kt).
Devuelve: set({ title?, value?, caption?, lines?, route?, bg?, ink?, accent?, textSize?, align?, wrap?, … }) → Promise { ok: true, placed }, rechazada con el motivo cuando la tarjeta no es vĂĄlida (placed = widgets que hay ahora en la pantalla de inicio). clear() → void. placedCount() → { value }. requestPin() → { value: boolean } (true cuando se abriĂł la hoja de "aĂąadir widget" del launcher). Requisitos: no hay que activar nada: todas las apps declaran el widget. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
var Widget = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.AppwrightWidget;
async function updateWidget(tasks) {
if (!Widget) return;
await Widget.set({
title: 'Today',
value: tasks.length + ' tasks',
lines: tasks.slice(0, 6).map(function (t) { return t.title; }),
route: '/today', // opened when the widget is tapped
bg: '#0B0F1A', ink: '#FFFFFF', accent: '#22D3EE'
});
}Ofrece colocarlo (solo cuando aĂşn no hay ninguno colocado):
async function offerWidget() {
if (!Widget) return;
var n = (await Widget.placedCount()).value;
if (n > 0) return;
var r = await Widget.requestPin();
if (!r.value) alert('Long-press the home screen, tap Widgets and pick this app.');
}En una app creada con IA:
import { widget } from '@/lib/appmintNative';
await widget.set({ title: 'Today', value: '3 tasks', lines: ['Gym', 'Call mum'], route: '/today' });
if ((await widget.placedCount()) === 0) await widget.requestPin();Notas: Los colores son #RRGGBB, #AARRGGBB (alfa primero) o rgba(); los vacĂos usan una tarjeta oscura con un valor cian. Consulta AppMint.widget para lĂneas con estilo, caption, textSize, align, wrap y font (tu propio archivo .ttf/.otf, indicado como una ruta en tu app). El toque abre la app en route como enlace profundo (lĂŠelo con WebToApk.getLaunchUrl() o el evento appmint:deep-link). Antes de cualquier set() el widget muestra "Nothing to show yet"; clear() lo devuelve a ese estado. En un navegador can('widget') es 'none'.
Capacitor.Badge Capacitor#
Capacitor.Plugins.Badge — the launcher-icon count
Ejemplo
El plugin Badge (capawesome) que pone el nĂşmero en el icono de la app en el launcher.
Devuelve: Promises: set({ count }), clear(), increase(), decrease() → void; get() → { count }; isSupported() → { isSupported }. El plugin de Android no tiene mĂŠtodos de permisos. Requisitos: nada en Android. No disponible en la web.
En una app creada con IA usa el wrapper badge de @/lib/appmintNative:
import { badge } from '@/lib/appmintNative';
await badge.set(3);
await badge.clear();En una pĂĄgina escrita a mano:
async function setUnread(count) {
const B = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Badge;
if (!B) return false; // not inside the app
try {
const s = await B.isSupported();
if (!s.isSupported) return false; // this launcher shows no badges
if (count > 0) await B.set({ count: count });
else await B.clear();
return true;
} catch (e) {
return false;
}
}
window.addEventListener('appmint:push', function () {
const inbox = JSON.parse(window.WebToApk ? WebToApk.getPushInbox() : '[]');
setUnread(inbox.filter(function (m) { return !m.read; }).length);
});Cuenta hacia arriba y hacia abajo a medida que los elementos llegan y se leen:
const B = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Badge;
async function onNewMessage() { if (B) await B.increase(); }
async function onMessageRead() { if (B) await B.decrease(); }
async function showCurrent() {
if (!B) return;
const { count } = await B.get();
console.log('badge shows', count);
}Notas: en Android el aspecto depende del launcher (un nĂşmero, un punto, o nada). navigator.setAppBadge(n) en la app escribe en la misma insignia (solo existe en launchers que pueden mostrar un contador).
Capacitor.BarcodeScanner Capacitor#
Capacitor.Plugins.BarcodeScanner — scan, startScan, readBarcodesFromImage, isSupported
Ejemplo
Escaneo de QR y cĂłdigos de barras con la API de @capacitor-mlkit/barcode-scanning: el plugin propio de la app (BarcodeScannerPlugin.kt) sobre el mismo escĂĄner de cĂłdigos de Google que AppMint.scanCode(). Las llamadas antiguas de @capacitor-community/barcode-scanner (startScan() que devuelve { hasContent, content }, checkPermission, prepare, hideBackground) comparten este nombre y tambiĂŠn funcionan.
Devuelve: scan({ formats?, autoZoom? }) → { barcodes: [{ rawValue, displayValue, format, valueType, bytes?, cornerPoints?, urlBookmark?, wifi?, email?, phone?, sms?, geoPoint?, contactInfo?, calendarEvent?, driverLicense? }] } (se rechaza con "scan canceled." cuando el usuario retrocede); readBarcodesFromImage({ path, formats? }) → { barcodes }; isSupported() → { supported }; isGoogleBarcodeScannerModuleAvailable() → { available }; installGoogleBarcodeScannerModule() (progreso como googleBarcodeScannerModuleInstallProgress); checkPermissions() / requestPermissions() → { camera }; openSettings(). format es 'QR_CODE', 'EAN_13', 'CODE_128'… Requisitos: no hay que activar nada ni se necesita permiso de cĂĄmara: el escĂĄner de Google dibuja su propia pantalla (Play services la descarga la primera vez). window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.BarcodeScanner;
scanBtn.onclick = async () => {
if (!Scanner) return;
try {
const { barcodes } = await Scanner.scan({ formats: ['QR_CODE'] });
const code = barcodes[0];
if (code.valueType === 'URL') location.href = code.urlBookmark.url;
else resultBox.textContent = code.displayValue;
} catch (e) {
if (e.message !== 'scan canceled.') alert(e.message);
}
};Consulta de precio a partir del cĂłdigo de barras de un producto, con el estilo de listener (startScan + barcodesScanned) que ya usan las apps con ML Kit:
const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.BarcodeScanner;
async function scanProduct() {
const listener = await Scanner.addListener('barcodesScanned', async ({ barcodes }) => {
await listener.remove();
await Scanner.stopScan();
const ean = barcodes[0].rawValue;
const res = await fetch('https://api.example.com/products/' + encodeURIComponent(ean));
priceBox.textContent = res.ok ? (await res.json()).price : 'Not found';
});
await Scanner.startScan({ formats: ['EAN_13', 'EAN_8', 'UPC_A', 'UPC_E'] });
}Lee un cĂłdigo QR de una foto que el usuario ya tiene:
const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.BarcodeScanner;
const Camera = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Camera;
async function qrFromGallery() {
const photo = await Camera.getPhoto({ source: 'PHOTOS', resultType: 'uri', quality: 90 });
const { barcodes } = await Scanner.readBarcodesFromImage({ path: photo.path, formats: ['QR_CODE'] });
return barcodes.length ? barcodes[0].rawValue : null;
}Notas: El startScan() original muestra una vista previa en vivo de la cámara detrás de una página transparente y sigue escaneando hasta stopScan(); aquí abre la pantalla del escáner, el primer código dispara barcodeScanned / barcodesScanned, y la sesión termina (la llamada entonces se resuelve con { hasContent, content, format } para el código de la comunidad; un escáner cerrado se resuelve con { hasContent: false }). La linterna y el zoom pertenecen a esa vista previa, así que isTorchAvailable() es false y los métodos para fijar linterna/zoom se rechazan: la pantalla del escáner tiene su propio botón de linterna. checkPermissions() responde granted cuando la app no tiene ningún permiso de cámara (el escáner no necesita ninguno); una app que también usa la cámara obtiene su estado real. Las apps creadas con IA usan scanCode() desde @/lib/appmintNative.
Capacitor.Browser Capacitor#
Capacitor.Plugins.Browser — open({ url, toolbarColor }), close(), addListener('browserFinished')
Ejemplo
Abre una pĂĄgina web en una pestaña de navegador dentro de la app (Chrome Custom Tabs), para que el usuario lea tĂŠrminos, documentaciĂłn o una pĂĄgina de inicio de sesiĂłn y vuelva con un solo gesto (@capacitor/browser 8.0.3).
Devuelve: open() / close() → Promise void. Eventos: browserFinished (el usuario cerrĂł la pestaña) y browserPageLoaded. Requisitos: nada: todas las apps incluyen el plugin (debe estar instalado un navegador compatible con Custom Tabs, como Chrome). window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
var Browser = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Browser;
async function openTerms() {
if (!Browser) return;
var h = await Browser.addListener('browserFinished', function () {
console.log('user closed the terms');
h.remove();
});
await Browser.open({ url: 'https://example.com/terms', toolbarColor: '#0B0F1A' });
}En una app creada con IA (una pestaña nueva en la web):
import { browser } from '@/lib/appmintNative';
const off = browser.onClosed(() => refreshAccount());
await browser.open('https://example.com/terms', { toolbarColor: '#0B0F1A' });
// call off() when you no longer careAbre un enlace y cierra la pestaña cuando un retorno de inicio de sesiĂłn llega a la pĂĄgina:
var Browser = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Browser;
async function openHelp() {
if (!Browser) { window.open('https://example.com/help', '_blank'); return; }
try {
await Browser.open({ url: 'https://example.com/help' });
} catch (e) {
alert('Could not open the page: ' + e.message);
}
}
window.addEventListener('appmint:deep-link', function () {
if (Browser) Browser.close().catch(function () {});
});Notas: url no debe estar vacĂo. toolbarColor es un color hexadecimal; uno no vĂĄlido se ignora. close() tambiĂŠn funciona en Android en esta versiĂłn del plugin (termina la activity anfitriona de la pestaña), Ăştil despuĂŠs de que un enlace de inicio de sesiĂłn vuelve a la app. La pestaña es un navegador aparte: no comparte las cookies de la app ni localStorage.
Capacitor.Calendar Capacitor#
Capacitor.Plugins.Calendar — createEvent, findEvents, deleteEvent, listCalendars, openCalendar
Ejemplo
AĂąade, busca y borra eventos en el calendario propio del telĂŠfono (Android CalendarContract), y abre la app de calendario en una fecha. Incluido @capacitor/calendar (template/plugins/calendar).
Devuelve: createEvent() → { id }; findEvents() → { events: [{ id, title, location?, notes?, startDate, endDate, isAllDay, calendarId, calendarName?, attendees? }] }; listCalendars() → { calendars: [{ id, name, displayName?, isPrimary }] }; deleteEvent(), openCalendar() → void. Las fechas son milisegundos de ĂŠpoca. Requisitos: marca Calendar en el Paso 4 (Access) al compilar. En las apps HTML, ZIP y creadas con IA, la compilaciĂłn tambiĂŠn aĂąade sola el permiso de calendario cuando tus archivos contienen una llamada Calendar.<method>( escrita exactamente asĂ (como abajo) o el calendar.createEvent( del wrapper. El plugin pide al usuario acceso al calendario la primera vez. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
var Calendar = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Calendar;
async function addDentist() {
if (!Calendar) return;
var start = new Date('2026-10-02T10:00:00').getTime();
try {
var r = await Calendar.createEvent({
title: 'Dentist', startDate: start, endDate: start + 60 * 60 * 1000,
location: 'Main St 5', notes: 'Bring the card', isAllDay: false,
firstReminderMinutes: 30
});
console.log('event id', r.id);
} catch (e) {
// e.code: OS-PLUG-CLDR-0020 permission denied, -0001 bad arguments
alert('Could not add the event: ' + e.message);
}
}Lee esta semana, borra uno, abre el calendario:
async function thisWeek() {
if (!Calendar) return;
var now = Date.now();
var found = await Calendar.findEvents({ startDate: now, endDate: now + 7 * 864e5 });
found.events.forEach(function (ev) { console.log(ev.title, new Date(ev.startDate)); });
if (found.events.length) await Calendar.deleteEvent({ id: found.events[0].id });
await Calendar.openCalendar({ date: now });
}En una app creada con IA (en la web createEvent descarga un archivo .ics; leer devuelve []):
import { calendar } from '@/lib/appmintNative';
if ((await calendar.requestPermission()) === 'granted') {
const id = await calendar.createEvent({ title: 'Dentist', start: new Date('2026-10-02T10:00'), end: new Date('2026-10-02T11:00') });
const week = await calendar.listEvents({ from: Date.now(), to: Date.now() + 7 * 864e5 });
if (id) await calendar.deleteEvent(id);
await calendar.openCalendar(new Date());
}Notas: Sin el permiso de calendario en la app no aparece ningĂşn diĂĄlogo y todas las llamadas de eventos se rechazan (falta de permiso); un usuario que dice que no recibe OS-PLUG-CLDR-0020. recurrence: { frequency: 'daily' | 'weekly' | 'monthly' | 'yearly', interval?, count?, endDate? } crea un evento repetitivo. createEventInteractively({ title, startDate, endDate }) abre en su lugar el propio editor de la app de calendario: se resuelve con { id } del evento guardado, y se rechaza con OS-PLUG-CLDR-0006 cuando el usuario cierra el editor sin guardar (necesita acceso de lectura ademĂĄs de escritura para distinguir ambos casos). deleteEvent({ id, fromDate }) termina un evento repetitivo antes de fromDate y conserva las repeticiones anteriores. El wrapper devuelve null / [] / false en lugar de lanzar errores.
Capacitor.Camera Capacitor#
Capacitor.Plugins.Camera
Ejemplo
El plugin oficial Capacitor Camera, incluido en la app: haz una foto con la cĂĄmara o elige fotos de la galerĂa.
Devuelve: Promises. getPhoto(opts) → { dataUrl | base64String | webPath, format, saved } (el campo depende de resultType), y SE RECHAZA cuando el usuario cancela; pickImages(opts) → { photos: [{ webPath, format }] }; checkPermissions() / requestPermissions({ permissions }) → { camera, photos }. Requisitos: marca Camera en el Paso 4 (Access). En las apps HTML, ZIP y creadas con IA, la compilaciĂłn tambiĂŠn aĂąade sola el permiso de cĂĄmara cuando tus archivos contienen Camera.getPhoto( escrito exactamente asĂ (como abajo), getUserMedia con vĂdeo, o <input capture>. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
Toma una foto y muéstrala.
async function takePhoto() {
var Camera = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Camera;
if (!Camera) { showMessage('Open the app to use the camera.'); return; }
try {
var perm = await Camera.requestPermissions({ permissions: ['camera'] });
if (perm.camera !== 'granted') { showMessage('Camera permission was refused.'); return; }
var photo = await Camera.getPhoto({
source: 'CAMERA', // 'CAMERA' | 'PHOTOS' | 'PROMPT'
resultType: 'dataUrl', // 'dataUrl' | 'base64' | 'uri'
quality: 80,
direction: 'REAR', // 'REAR' | 'FRONT'
correctOrientation: true,
saveToGallery: false
});
document.getElementById('photo').src = photo.dataUrl;
} catch (err) {
// The user closed the camera (or no camera app). Nothing to do.
}
}Elige hasta 5 fotos de la galerĂa.
async function choosePhotos() {
var Camera = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Camera;
if (!Camera) return;
try {
var result = await Camera.pickImages({ quality: 80, limit: 5 });
result.photos.forEach(function (p) {
var img = document.createElement('img');
img.src = p.webPath; // a URL the page can load
document.getElementById('gallery').appendChild(img);
});
} catch (err) { /* cancelled */ }
}En una app creada con IA usa el wrapper, que tambiĂŠn funciona en la web (y devuelve null en lugar de lanzar un error al cancelar):
import { camera } from '@/lib/appmintNative';
const photo = await camera.take({ source: 'camera' });Notas: pickImages no necesita permiso de cĂĄmara. Si el permiso de cĂĄmara no estĂĄ en la app (la casilla estaba desmarcada y la compilaciĂłn no encontrĂł ninguna llamada a la cĂĄmara), el permiso de cĂĄmara se rechaza sin pedirlo. Un <input type="file" accept="image/*" capture> tambiĂŠn abre la cĂĄmara. La cĂĄmara es sensible: decl\u00e1rala en tu formulario de seguridad de los datos de Play.
Capacitor.CapacitorBarcodeScanner Capacitor#
Capacitor.Plugins.CapacitorBarcodeScanner — scanBarcode({ hint })
Ejemplo
Escaneo de QR / cĂłdigos de barras en una sola llamada con la API oficial de @capacitor/barcode-scanner: el plugin propio de la app (CapacitorBarcodeScannerPlugin.kt) sobre el mismo escĂĄner de cĂłdigos de Google que AppMint.scanCode(). El cĂłdigo escrito para el paquete de npm (CapacitorBarcodeScanner.scanBarcode({ hint: CapacitorBarcodeScannerTypeHint.ALL })) funciona sin cambios.
Devuelve: scanBarcode({ hint, scanInstructions?, cameraDirection?, scanOrientation? }) → { ScanResult, format }. hint / format son los nĂşmeros del paquete: 0 QR_CODE, 1 AZTEC, 2 CODABAR, 3 CODE_39, 4 CODE_93, 5 CODE_128, 6 DATA_MATRIX, 8 ITF, 9 EAN_13, 10 EAN_8, 11 PDF_417, 14 UPC_A, 15 UPC_E, 17 ALL. Se rechaza con el cĂłdigo OS-PLUG-BARC-0006 cuando el usuario cierra el escĂĄner. Requisitos: no hay que activar nada ni se necesita permiso de cĂĄmara: el escĂĄner de Google dibuja su propia pantalla (Play services la descarga la primera vez). window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorBarcodeScanner;
ticketBtn.onclick = async () => {
if (!Scanner) return;
try {
const { ScanResult } = await Scanner.scanBarcode({ hint: 0 }); // QR codes only
const ok = await fetch('/api/tickets/check?code=' + encodeURIComponent(ScanResult)).then((r) => r.ok);
statusBox.textContent = ok ? 'Valid ticket' : 'Unknown ticket';
} catch (e) {
if (e.code !== 'OS-PLUG-BARC-0006') alert(e.message);
}
};Acepta cualquier cĂłdigo e indica al usuario de quĂŠ tipo era:
const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorBarcodeScanner;
const NAMES = { 0: 'QR code', 5: 'Code 128', 9: 'EAN-13', 10: 'EAN-8', 14: 'UPC-A', 15: 'UPC-E' };
async function scanAnything() {
const { ScanResult, format } = await Scanner.scanBarcode({ hint: 17 });
return (NAMES[format] || 'Barcode') + ': ' + ScanResult;
}Gestiona un rechazo que no se debe a que el usuario cerrĂł el escĂĄner:
const Scanner = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorBarcodeScanner;
async function scanProduct() {
if (!Scanner) { alert('Scanning works only inside the app'); return null; }
try {
const { ScanResult } = await Scanner.scanBarcode({ hint: 9 }); // EAN-13
return ScanResult;
} catch (e) {
if (e.code === 'OS-PLUG-BARC-0006') return null; // user closed the scanner
alert('Scan failed: ' + e.message);
return null;
}
}Notas: scanInstructions, scanButton, cameraDirection y scanOrientation dan estilo a la pantalla de cĂĄmara propia del plugin original y no tienen efecto en el escĂĄner de Google (siempre la cĂĄmara trasera). MAXICODE, RSS_14, RSS_EXPANDED y UPC_EAN_EXTENSION no se admiten como hint (se rechaza con OS-PLUG-BARC-0008); 17 (ALL) escanea todos los tipos admitidos. Las apps creadas con IA usan scanCode() de @/lib/appmintNative.
Capacitor.CapacitorCookies Capacitor#
Capacitor.Plugins.CapacitorCookies — getCookies / setCookie / deleteCookie / clearCookies / clearAllCookies
Ejemplo
Lee y escribe las cookies de la app, incluidas las de otro host con el que habla tu pĂĄgina (el de Capacitor core CapacitorCookies).
Devuelve: getCookies({ url? }) → { [name]: value }: con una url, las cookies que esa URL (host y ruta) enviaría; sin ella, el document.cookie propio de la página. Rechaza una url que no sea http(s). setCookie({ key, value, url?, path?, expires? }), deleteCookie({ key, url? }), clearCookies({ url? }), clearAllCookies() → Promesa void; setCookie / deleteCookie se rechazan sin una key de tipo cadena (y value) y entonces no escriben nada. Requiere: nada que activar: todas las apps alojan el plugin. window.Capacitor existe en las páginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app en modo Sitio web, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que abra la app. Detecta la función.
var Cookies = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorCookies;
// Read the session cookie your API host set — not the page's own cookies.
async function apiSession() {
if (!Cookies) return null; // not inside the app
var jar = await Cookies.getCookies({ url: 'https://api.example.com/' });
return jar.session || null;
}
// Remember a choice for the API host, for 30 days, on one path only.
async function rememberRegion(region) {
if (!Cookies) return;
var expires = new Date(Date.now() + 30 * 864e5).toUTCString();
await Cookies.setCookie({ url: 'https://api.example.com', path: '/v2', key: 'region', value: region, expires: expires });
}Cerrar sesiĂłn: elimina las cookies de ese host, o todas las cookies que guarda la app.
async function signOut(everything) {
if (!Cookies) return;
if (everything) await Cookies.clearAllCookies();
else await Cookies.clearCookies({ url: 'https://api.example.com' });
}Notas: Una cookie establecida con un path solo se devuelve para una url bajo esa ruta. Los valores se decodifican de URL al leerse. Las cookies las comparten todas las pĂĄginas que muestra la app, asĂ que nunca guardes secretos en una que una pĂĄgina externa pueda leer: van en Preferences o en el almacenamiento seguro de la app.
Capacitor.CapacitorSQLite Capacitor#
Capacitor.Plugins.CapacitorSQLite — createConnection, open, execute, query, run, executeSet, close
Ejemplo
Una base de datos SQLite real en el telĂŠfono, con la API de @capacitor-community/sqlite. Incluye @capacitor-community/sqlite (template/plugins/sqlite) y se ejecuta sobre el SQLite propio de Android. El cĂłdigo escrito para el paquete de npm (new SQLiteConnection(CapacitorSQLite)) funciona sin cambios; una pĂĄgina escrita a mano llama directamente al objeto del plugin, como se muestra abajo.
Devuelve: createConnection({ database, version, encrypted: false, mode: 'no-encryption', readonly: false }), open({ database }), close({ database }), closeConnection({ database }) → void; execute({ database, statements }) → { changes: { changes } }; run({ database, statement, values }) → { changes: { changes, lastId } }; query({ database, statement, values }) → { values: [rows] }; executeSet({ database, set: [{ statement, values }] }) → { changes }; isDBExists({ database }) / isDBOpen({ database }) → { result }; beginTransaction, commitTransaction, rollbackTransaction, isTransactionActive({ database }); deleteDatabase({ database }); exportToJson / importFromJson para copias de seguridad. Requisitos: no hay que activar nada ni se necesita permiso. La base de datos vive en el almacenamiento privado de la app y sobrevive a las actualizaciones. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
const DB = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorSQLite;
const database = 'notes';
async function openNotes() {
if (!DB) return false;
await DB.createConnection({ database, version: 1, encrypted: false, mode: 'no-encryption', readonly: false });
await DB.open({ database, readonly: false });
await DB.execute({ database, statements:
'CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY AUTOINCREMENT, text TEXT NOT NULL, at INTEGER);' });
return true;
}
async function addNote(text) {
const r = await DB.run({ database, statement: 'INSERT INTO notes (text, at) VALUES (?, ?);', values: [text, Date.now()] });
return r.changes.lastId;
}
async function listNotes() {
const r = await DB.query({ database, statement: 'SELECT id, text, at FROM notes ORDER BY at DESC;', values: [] });
return r.values || [];
}Varias escrituras que deben aplicarse todas o ninguna: una sola transacciĂłn con executeSet:
const DB = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorSQLite;
async function moveMoney(database, fromId, toId, amount) {
await DB.executeSet({ database, transaction: true, set: [
{ statement: 'UPDATE accounts SET balance = balance - ? WHERE id = ?;', values: [amount, fromId] },
{ statement: 'UPDATE accounts SET balance = balance + ? WHERE id = ?;', values: [amount, toId] },
{ statement: 'INSERT INTO ledger (from_id, to_id, amount, at) VALUES (?, ?, ?, ?);', values: [fromId, toId, amount, Date.now()] },
] });
}Abre la base de datos solo una vez por inicio de la app, incluso cuando dos pantallas la piden a la vez:
const DB = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.CapacitorSQLite;
let ready = null;
function db(database) {
if (!ready) ready = (async () => {
try {
await DB.createConnection({ database, version: 1, encrypted: false, mode: 'no-encryption', readonly: false });
} catch (e) {
if (!/already exists/i.test(e.message)) throw e; // a page reload keeps the native connection
}
if (!(await DB.isDBOpen({ database, readonly: false })).result) await DB.open({ database, readonly: false });
return database;
})();
return ready;
}Notas: La app se compila sin SQLCipher, asĂ que las bases de datos no estĂĄn cifradas: encrypted: true, setEncryptionSecret, changeEncryptionSecret, isSecretStored y las demĂĄs llamadas de cifrado se rechazan con "Encryption is not available in this app". isInConfigEncryption() responde false. Todo lo demĂĄs (consultas, valores enlazados, transacciones, actualizaciones con versiones mediante addUpgradeStatement, importaciĂłn/exportaciĂłn JSON) es cĂłdigo propio del plugin. Los rechazos incluyen el texto de error de SQLite.
Capacitor.Clipboard Capacitor#
Capacitor.Plugins.Clipboard — write(options), read()
Ejemplo
Copia texto (o un enlace) al portapapeles del sistema y lo lee de vuelta (@capacitor/clipboard 8.0.1).
Devuelve: write({ string?, url?, image?, label? }) → Promesa void. read() → Promesa { value, type } (type es 'text/plain' para texto). Requiere: nada que activar: todas las apps alojan el plugin. window.Capacitor existe en las páginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app en modo Sitio web, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que abra la app. Detecta la función.
async function copyCode(code) {
var Clipboard = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Clipboard;
if (!Clipboard) { alert('Copy is not available here'); return; }
await Clipboard.write({ string: code, label: 'Invite code' });
}
async function pasteCode(input) {
var Clipboard = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Clipboard;
if (!Clipboard) return;
try {
var r = await Clipboard.read();
input.value = r.value;
} catch (e) {
// An EMPTY clipboard is a rejection: "There is no data on the clipboard".
if (/no data/i.test(e.message)) input.value = '';
else alert('Could not read the clipboard: ' + e.message);
}
}En una app creada con IA el wrapper con forma Capacitor convierte un portapapeles vacĂo en '':
import { Clipboard } from '@/lib/appmintNative';
await Clipboard.write({ string: 'ABC-123' });
const { value } = await Clipboard.read(); // '' when the clipboard is emptyCopia un enlace y confirma con un toque de respuesta hĂĄptica:
async function copyLink(url) {
var P = window.Capacitor && window.Capacitor.Plugins;
if (!P || !P.Clipboard) { alert('Copy is not available here'); return; }
await P.Clipboard.write({ url: url });
if (P.Haptics) P.Haptics.impact({ style: 'LIGHT' });
copiedToast.hidden = false;
}Notas: write necesita uno de string, url o image (una data URL); si no, se rechaza con "No data provided". Android 12+ muestra su propio aviso "pegado desde…" al leer: es el sistema operativo, no la app. El write del wrapper solo envĂa string || url.
Capacitor.Contacts Capacitor#
Capacitor.Plugins.Contacts — getContacts, getContact, pickContact, createContact, deleteContact
Ejemplo
La agenda de contactos del telĂŠfono con la API de @capacitor-community/contacts. Incluye @capacitor-community/contacts (template/plugins/contacts). El cĂłdigo escrito para el paquete de npm funciona sin cambios.
Devuelve: checkPermissions() / requestPermissions() → { contacts, contactsWrite } (cada uno 'granted' | 'denied' | 'prompt'; contacts es lectura, contactsWrite es aĂąadir y borrar); getContacts({ projection }) → { contacts: [ContactPayload] }; getContact({ contactId, projection }) y pickContact({ projection }) → { contact }; createContact({ contact }) → { contactId }; deleteContact({ contactId }) → void. projection elige los campos: { name, phones, emails, organization, birthday, note, urls, postalAddresses, image } (cada uno true). Requisitos: marca Contacts en el Paso 4 (Access) para leer, y tambiĂŠn Edit Contacts para aĂąadir o borrar. Las compilaciones HTML, ZIP y AI-Studio los marcan solas cuando el cĂłdigo llama a Contacts.getContacts( / getContact( / pickContact( (lectura) o a Contacts.createContact( / deleteContact( (ambos). El plugin pide permiso al usuario la primera vez; si la casilla no estĂĄ marcada, la llamada se rechaza con "Permission is required to access contacts.", y en una app sin ninguno de Contacts, SMS o Call log marcados, el plugin ni siquiera estĂĄ en la app (Capacitor rechaza con "not implemented"). window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
const Contacts = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Contacts;
async function friendsWithPhones() {
if (!Contacts) return [];
const { contacts } = await Contacts.requestPermissions();
if (contacts !== 'granted') return [];
const res = await Contacts.getContacts({ projection: { name: true, phones: true } });
return res.contacts
.filter((c) => c.phones && c.phones.length)
.map((c) => ({ id: c.contactId, name: (c.name && c.name.display) || '', phone: c.phones[0].number }));
}Deja que el usuario elija a una persona en el selector del sistema:
const Contacts = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Contacts;
inviteBtn.onclick = async () => {
if (!Contacts) return;
try {
const { contact } = await Contacts.pickContact({ projection: { name: true, phones: true, emails: true } });
inviteField.value = (contact.emails && contact.emails[0] && contact.emails[0].address) || '';
} catch (e) {
// The user closed the picker, or refused access.
}
};Guarda una tarjeta de visita desde la app en la agenda de contactos:
const Contacts = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Contacts;
async function saveCard(card) {
const perm = await Contacts.requestPermissions();
if (perm.contactsWrite !== 'granted') return null;
const { contactId } = await Contacts.createContact({ contact: {
name: { given: card.first, family: card.last },
organization: { company: card.company, jobTitle: card.title },
phones: [{ type: 'work', label: 'work', number: card.phone }],
emails: [{ type: 'work', label: 'work', address: card.email }],
} });
return contactId;
}Notas: pickContact() se rechaza con el código CANCELLED cuando el usuario sale del selector. Android solo rellena contactId, name, phones, emails, organization, birthday, note, urls, postalAddresses e image cuando la proyección los pide: pide solo lo que muestras. Leer contactos es un permiso sensible en Google Play: describe el motivo en el formulario de seguridad de datos de la ficha. Las apps creadas con IA usan listContacts(), pickContact() y addContact() desde @/lib/appmintNative.
Capacitor.Device Capacitor#
Capacitor.Plugins.Device
Ejemplo
El plugin oficial Capacitor Device, incluido en la app: modelo del telĂŠfono, versiĂłn del sistema, baterĂa, un ID estable y el idioma.
Devuelve: Promises. getInfo() → { model, platform, operatingSystem, osVersion, androidSDKVersion, manufacturer, isVirtual, webViewVersion, … }; getId() → { identifier }; getBatteryInfo() → { batteryLevel (0–1), isCharging }; getLanguageCode() → { value }. Requisitos: no hay que activar nada. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
Muestra el telĂŠfono y la baterĂa.
async function showDevice() {
var cap = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Device;
if (!cap) { document.getElementById('out').textContent = navigator.userAgent; return; }
try {
var info = await cap.getInfo();
var battery = await cap.getBatteryInfo();
document.getElementById('out').textContent =
info.manufacturer + ' ' + info.model + ' - ' + info.operatingSystem + ' ' + info.osVersion +
' - battery ' + Math.round(battery.batteryLevel * 100) + '%' + (battery.isCharging ? ' (charging)' : '');
} catch (err) {
document.getElementById('out').textContent = 'Could not read device info';
}
}Un ID estable y el idioma.
async function helloServer() {
var cap = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Device;
if (!cap) return;
var id = (await cap.getId()).identifier;
var lang = (await cap.getLanguageCode()).value; // e.g. "en"
await fetch('https://api.example.com/hello?lang=' + encodeURIComponent(lang), {
method: 'POST', body: JSON.stringify({ device: id })
});
}En una app creada con IA usa el wrapper, que tambiĂŠn funciona en la web:
import { Device } from '@/lib/appmintNative';
const info = await Device.getInfo();Notas: Para el ID de compilaciĂłn de Android, el parche de seguridad, la pantalla, la memoria y la red, el WebToApk.getDeviceInfo() de la app ofrece mĂĄs detalle. Los ids del plugin no son ids de hardware; pueden cambiar tras un restablecimiento de fĂĄbrica.
Capacitor.Dialog Capacitor#
Capacitor.Plugins.Dialog — alert, confirm, prompt
Ejemplo
Muestra un diĂĄlogo real del sistema Android: un mensaje, una pregunta de sĂ/no o una pregunta de texto de una lĂnea (@capacitor/dialog 8.0.1).
Devuelve: alert({ title?, message, buttonTitle? }) → Promise void. confirm({ title?, message, okButtonTitle?, cancelButtonTitle? }) → { value: boolean }. prompt({ title?, message, okButtonTitle?, cancelButtonTitle?, inputPlaceholder?, inputText? }) → { value: string, cancelled: boolean }. Requisitos: no hay que activar nada: todas las apps incluyen el plugin. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
var Dialog = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Dialog;
async function deleteNote(id) {
if (!Dialog) return;
var r = await Dialog.confirm({
title: 'Delete note?',
message: 'This cannot be undone.',
okButtonTitle: 'Delete',
cancelButtonTitle: 'Keep'
});
if (r.value) removeNote(id);
}Alerta y prompt:
async function renameFlow() {
if (!Dialog) return;
await Dialog.alert({ title: 'Saved', message: 'Your changes are stored.', buttonTitle: 'OK' });
var p = await Dialog.prompt({ title: 'Rename', message: 'New name', inputText: 'Groceries', inputPlaceholder: 'List name' });
if (!p.cancelled && p.value.trim()) renameList(p.value.trim());
}En una app creada con IA el wrapper nunca rechaza: el descarte es { value: false } / { cancelled: true }, y en la web usa los diĂĄlogos propios del navegador:
import { Dialog } from '@/lib/appmintNative';
const { value } = await Dialog.confirm({ title: 'Delete note?', message: 'This cannot be undone.' });
if (value) removeNote(id);Notas: message es obligatorio: sin ĂŠl, el plugin se rechaza con "Please provide a message for the dialog". Los diĂĄlogos son modales; Ăşsalos solo para decisiones que deban bloquear.
Capacitor.Filesystem Capacitor#
Capacitor.Plugins.Filesystem
Ejemplo
El plugin Filesystem estĂĄndar de Capacitor: lee y escribe archivos en el almacenamiento PROPIO de la app (no en una carpeta elegida por el usuario; para eso usa WebToApkFS).
Devuelve: cada mĂŠtodo devuelve una Promise y se rechaza ante un fallo (por ejemplo, al leer un archivo que no existe). readFile → { data }, writeFile → { uri }, readdir → { files: [{ name, type, size, mtime, uri }] }, mkdir / deleteFile → nada. Requisitos: no hay que activar nada; 'DATA' y 'CACHE' no necesitan permiso.
Una pĂĄgina no tiene imports de Directory / Encoding, asĂ que pasa las cadenas simples 'DATA' (archivos privados de la app, conservados hasta desinstalar) o 'CACHE' (el sistema puede borrarlos), y 'utf8' para texto:
async function saveAndReadBack() {
var Fs = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Filesystem;
if (!Fs) { console.log('Filesystem plugin not available (not inside the app)'); return; }
try {
await Fs.mkdir({ path: 'notes', directory: 'DATA', recursive: true });
await Fs.writeFile({ path: 'notes/today.txt', data: 'Hello', directory: 'DATA', encoding: 'utf8', recursive: true });
var r = await Fs.readFile({ path: 'notes/today.txt', directory: 'DATA', encoding: 'utf8' });
console.log('text:', r.data);
var dir = await Fs.readdir({ path: 'notes', directory: 'DATA' });
dir.files.forEach(function (f) { console.log(f.type, f.name, f.size); }); // type: 'file' | 'directory'
await Fs.deleteFile({ path: 'notes/today.txt', directory: 'DATA' });
} catch (e) {
console.log('File error:', e.message); // e.g. the file does not exist
}
}Omite encoding para escribir o leer datos binarios en base64:
var Fs = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Filesystem;
var base64Data = btoa('raw bytes here'); // any base64 string, e.g. from a canvas or FileReader
if (Fs) {
Fs.writeFile({ path: 'blobs/data.bin', data: base64Data, directory: 'CACHE', recursive: true })
.then(function (w) { console.log('written to', w.uri); })
.catch(function (e) { console.log('write failed:', e.message); });
}En las apps creadas con IA, el wrapper @/lib/appmintNative que usa este plugin es fileTransfer (prepara las descargas y subidas en 'CACHE'):
import { fileTransfer } from '@/lib/appmintNative';
const r = await fileTransfer.download('https://example.com/report.pdf', 'report.pdf', {
onProgress: (p) => console.log(Math.round(p.fraction * 100) + '%'),
});
if (r.path) console.log('saved in the app at', r.path); // on the web the browser saves it insteadNotas: window.Capacitor existe solo dentro de la app: detecta siempre la función. Los archivos en 'DATA' son privados de la app y se borran al desinstalar; para poner archivos donde el usuario pueda verlos, usa WebToApkFS (una carpeta que el usuario concede) o una descarga.
Capacitor.FileTransfer Capacitor#
Capacitor.Plugins.FileTransfer
Ejemplo
El plugin oficial Capacitor File Transfer: descarga una URL a un archivo en el telĂŠfono, o sube un archivo del telĂŠfono, de forma nativa y con eventos de progreso.
Devuelve: downloadFile({url, path, headers?, progress?}) → Promise<{path}>; uploadFile({url, path, fileKey?, mimeType?, method?, headers?, progress?}) → Promise<{bytesSent, responseCode, response, headers}>. El progreso llega como eventos del listener 'progress' {type, url, bytes, contentLength, lengthComputable}. Los fallos se rechazan con {message, code}. Requisitos: no hay que activar nada. window.Capacitor existe en las pĂĄginas que la propia app sirve y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios. Detecta siempre la funciĂłn antes de usarla.
Descarga en la cachĂŠ de la app con progreso:
async function download(url, name, onPct) {
const P = window.Capacitor && window.Capacitor.Plugins;
if (!P || !P.FileTransfer || !P.Filesystem) return null; // not in the app
const target = await P.Filesystem.getUri({ path: name, directory: 'CACHE' });
const listener = await P.FileTransfer.addListener('progress', function (p) {
if (p.url === url && p.lengthComputable) onPct(Math.round(p.bytes / p.contentLength * 100));
});
try {
const r = await P.FileTransfer.downloadFile({ url: url, path: target.uri, progress: true });
return r.path;
} catch (e) {
alert('Download failed: ' + e.message);
return null;
} finally {
listener.remove();
}
}Sube un archivo que ya estĂĄ en el telĂŠfono:
const P = window.Capacitor && window.Capacitor.Plugins;
if (P && P.FileTransfer) {
P.FileTransfer.uploadFile({
url: 'https://example.com/api/upload', path: localFileUri,
fileKey: 'file', mimeType: 'image/jpeg', headers: { Authorization: 'Bearer ' + token }
}).then(function (r) { console.log('server said', r.responseCode, r.response); })
.catch(function (e) { alert('Upload failed: ' + e.message); });
}Informa de una transferencia fallida por su cĂłdigo:
async function safeDownload(url, target) {
const P = window.Capacitor && window.Capacitor.Plugins;
if (!P || !P.FileTransfer) { alert('Downloads need the app'); return null; }
try {
const r = await P.FileTransfer.downloadFile({ url: url, path: target });
return r.path;
} catch (e) {
console.log('transfer failed', e.code, e.message);
alert('Could not download the file.');
return null;
}
}Notas: La ruta debe ser una ruta de archivo o un URI file://, no un Blob: escribe antes el Blob en la cachĂŠ con Filesystem.writeFile. En Android 10 y anteriores, una ruta en almacenamiento pĂşblico pide permiso de almacenamiento. En las apps creadas con IA, prefiere fileTransfer de @/lib/appmintNative, que hace todo esto y tambiĂŠn funciona en la web.
Capacitor.FileViewer Capacitor#
Capacitor.Plugins.FileViewer
Ejemplo
El plugin oficial Capacitor File Viewer: abre un documento o archivo multimedia en la app visora del telĂŠfono, desde una direcciĂłn web, una ruta de archivo local o un archivo incluido en la app.
Devuelve: cada mĂŠtodo devuelve una Promise<void> que se rechaza con {message, code} cuando nada puede abrir el archivo. Requisitos: no hay que activar nada. window.Capacitor existe en las pĂĄginas que la propia app sirve y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios. Detecta siempre la funciĂłn antes de usarla.
async function openPdf(url) {
const FV = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.FileViewer;
if (!FV) { window.open(url, '_blank'); return; } // a normal browser: open a tab
try {
await FV.openDocumentFromUrl({ url: url });
} catch (e) {
alert('No app on this phone can open this file.');
}
}Un archivo en el telĂŠfono, por ejemplo uno escrito con Capacitor.Plugins.Filesystem:
async function openSaved(name) {
const P = window.Capacitor && window.Capacitor.Plugins;
if (!P || !P.FileViewer || !P.Filesystem) return;
const f = await P.Filesystem.getUri({ path: name, directory: 'CACHE' });
try {
await P.FileViewer.openDocumentFromLocalPath({ path: f.uri.replace(/^file:\/\//, '') });
} catch (e) {
alert('Cannot open ' + name + ': ' + e.message);
}
}openDocumentFromResources({path}) abre un archivo empaquetado en la carpeta assets del propio APK. Los mismos tres mĂŠtodos existen tambiĂŠn como previewMediaContentFromUrl, previewMediaContentFromLocalPath y previewMediaContentFromResources para vĂdeo y audio.
Descarga un archivo y ĂĄbrelo cuando llegue:
async function downloadAndOpen(url, name) {
const P = window.Capacitor && window.Capacitor.Plugins;
if (!P || !P.FileTransfer || !P.Filesystem || !P.FileViewer) return;
const f = await P.Filesystem.getUri({ path: name, directory: 'CACHE' });
const r = await P.FileTransfer.downloadFile({ url: url, path: f.uri });
await P.FileViewer.openDocumentFromLocalPath({ path: r.path.replace(/^file:\/\//, '') });
}Notas: En las apps creadas con IA, prefiere fileViewer.open(target) de @/lib/appmintNative, que elige el mĂŠtodo adecuado y tambiĂŠn funciona en la web. Una ruta local es una ruta simple (sin file://).
Capacitor.Geolocation Capacitor#
Capacitor.Plugins.Geolocation
Ejemplo
El plugin oficial Capacitor Geolocation, incluido en la app: la posiciĂłn del telĂŠfono una vez, o actualizaciones continuas.
Devuelve: Promises. getCurrentPosition(opts) → { timestamp, coords: { latitude, longitude, accuracy, altitude, speed, heading, … } }; watchPosition(opts, callback) → el id de seguimiento (una cadena); clearWatch({ id }); checkPermissions() / requestPermissions() → { location, coarseLocation } ('granted' | 'denied' | 'prompt' | …). Requisitos: GPS y/o Location en el Paso 4 (Access); en las apps HTML, ZIP y creadas con IA, la compilaciĂłn tambiĂŠn los activa sola cuando tus archivos llaman a getCurrentPosition o watchPosition. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
PosiciĂłn una sola vez, pidiendo permiso antes.
async function whereAmI() {
var geo = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Geolocation;
if (!geo) { showMessage('Open the app to use location.'); return; }
try {
var perm = await geo.checkPermissions();
if (perm.location !== 'granted' && perm.coarseLocation !== 'granted') {
perm = await geo.requestPermissions();
if (perm.location !== 'granted' && perm.coarseLocation !== 'granted') {
showMessage('Location is off for this app.');
return;
}
}
var pos = await geo.getCurrentPosition({ enableHighAccuracy: true, timeout: 15000 });
showMessage(pos.coords.latitude.toFixed(5) + ', ' + pos.coords.longitude.toFixed(5));
} catch (err) {
showMessage('No location: ' + err.message); // location off in settings, timeout, …
}
}Actualizaciones continuas. El callback recibe (position, error).
var watchId = null;
async function startTracking() {
var geo = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Geolocation;
if (!geo) return;
watchId = await geo.watchPosition({ enableHighAccuracy: true }, function (pos, err) {
if (err || !pos) return;
addPointToMap(pos.coords.latitude, pos.coords.longitude);
});
}
async function stopTracking() {
var geo = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Geolocation;
if (geo && watchId) { await geo.clearWatch({ id: watchId }); watchId = null; }
}En una app creada con IA usa el wrapper, que tambiĂŠn funciona en la web:
import { Geolocation } from '@/lib/appmintNative';
const pos = await Geolocation.getCurrentPosition({ enableHighAccuracy: true });Notas: El navigator.geolocation simple tambiĂŠn funciona en la app. Si los interruptores de ubicaciĂłn estaban desactivados al compilar, el permiso se rechaza sin pedirlo. En Android 12+ el usuario puede permitir solo la ubicaciĂłn aproximada (coarseLocation concedido). La ubicaciĂłn es un dato personal: decl\u00e1rala en tu formulario de seguridad de los datos de Play.
Capacitor.Haptics Capacitor#
Capacitor.Plugins.Haptics
Ejemplo
El plugin oficial Capacitor Haptics (@capacitor/haptics), incluido en la app: toques ligeros/medios/fuertes, respuesta de ĂŠxito/advertencia/error, pulsos de selecciĂłn y vibraciĂłn simple.
Devuelve: cada método devuelve una Promesa que se resuelve sin valor. Requiere: nada que activar: todas las apps declaran el permiso de vibración, esté o no marcado Vibrar en el Paso 4 (Acceso). window.Capacitor existe en las páginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app en modo Sitio web, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que abra la app. Detecta la función.
function haptics() {
return window.Capacitor && window.Capacitor.Plugins ? window.Capacitor.Plugins.Haptics : null;
}
async function tap(style) { // 'LIGHT' | 'MEDIUM' | 'HEAVY'
var h = haptics();
if (!h) return;
try { await h.impact({ style: style }); } catch (e) { console.log('haptics failed', e); }
}
async function result(type) { // 'SUCCESS' | 'WARNING' | 'ERROR'
var h = haptics();
if (h) { try { await h.notification({ type: type }); } catch (e) {} }
}
document.getElementById('add').addEventListener('click', function () { tap('LIGHT'); });
document.getElementById('pay').addEventListener('click', function () { result('SUCCESS'); });Pulsos de selecciĂłn para un selector o control deslizante, y una vibraciĂłn simple:
var h = window.Capacitor && window.Capacitor.Plugins ? window.Capacitor.Plugins.Haptics : null;
var wheel = document.getElementById('wheel');
wheel.addEventListener('pointerdown', function () { if (h) h.selectionStart(); });
wheel.addEventListener('change', function () { if (h) h.selectionChanged(); });
wheel.addEventListener('pointerup', function () { if (h) h.selectionEnd(); });
document.getElementById('buzz').addEventListener('click', function () {
if (h) h.vibrate({ duration: 300 }); // milliseconds
});Haz vibrar ante un error y acompåålo de un mensaje visible:
var h = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Haptics;
function rejectInput(field) {
field.classList.add('invalid');
if (h) h.notification({ type: 'ERROR' }).catch(function () {});
}Notas: Las cadenas van en mayĂşsculas ('HEAVY', no 'heavy'). En las apps creadas con IA, import { Haptics } from '@/lib/appmintNative' da los mismos nombres. Para ritmos personalizados con intensidad por pulso, usa Capacitor.Plugins.AppwrightHaptics.
Capacitor.InAppReview Capacitor#
Capacitor.Plugins.InAppReview — requestReview()
Ejemplo
Pide a Google Play que muestre su propia hoja de "valorar esta app" dentro de la app. Incluido @capacitor-community/in-app-review (template/plugins/in-app-review).
Devuelve: Promise void: se resuelve cuando termina el flujo de Play, y Play nunca dice si la hoja se mostrĂł ni quĂŠ hizo el usuario. Se rechaza cuando Play no pudo iniciar el flujo. Requisitos: no hay que activar nada; la app debe estar instalada desde Google Play para que aparezca la hoja. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
var Review = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.InAppReview;
async function afterThirdOrder() {
if (!Review) return;
try {
await Review.requestReview();
} catch (e) {
console.log('review flow not available:', e.message);
}
// continue the app flow either way — you cannot know if the user rated
}En una app creada con IA:
import { requestReview } from '@/lib/appmintNative';
// after a success moment, not on launch
const asked = await requestReview(); // false where nothing could be asked (web)Pide una sola vez, tras un momento de ĂŠxito, y recuerda que ya lo pediste:
var Review = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.InAppReview;
async function maybeAskForReview() {
if (!Review || localStorage.getItem('review_asked')) return;
localStorage.setItem('review_asked', '1');
try { await Review.requestReview(); } catch (e) { console.log('review not shown:', e.message); }
}Notas: Play limita la frecuencia con que aparece la hoja y no la muestra en cada llamada: nunca vincules una recompensa a ella y nunca la pidas desde un botĂłn "ValĂłranos" esperando que se abra (para eso abre la ficha de la tienda). Pide despuĂŠs de un momento de ĂŠxito, no al iniciar. Una instalaciĂłn externa o de depuraciĂłn normalmente no muestra nada.
Capacitor.KeepAwake Capacitor#
Capacitor.Plugins.KeepAwake — keepAwake(), allowSleep(), isKeptAwake(), isSupported()
Ejemplo
Evita que la pantalla se atenĂşe y se bloquee mientras algo debe permanecer visible: una receta, una ruta, un cĂłdigo QR, un temporizador. Incluido @capacitor-community/keep-awake (template/plugins/keep-awake).
Devuelve: keepAwake() / allowSleep() → Promise void. isKeptAwake() → { isKeptAwake: boolean }. isSupported() → { isSupported: true }. Requisitos: nada: todas las apps incluyen el plugin; sin permisos. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
var KA = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.KeepAwake;
async function startCooking() {
if (KA) await KA.keepAwake();
showSteps();
}
async function stopCooking() {
if (KA) await KA.allowSleep(); // always release when the view closes
}
if (KA) KA.isKeptAwake().then(function (r) { console.log('awake?', r.isKeptAwake); });En una app creada con IA (la Screen Wake Lock API en la web):
import { keepAwake } from '@/lib/appmintNative';
useEffect(() => {
void keepAwake(true);
return () => { void keepAwake(false); };
}, []);MantĂŠn la pantalla encendida solo mientras un temporizador estĂĄ en marcha:
var KA = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.KeepAwake;
async function runTimer(seconds) {
if (KA) await KA.keepAwake();
await new Promise(function (done) { setTimeout(done, seconds * 1000); });
if (KA) await KA.allowSleep();
alert('Time is up');
}Notas: El indicador pertenece a la ventana de la app: solo funciona mientras la app estĂĄ en primer plano, y sigue activo hasta allowSleep(); libĂŠralo en cada salida de la pantalla. keepAwake() devuelve false cuando nada pudo mantener la pantalla encendida.
Capacitor.Keyboard Capacitor#
Capacitor.Plugins.Keyboard — show(), hide(), addListener('keyboardDidShow' | ...)
Ejemplo
Abre o cierra el teclado en pantalla e informa a la pĂĄgina cuando aparece y cuĂĄnto mide (@capacitor/keyboard 8.0.5).
Devuelve: show() / hide() → Promise void. addListener(event, fn) → una Promise de un handle con remove(), como en la propia API de Capacitor: usa await o encadena .then(); el valor devuelto tambiĂŠn tiene remove() por sĂ mismo; los eventos show pasan { keyboardHeight } en pĂxeles CSS. Eventos: keyboardWillShow, keyboardDidShow, keyboardWillHide, keyboardDidHide. Requisitos: no hay que activar nada: todas las apps incluyen el plugin. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
var Keyboard = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Keyboard;
if (Keyboard) {
Keyboard.addListener('keyboardDidShow', function (info) {
console.log('keyboard height', info.keyboardHeight);
document.body.classList.add('typing'); // e.g. hide the bottom tab bar
});
Keyboard.addListener('keyboardDidHide', function () {
document.body.classList.remove('typing');
});
}
function onSend() {
if (Keyboard) Keyboard.hide().catch(function () {}); // rejects if no field is focused
}En una app creada con IA usa onKeyboard() para el diseĂąo (informa solo de la parte del teclado que la pĂĄgina redimensionada no libera ya) y hideKeyboard() para cerrarlo:
import { onKeyboard, hideKeyboard, Keyboard } from '@/lib/appmintNative';
const off = onKeyboard((px) => { composer.style.paddingBottom = `${px}px`; }); // call off() on unmount
hideKeyboard();
const h = Keyboard.addListener('keyboardWillShow', ({ keyboardHeight }) => console.log(keyboardHeight));
h.remove();Muestra el teclado para un campo despuĂŠs de tocar un botĂłn:
var Keyboard = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Keyboard;
searchBtn.addEventListener('click', function () {
searchInput.focus();
if (Keyboard) Keyboard.show().catch(function () {});
});Notas: La app ya redimensiona la pĂĄgina para el teclado, asĂ que NO aĂąadas el keyboardHeight completo como relleno: una barra inferior ya queda sobre las teclas. setAccessoryBarVisible, setStyle, setResizeMode y setScroll no estĂĄn implementados en Android: no los llames. hide() se rechaza con "Can't close keyboard, not currently focused" cuando nada tiene el foco.
Capacitor.LocalNotifications Capacitor#
Capacitor.Plugins.LocalNotifications — schedule, cancel, getPending, requestPermissions, events
Ejemplo
Notificaciones que la propia app publica, ahora o a una hora determinada, con la API oficial de @capacitor/local-notifications (com.capacitorjs:local-notifications). El cĂłdigo escrito para el paquete de npm funciona sin cambios.
Devuelve: requestPermissions() / checkPermissions() → { display: 'granted' | 'denied' | 'prompt' }; schedule({ notifications: [{ id, title, body, schedule?: { at | on | every }, extra?, actionTypeId?, channelId? }] }) → { notifications: [{ id }] }; getPending() → { notifications }; cancel({ notifications: [{ id }] }); registerActionTypes({ types }); createChannel / listChannels / deleteChannel; checkExactNotificationSetting() → { exact_alarm }. Eventos: localNotificationReceived, localNotificationActionPerformed (actionId es 'tap' cuando se toca la propia notificaciĂłn). Requisitos: marca Notifications en el Paso 4 (Access); sin ello el plugin no estĂĄ en la app y toda llamada se rechaza con "not implemented". Para notificaciones programadas marca ademĂĄs ⏰ Reminders (hora exacta y que sobrevivan a un reinicio). Las compilaciones HTML, ZIP y AI-Studio marcan ambas solas cuando el cĂłdigo importa @capacitor/local-notifications y llama a LocalNotifications.schedule(. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
const LN = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.LocalNotifications;
async function remindIn(minutes, text) {
if (!LN) return false;
const { display } = await LN.requestPermissions();
if (display !== 'granted') return false;
await LN.schedule({ notifications: [{
id: Date.now() % 2147483647,
title: 'Reminder',
body: text,
schedule: { at: new Date(Date.now() + minutes * 60000), allowWhileIdle: true },
extra: { screen: 'tasks' },
}] });
return true;
}Abre la pantalla correcta cuando el usuario toca una notificaciĂłn, tambiĂŠn cuando el toque iniciĂł la app, ya que el evento espera al listener:
const LN = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.LocalNotifications;
if (LN) {
LN.addListener('localNotificationActionPerformed', ({ actionId, notification }) => {
if (actionId === 'tap' && notification.extra && notification.extra.screen) {
location.hash = '#/' + notification.extra.screen;
}
});
}Un recordatorio diario de un hĂĄbito con botones Hecho / Posponer:
const LN = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.LocalNotifications;
async function dailyWaterReminder() {
await LN.registerActionTypes({ types: [{ id: 'water', actions: [
{ id: 'done', title: 'Done' },
{ id: 'snooze', title: 'In 30 min' },
] }] });
await LN.schedule({ notifications: [{
id: 42, title: 'Drink water', body: 'Time for a glass of water.',
actionTypeId: 'water', schedule: { on: { hour: 10, minute: 0 }, repeats: true },
}] });
LN.addListener('localNotificationActionPerformed', ({ actionId }) => {
if (actionId === 'snooze') {
LN.schedule({ notifications: [{ id: 43, title: 'Drink water', body: 'Snoozed reminder.',
schedule: { at: new Date(Date.now() + 30 * 60000) } }] });
}
});
}Notas: En Android 12+ una notificaciĂłn programada requiere el permiso de alarma exacta: el primer schedule() puede abrir la pĂĄgina del sistema "Alarmas y recordatorios"; si el usuario la deja desactivada, la notificaciĂłn se dispara igualmente, un poco mĂĄs tarde (el resultado incluye un warning). Las notificaciones del plugin usan su propio canal "Default", separado de las demĂĄs notificaciones de la app. Un sound desde los archivos web no es compatible (Android reproduce el sonido predeterminado del canal). Los toques llegan a la pĂĄgina a travĂŠs de la pantalla de desbloqueo cuando la app tiene PIN. Las apps creadas con IA usan notify() / LocalNotifications.schedule de @/lib/appmintNative, que publica mediante la pila de notificaciones de la propia app.
Capacitor.Network Capacitor#
Capacitor.Plugins.Network — getStatus(), addListener('networkStatusChange')
Ejemplo
Informa a la pĂĄgina de si el telĂŠfono estĂĄ conectado y con quĂŠ tipo de conexiĂłn, y cuĂĄndo eso cambia (@capacitor/network 8.0.1).
Devuelve: getStatus() → Promise { connected: boolean, connectionType: 'wifi' | 'cellular' | 'none' | 'unknown' }. El evento networkStatusChange pasa la misma estructura. Requisitos: no hay que activar nada: todas las apps incluyen el plugin. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
var Network = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Network;
function showBanner(s) {
document.getElementById('offline').hidden = s.connected;
}
if (Network) {
Network.getStatus().then(showBanner);
Network.addListener('networkStatusChange', function (s) {
showBanner(s);
if (s.connected) retryQueuedWrites();
if (s.connectionType === 'cellular') console.log('on mobile data');
});
}En una app creada con IA:
import { Network, networkStatus, onNetworkChange } from '@/lib/appmintNative';
const { connected, connectionType } = await Network.getStatus();
const now = networkStatus(); // sync: { connected, type }
const off = onNetworkChange((s) => setOnline(s.connected)); // call off() on unmountPausa una subida grande cuando se usan datos mĂłviles:
var Network = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Network;
async function canUploadVideo() {
if (!Network) return navigator.onLine;
var s = await Network.getStatus();
if (!s.connected) return false;
return s.connectionType === 'wifi' || confirm('Upload over mobile data?');
}Notas: connected significa que el telĂŠfono tiene red, no que tu servidor responda: gestiona igualmente las peticiones fallidas. El Network.getStatus() y el networkStatus() del wrapper leen navigator.onLine / navigator.connection, no el plugin, asĂ que su tipo puede ser 'unknown' o una clase de velocidad como '4g'; onNetworkChange() sĂ usa el evento del plugin en la app.
Capacitor.Preferences Capacitor#
Capacitor.Plugins.Preferences — get / set / remove / keys / clear
Ejemplo
Un pequeĂąo almacĂŠn nativo de clave-valor (Android SharedPreferences) para cadenas de texto (@capacitor/preferences 8.0.1).
Devuelve: set({ key, value }), remove({ key }), clear() → Promise void; get({ key }) → { value } (null cuando falta la clave); keys() → { keys: string[] }. Requisitos: no hay que activar nada: todas las apps incluyen el plugin. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
var Prefs = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Preferences;
async function saveTheme(name) {
if (!Prefs) return false; // not inside the app
await Prefs.set({ key: 'theme', value: name });
return true;
}
async function loadTheme() {
if (!Prefs) return null;
var r = await Prefs.get({ key: 'theme' });
return r.value; // null if never saved
}Los objetos deben convertirse primero en una cadena:
async function saveUser() {
if (!Prefs) return;
await Prefs.set({ key: 'user', value: JSON.stringify({ id: 7, name: 'Asha' }) });
var u = JSON.parse((await Prefs.get({ key: 'user' })).value || 'null');
var all = (await Prefs.keys()).keys;
await Prefs.remove({ key: 'user' });
}Lista y borra las claves guardadas desde una pantalla de ajustes:
async function resetSettings() {
if (!Prefs) return;
var k = (await Prefs.keys()).keys;
console.log('clearing', k.length, 'saved values');
await Prefs.clear();
}Notas: @/lib/appmintNative NO tiene wrapper de Preferences, a propĂłsito: localStorage ya es real y persistente en la app, y un segundo almacĂŠn dividirĂa los datos de una app en dos sitios. Las apps creadas con IA deben seguir usando localStorage (o el runtime de datos). Usa Preferences en una pĂĄgina escrita a mano solo si quieres tener todos tus ajustes ahĂ, y elige un almacĂŠn por valor. configure({ group }) cambia el nombre del almacĂŠn (por defecto CapacitorStorage).
Capacitor.PrivacyScreen Capacitor#
Capacitor.Plugins.PrivacyScreen — enable(), disable(), isEnabled()
Ejemplo
El plugin oficial @capacitor/privacy-screen: bloquea las capturas y grabaciones de pantalla y oculta el contenido de la app en la vista de apps recientes. Incluido para que funcionen los proyectos de Capacitor importados que lo llaman.
Devuelve: enable({android}) → {success}; disable() → {success}; isEnabled() → {enabled}. Requisitos: no hay que activar nada.
const Privacy = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.PrivacyScreen;
async function openVault() {
if (Privacy) await Privacy.enable({ android: { privacyModeOnActivityHidden: 'dim' } });
showVault();
}
async function closeVault() {
if (Privacy) await Privacy.disable();
}Comprueba el estado actual antes de alternarlo:
async function toggleProtection() {
if (!Privacy) return;
var s = await Privacy.isEnabled();
if (s.enabled) await Privacy.disable();
else await Privacy.enable();
}Protege la pantalla solo mientras una vista sensible estĂĄ abierta:
async function showCardNumber() {
if (Privacy) await Privacy.enable({ android: { privacyModeOnActivityHidden: 'splash' } });
cardBox.hidden = false;
}
async function hideCardNumber() {
cardBox.hidden = true;
if (Privacy) await Privacy.disable();
}Notas: privacyModeOnActivityHidden: 'none', 'dim' o 'splash'. El cĂłdigo escrito para la propia app debe usar WebToApk.setSecureScreen(true) / privacyScreen.enable() de @/lib/appmintNative, que sigue a la pĂĄgina (se libera cuando la app la abandona); si mezclas ambos, gana la Ăşltima llamada.
Capacitor.PushNotifications Capacitor#
Capacitor.Plugins.PushNotifications — register, requestPermissions, registration, pushNotificationReceived
Ejemplo
Notificaciones push desde TU PROPIO servidor a travĂŠs de TU proyecto de Firebase, con la API oficial de @capacitor/push-notifications (com.capacitorjs:push-notifications, registrada por el PushNotificationsPlugin.kt de la app). El cĂłdigo escrito para el paquete de npm funciona sin cambios: register(), y luego envĂa al token del evento registration con el Firebase Admin SDK o la API FCM HTTP v1.
Devuelve: requestPermissions() / checkPermissions() → { receive: 'granted' | 'denied' | 'prompt' }; register() / unregister() → void (el token llega como el evento registration { value }, un fallo como registrationError { error }); getDeliveredNotifications() → { notifications }; removeDeliveredNotifications({ notifications }), removeAllDeliveredNotifications(); createChannel({ id, name, importance? }), listChannels(), deleteChannel({ id }). Eventos: pushNotificationReceived (un mensaje mientras la app estĂĄ abierta: { id, title?, body?, data }) y pushNotificationActionPerformed ({ actionId: 'tap', notification: { id, data } }). Requisitos: compila con AppMint Push activado y tu google-services.json subido (paso Notifications): ese es el proyecto de Firebase al que pertenece el token. Sin ĂŠl, register() se rechaza con el cĂłdigo PUSH_NOT_CONFIGURED ("Push is not set up in this app"). Las compilaciones HTML, ZIP y AI-Studio marcan Notifications solas cuando el cĂłdigo llama a PushNotifications.register( / requestPermissions( / addListener(. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
const Push = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.PushNotifications;
async function enablePush(userId) {
if (!Push) return;
await Push.addListener('registration', ({ value }) => {
// Your server stores the token and sends to it later.
fetch('https://api.example.com/push-tokens', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ userId, token: value, platform: 'android' }),
});
});
await Push.addListener('registrationError', ({ error }) => console.warn('push:', error));
const { receive } = await Push.requestPermissions();
if (receive !== 'granted') return;
try { await Push.register(); }
catch (e) { if (e.code === 'PUSH_NOT_CONFIGURED') alert('Push is not set up in this build.'); }
}Reacciona a un mensaje mientras la app estĂĄ abierta, y al toque en uno que llegĂł con la app cerrada (el evento de toque espera a tu listener, asĂ que un arranque en frĂo no se pierde):
const Push = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.PushNotifications;
if (Push) {
Push.addListener('pushNotificationReceived', (msg) => {
alert((msg.title || 'New message') + (msg.body ? ': ' + msg.body : ''));
});
Push.addListener('pushNotificationActionPerformed', ({ notification }) => {
const orderId = notification.data && notification.data.orderId;
if (orderId) location.hash = '#/orders/' + orderId;
});
}Un canal para alertas importantes (Android 8+), usado por los mensajes que lo nombran en android.notification.channel_id:
const Push = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.PushNotifications;
async function setupChannels() {
if (!Push) return;
await Push.createChannel({ id: 'orders', name: 'Order updates', description: 'Your order status', importance: 4, vibration: true });
}Notas: Un mensaje enviado con un bloque notification lo muestra el propio Android mientras la app está en segundo plano; su toque abre la app (a través de la pantalla de desbloqueo cuando la app tiene PIN) y dispara pushNotificationActionPerformed. Mientras la app está abierta, los mensajes llegan como pushNotificationReceived y no se dibujan en la bandeja. Los mensajes solo de datos llegan a la página únicamente mientras está abierta. Los mensajes de AppMint Push siguen funcionando en paralelo: nunca llegan a este plugin. En una app compilada con OneSignal en lugar de AppMint Push, los mensajes los entrega OneSignal y nunca llegan a este plugin. Las apps creadas con IA reciben los push del creador mediante pushInbox() desde @/lib/appmintNative.
Capacitor.ScreenBrightness Capacitor#
Capacitor.Plugins.ScreenBrightness — getBrightness(), setBrightness({ brightness })
Ejemplo
Ajusta el brillo de pantalla de la ventana de la app: brillo completo para una tarjeta de embarque o un cĂłdigo QR, y luego de vuelta al valor anterior. Incluido @capacitor-community/screen-brightness (template/plugins/screen-brightness).
Devuelve: getBrightness() → Promise { brightness } (0-1, o -1 cuando la app no lo ha sobrescrito y la pantalla sigue al sistema). setBrightness({ brightness }) → Promise void. Requisitos: nada: todas las apps incluyen el plugin; sin permisos (solo cambia la ventana de esta app, no el ajuste del sistema). window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
var SB = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ScreenBrightness;
async function showTicket() {
if (SB) await SB.setBrightness({ brightness: 1 }); // full brightness
document.getElementById('qr').hidden = false;
}
async function hideTicket() {
if (SB) await SB.setBrightness({ brightness: -1 }); // -1 = follow the system again
document.getElementById('qr').hidden = true;
}En una app creada con IA:
import { brightness } from '@/lib/appmintNative';
await brightness.set(1); // clamped to 0–1; false where not available (web)
// ... on leaving the screen
await brightness.restore();
const level = await brightness.get(); // -1 = following the system / not availableLee primero el nivel actual y restaura exactamente ese:
var SB = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ScreenBrightness;
var before = -1;
async function boost() {
if (!SB) return;
before = (await SB.getBrightness()).brightness;
await SB.setBrightness({ brightness: 1 });
}
async function undo() {
if (SB) await SB.setBrightness({ brightness: before });
}Notas: Pasa siempre un nĂşmero: setBrightness({}) no tiene ningĂşn valor que aplicar. Restaura con -1 cuando se cierre la vista; el ajuste tambiĂŠn termina cuando se cierra la app. Una pĂĄgina web no puede controlar la retroiluminaciĂłn, asĂ que can('brightness') es 'none' en un navegador.
Capacitor.ScreenOrientation Capacitor#
Capacitor.Plugins.ScreenOrientation — orientation(), lock({ orientation }), unlock()
Ejemplo
Lee la orientaciĂłn de la pantalla, la fija para una vista (un juego, un grĂĄfico, un panel de firma) y la libera (@capacitor/screen-orientation 8.0.1).
Devuelve: orientation() → Promise { type } (p. ej. 'portrait-primary'). lock() / unlock() → Promise void. El evento screenOrientationChange pasa { type }. Requisitos: no hay que activar nada: todas las apps incluyen el plugin. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
orientation valores: 'portrait', 'landscape', 'portrait-primary', 'portrait-secondary', 'landscape-primary', 'landscape-secondary', 'natural', 'any'.
var SO = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ScreenOrientation;
async function openChart() {
if (SO) await SO.lock({ orientation: 'landscape' });
showChart();
}
async function closeChart() {
if (SO) await SO.unlock(); // always release when leaving the view
hideChart();
}
if (SO) {
SO.orientation().then(function (o) { console.log('now', o.type); });
SO.addListener('screenOrientationChange', function (o) { console.log('rotated to', o.type); });
}En una app creada con IA:
import { lockOrientation, ScreenOrientation } from '@/lib/appmintNative';
const ok = await lockOrientation('landscape'); // false when refused (always on desktop)
await lockOrientation('any'); // release
await ScreenOrientation.lock({ orientation: 'portrait' });
await ScreenOrientation.unlock();Gestiona un bloqueo rechazado e informa al usuario:
var SO = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ScreenOrientation;
var Toast = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Toast;
async function tryLandscape() {
if (!SO) { document.getElementById('rotate-hint').hidden = false; return; } // ask the user to rotate by hand
try {
await SO.lock({ orientation: 'landscape' });
} catch (e) {
if (Toast) Toast.show({ text: 'Could not rotate the screen', duration: 'short' });
}
}Notas: Los wrappers solo conocen portrait / landscape / any: ScreenOrientation.lock({ orientation: 'landscape-secondary' }) bloquea en un simple landscape. Da al usuario una forma de salir de una vista bloqueada.
Capacitor.ScreenReader Capacitor#
Capacitor.Plugins.ScreenReader — isEnabled(), speak({ value, language }), addListener('stateChange')
Ejemplo
Informa a la pĂĄgina de si TalkBack estĂĄ activado y dice un anuncio en voz alta (@capacitor/screen-reader 8.0.1).
Devuelve: isEnabled() → Promise { value: boolean }. speak() → Promise void. El evento stateChange pasa { value: boolean } cuando TalkBack se activa o desactiva. Requisitos: no hay que activar nada: todas las apps incluyen el plugin. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
var SR = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ScreenReader;
function setCalmMode(on) {
document.documentElement.classList.toggle('no-motion', on); // shorten animations
}
if (SR) {
SR.isEnabled().then(function (r) { setCalmMode(r.value); });
SR.addListener('stateChange', function (s) { setCalmMode(s.value); });
}
async function announceSaved() {
if (SR) await SR.speak({ value: 'Order placed', language: 'en' });
}En una app creada con IA (speak usa sĂntesis de voz en la web; isEnabled() es false allĂ):
import { screenReader } from '@/lib/appmintNative';
const on = await screenReader.isEnabled();
const off = screenReader.onChange((enabled) => setCalmMode(enabled));
await screenReader.speak('Order placed', 'en');Detecta la funciĂłn y mantĂŠn la pĂĄgina utilizable sin el plugin:
var SR = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.ScreenReader;
async function say(message) {
if (SR) { await SR.speak({ value: message }); return; }
document.getElementById('live-region').textContent = message; // an aria-live="polite" element
}Notas: language es 'en' por defecto. Prefiere el marcado accesible normal (etiquetas, regiones aria-live) para la mayorĂa de los anuncios; usa speak para cambios de estado breves e importantes. No existe ninguna API web para detectar un lector de pantalla, asĂ que can('screenReader') es 'none' en un navegador.
Capacitor.SpeechRecognition Capacitor#
Capacitor.Plugins.SpeechRecognition
Ejemplo
Convierte la voz del usuario en texto con el reconocedor de voz de Android (el plugin de la comunidad @capacitor-community/speech-recognition, incluido en la app). El WebView de Android no tiene reconocimiento Web Speech propio, asĂ que esta es la forma de hacer dictado.
Devuelve: Promises. available() → { available }. checkPermissions() / requestPermissions() → { speechRecognition: 'granted' | 'denied' | 'prompt' }. start({ partialResults: false }) → { status: 'success', matches: [...] } despuĂŠs de que el usuario deja de hablar; se rechaza ante errores como falta de voz o ausencia de coincidencia. Requisitos: marca Mic en el Paso 4 (Access) al compilar (en las apps HTML, ZIP y creadas con IA la compilaciĂłn tambiĂŠn aĂąade sola el permiso de micrĂłfono cuando tus archivos mencionan SpeechRecognition), y el usuario debe permitir el micrĂłfono. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
Dictado de una sola vez (de la misma forma que lo usa @/lib/appmintNative speech):
var SR = window.Capacitor && window.Capacitor.Plugins ? window.Capacitor.Plugins.SpeechRecognition : null;
async function dictate() {
var out = document.getElementById('text');
if (!SR || !(await SR.available()).available) { out.textContent = 'Voice input is not available on this phone.'; return; }
var p = (await SR.checkPermissions()).speechRecognition;
if (p !== 'granted') p = (await SR.requestPermissions()).speechRecognition;
if (p !== 'granted') { out.textContent = 'Microphone permission was not given.'; return; }
try {
var r = await SR.start({ language: 'en-US', maxResults: 3, partialResults: false, popup: false });
out.textContent = r.matches && r.matches.length ? r.matches[0] : '';
} catch (e) {
out.textContent = 'Did not catch that. Try again.';
}
}
document.getElementById('mic').addEventListener('click', dictate);Texto en vivo mientras el usuario habla (partialResults: true), y el estado de escucha:
// Add the listeners ONCE, when the page starts.
if (SR) {
SR.addListener('partialResults', function (d) {
// Words as they come, and then the final text, all arrive here.
if (d.matches && d.matches.length) document.getElementById('text').textContent = d.matches[0];
});
SR.addListener('listeningState', function (d) {
// 'started' = the user began speaking, 'stopped' = the user stopped speaking
document.body.classList.toggle('listening', d.status === 'started');
});
}
document.getElementById('mic-live').addEventListener('click', async function () {
if (!SR) return;
try {
await SR.start({ language: 'en-US', partialResults: true, popup: false }); // resolves at once, no matches
} catch (e) {
document.getElementById('text').textContent = 'Could not start: ' + e.message;
}
});
document.getElementById('stop').addEventListener('click', function () { if (SR) SR.stop(); });Muestra el botón del micrófono solo cuando el dictado pueda funcionar, y deja de escuchar cuando la página se oculte:
var SR = window.Capacitor && window.Capacitor.Plugins ? window.Capacitor.Plugins.SpeechRecognition : null;
var mic = document.getElementById('mic');
mic.hidden = true;
if (SR) {
SR.available().then(function (r) { mic.hidden = !r.available; });
}
document.addEventListener('visibilitychange', function () {
if (document.hidden && SR) SR.stop();
});Notas:
- En modo en vivo (
partialResults: true), el texto final llega despuĂŠs del estado'stopped', asĂ que no elimines el listener departialResultsen'stopped'. Un error posterior al inicio (sin voz, sin coincidencia) no se informa en este modo. languagees una etiqueta como'en-US'o'ta-IN'(por defecto: el idioma del telĂ©fono).popup: truemuestra el propio cuadro de escucha de Google. TambiĂ©n existengetSupportedLanguages()→{ languages }yisListening()→{ listening }.start()se rechaza con'Missing permission'si no pediste permiso antes. La escucha se detiene sola tras una pausa en la voz.
Capacitor.SplashScreen Capacitor#
Capacitor.Plugins.SplashScreen — show(), hide()
Ejemplo
La API de @capacitor/splash-screen sobre la pantalla de inicio de marca de la propia app, para que los proyectos de Capacitor / AI Studio importados que llaman a SplashScreen.hide() cuando su primera pantalla estĂĄ lista funcionen en la app de Android.
Devuelve: hide() → Promise (la pantalla de inicio desaparece una vez pasado el tiempo mĂnimo de pantalla de inicio del creador); show({showDuration, autoHide}) → Promise (la pantalla de inicio vuelve sobre la pĂĄgina y, con autoHide —el valor por defecto—, desaparece tras showDuration ms, por defecto 3000). Requisitos: no hay que activar nada.
const Splash = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.SplashScreen;
async function boot() {
await loadFirstScreen();
if (Splash) await Splash.hide(); // otherwise the shell hides it at first paint
}
boot();Cubre un cambio lento de cuenta con la pantalla de inicio, mantenida hasta que los datos nuevos estĂŠn en pantalla:
const Splash = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.SplashScreen;
async function switchAccount(accountId) {
if (Splash) await Splash.show({ autoHide: false }); // stays until hide()
try {
await loadAccount(accountId);
renderHome();
} finally {
if (Splash) await Splash.hide();
}
}Muestra la pantalla de inicio de marca un momento tras cerrar sesiĂłn; desaparece sola despuĂŠs de showDuration:
const Splash = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.SplashScreen;
async function signOut() {
await clearSession();
showSignInScreen();
if (Splash) {
try {
await Splash.show({ showDuration: 1200 });
} catch (e) {
console.warn('splash not shown:', e.code);
}
}
}Notas: sin una llamada a hide(), la pantalla de inicio sigue desapareciendo en el primer renderizado, como en cualquier app. Las apps creadas con IA usan splash.hold() / splash.ready() de @/lib/appmintNative.
Capacitor.StatusBar Capacitor#
Capacitor.Plugins.StatusBar — setStyle, setBackgroundColor, show, hide, getInfo
Ejemplo
Cambia el estilo de iconos, el color y la visibilidad de la barra de estado (@capacitor/status-bar 8.0.2).
Devuelve: cada mĂŠtodo → Promise void, salvo getInfo() → { visible, style, color, overlays, height }. Requisitos: no hay que activar nada: todas las apps incluyen el plugin. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
style nombra el FONDO al que se adapta: 'DARK' = iconos claros (para una barra oscura), 'LIGHT' = iconos oscuros, 'DEFAULT' = seguir al sistema.
var StatusBar = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.StatusBar;
if (StatusBar) {
StatusBar.setStyle({ style: 'DARK' }); // light icons
StatusBar.hide(); // e.g. while a video plays
// later
StatusBar.show();
}Colorea la barra con el puente de la app, no con el plugin. En Android 15+ el setBackgroundColor del plugin no hace nada (el modo de borde a borde lo ignora). La app pinta la franja ella misma y toma el estilo de los iconos en la misma llamada:
if (window.WebToApk && window.WebToApk.setStatusBarColor) {
window.WebToApk.setStatusBarColor('#0B0F1A', 'light'); // dark bar, light icons
} else if (StatusBar) {
StatusBar.setBackgroundColor({ color: '#0B0F1A' }); // hex only, e.g. #RRGGBB
}En una app creada con IA usa setStatusBar(color, contentStyle); prefiere el puente de la app y define color e iconos en una sola llamada:
import { setStatusBar, StatusBar } from '@/lib/appmintNative';
setStatusBar('#0B0F1A', 'light'); // dark bar, light icons
await StatusBar.setBackgroundColor({ color: '#FFFFFF' }); // colour only; icons picked from luminanceNotas: setBackgroundColor rechaza un color que no sea una cadena hexadecimal. En compilaciones de pantalla completa / quiosco, las barras las oculta la app. En la app de Android, el StatusBar.setStyle() del wrapper por sĂ solo no cambia nada (el puente necesita un color para pintar): pasa el estilo a setStatusBar() junto con un color.
Capacitor.TextToSpeech Capacitor#
Capacitor.Plugins.TextToSpeech — speak(), stop(), getSupportedLanguages(), getSupportedVoices()
Ejemplo
El plugin de la comunidad @capacitor-community/text-to-speech sobre el motor de texto a voz del teléfono. Incluido para que funcionen los proyectos Capacitor importados que lo llaman.
Devuelve: speak({text, lang, rate, pitch, volume, voice}) → Promise que se resuelve cuando se ha dicho la frase; stop(); getSupportedLanguages() → {languages}; getSupportedVoices() → {voices}; isLanguageSupported({lang}) → {supported}. Requisitos: no hay que activar nada.
const Tts = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.TextToSpeech;
async function readAloud(text) {
if (!Tts) { speechSynthesis.speak(new SpeechSynthesisUtterance(text)); return; }
await Tts.speak({ text: text, lang: 'en-US', rate: 1.0, pitch: 1.0, volume: 1.0 });
}
document.getElementById('stop').onclick = () => Tts && Tts.stop();Comprueba el idioma antes de hablar y muestra un mensaje cuando no estĂŠ instalado:
const Tts = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.TextToSpeech;
async function speakIn(lang, text) {
if (!Tts) return false;
const { supported } = await Tts.isLanguageSupported({ lang: lang });
if (!supported) { showMessage('This phone has no ' + lang + ' voice installed.'); return false; }
await Tts.speak({ text: text, lang: lang });
return true;
}Lee un pĂĄrrafo en voz alta con un botĂłn de parar, y gestiona un error al hablar:
const Tts = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.TextToSpeech;
async function readParagraph(el, btn) {
if (!Tts) return;
btn.textContent = 'Stop';
btn.onclick = () => Tts.stop();
try {
await Tts.speak({ text: el.textContent, lang: 'en-US', rate: 0.9 }); // resolves when finished
} catch (e) {
console.warn('could not speak:', e.message);
} finally {
btn.textContent = 'Listen';
btn.onclick = () => readParagraph(el, btn);
}
}Notas: window.speechSynthesis tambiĂŠn funciona en la app (el motor propio de la app) y es lo que usan las apps creadas con IA a travĂŠs de speak(); este plugin es la vĂa con forma Capacitor.
Capacitor.TextZoom Capacitor#
Capacitor.Plugins.TextZoom — get(), getPreferred(), set({ value })
Ejemplo
Lee y cambia el tamaĂąo de texto de la pĂĄgina de la app, para un control de "tamaĂąo de texto" dentro de la app (@capacitor/text-zoom 8.0.1).
Devuelve: get() → Promise { value } (zoom actual, 1 = 100%). getPreferred() → { value } (el tamaĂąo que el usuario eligiĂł en los ajustes de Android). set({ value }) → Promise void. Requisitos: no hay que activar nada: todas las apps incluyen el plugin. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
var TZ = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.TextZoom;
async function biggerText() {
if (!TZ) return;
var now = (await TZ.get()).value;
await TZ.set({ value: Math.min(2, now + 0.1) });
}
async function resetText() {
if (!TZ) return;
var pref = (await TZ.getPreferred()).value; // e.g. 1.15 when the phone uses large text
await TZ.set({ value: pref });
}En una app creada con IA (en la web escala el tamaĂąo de fuente raĂz):
import { textZoom } from '@/lib/appmintNative';
const size = await textZoom.get();
await textZoom.set(size + 0.1); // clamped to 0.5–3
await textZoom.set(await textZoom.getPreferred()); // back to the system sizeUn control deslizante de tamaĂąo de texto que recuerda la elecciĂłn:
var TZ = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.TextZoom;
var slider = document.getElementById('text-size'); // <input type="range" min="0.8" max="1.6" step="0.1">
if (TZ) {
var saved = parseFloat(localStorage.getItem('textZoom'));
if (saved) TZ.set({ value: saved });
slider.addEventListener('change', function () {
TZ.set({ value: parseFloat(slider.value) });
localStorage.setItem('textZoom', slider.value);
});
} else {
slider.hidden = true;
}Notas: La app ya sigue el tamaĂąo de texto del sistema; esto es para un control extra dentro de la app. Prueba tu diseĂąo con tamaĂąos grandes: las alturas fijas en controles de texto recortarĂĄn el contenido.
Capacitor.Toast Capacitor#
Capacitor.Plugins.Toast — show({ text, duration, position })
Ejemplo
Muestra un toast breve del sistema Android como "Guardado" o "Copiado" (@capacitor/toast 8.0.1).
Devuelve: Promise void. Requisitos: no hay que activar nada: todas las apps incluyen el plugin. window.Capacitor existe en las pĂĄginas que la propia app sirve (apps HTML, ZIP y creadas con IA) y, en una app de modo Website, en tu propio sitio (su dominio y subdominios), nunca en otros sitios que la app abra. Detecta la funciĂłn antes de usarla.
var Toast = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Toast;
function saved() {
if (Toast) Toast.show({ text: 'Saved', duration: 'short', position: 'bottom' });
}duration es 'short' (unos 2 s) o 'long' (unos 3,5 s). position es 'top', 'center' o 'bottom'.
En una app creada con IA usa toast() o el Toast con forma Capacitor; en la web dibujan un snackbar con los colores de la app:
import { Toast, toast } from '@/lib/appmintNative';
await Toast.show({ text: 'Added to list', duration: 'long' });
toast('Copied'); // short form, same resultDetecta la funciĂłn y muestra un mensaje en la pĂĄgina cuando falte el plugin:
function notify(message) {
var Toast = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Toast;
if (Toast) { Toast.show({ text: message, duration: 'short' }); return; }
var el = document.getElementById('snackbar'); // a plain in-page message
el.textContent = message;
el.hidden = false;
setTimeout(function () { el.hidden = true; }, 2000);
}Notas: text es obligatorio («Must provide text»). El sistema dibuja el toast al estilo del fabricante del teléfono, y las versiones más nuevas de Android ignoran position en los toasts de texto. Un toast es fácil de pasar por alto: nunca lo uses para un error que el usuario deba atender; usa Dialog.alert para eso.
Capacitor.Torch Capacitor#
Capacitor.Plugins.Torch — enable(), disable(), toggle(), isEnabled(), isAvailable()
Ejemplo
La linterna del telĂŠfono, con la API de @capawesome/capacitor-torch. Plugin propio de la app (TorchPlugin.kt).
Devuelve: enable() / disable() / toggle() → Promise (se rechaza con CAMERA_IN_USE mientras estĂĄ abierto el flujo de la cĂĄmara de la propia app, y con UNAVAILABLE si no hay flash); isEnabled() → {enabled}; isAvailable() → {available}. Requisitos: no hay que activar nada ni se necesita permiso.
const Torch = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Torch;
async function setupLightButton() {
if (!Torch || !(await Torch.isAvailable()).available) { lightBtn.hidden = true; return; }
lightBtn.onclick = async () => {
try {
await Torch.toggle();
lightBtn.classList.toggle('on', (await Torch.isEnabled()).enabled);
} catch (e) {
alert(e.message);
}
};
}Haz parpadear una señal SOS desde un botón, y apaga la luz si la cámara toma el flash a mitad:
const Torch = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Torch;
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
sosBtn.onclick = async () => {
if (!Torch || !(await Torch.isAvailable()).available) return;
const flashes = [200, 200, 200, 600, 600, 600, 200, 200, 200]; // S O S, in ms
try {
for (const ms of flashes) {
await Torch.enable(); await wait(ms);
await Torch.disable(); await wait(200);
}
} catch (e) {
await Torch.disable().catch(() => {});
alert(e.code === 'CAMERA_IN_USE' ? 'Close the camera first.' : e.message);
}
};MantĂŠn un botĂłn de luz sincronizado con el sistema, ya que el usuario puede encender la linterna desde el mosaico de ajustes rĂĄpidos mientras la app estĂĄ en segundo plano:
const Torch = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Torch;
async function syncLightButton() {
if (!Torch) return;
const { enabled } = await Torch.isEnabled();
lightBtn.classList.toggle('on', enabled);
lightBtn.setAttribute('aria-pressed', String(enabled));
}
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') syncLightButton();
});
syncLightButton();Notas: la luz sigue el estado del sistema (apagarla desde el mosaico de ajustes rĂĄpidos se lee como apagada) y se apaga cuando se cierra la app. Mientras hay un flujo de getUserMedia abierto, enciende la luz a travĂŠs de la pista: track.applyConstraints({ advanced: [{ torch: true }] }). Las apps creadas con IA usan torch de @/lib/appmintNative.