API da ponte JavaScript
Plugins do Capacitor
Os plugins do Capacitor que o app hospeda. Uma pĂĄgina escrita Ă mĂŁo os acessa como window.Capacitor.Plugins.<Name>; um app criado com IA usa o wrapper @/lib/appmintNative citado em cada exemplo.
Capacitor.ActionSheet Capacitor#
Capacitor.Plugins.ActionSheet — showActions({ title, message, options })
Exemplo
Mostra uma folha inferior nativa com uma lista de opçÔes e informa qual foi tocada (@capacitor/action-sheet 8.1.1).
Retorna: Promise { index, canceled } - index Ă© a opção tocada; quando a folha Ă© dispensada canceled Ă© true e index fica fora da lista (-1). Requer: nada para ativar - todo app hospeda o plugin. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
Cada opção Ă© { title, style? } com style 'DEFAULT', 'DESTRUCTIVE' ou '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();
}Em um app criado com IA o wrapper no formato Capacitor retorna { index: -1 } ao dispensar; a forma curta actionSheet() retorna 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 | nullConfirmaçÔes de exclusĂŁo que tambĂ©m funcionam em um navegador comum:
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;
}Observaçþes: Sempre verifique o limite do Ăndice - nunca trate qualquer Ăndice como uma escolha real. O formato de opção do wrapper Ă© { title, destructive? }; ele mapeia destructive para o estilo 'DESTRUCTIVE' do plugin.
Capacitor.App Capacitor#
Capacitor.Plugins.App — getInfo(), getState(), exitApp(), minimizeApp(), addListener(...)
Exemplo
Identidade e ciclo de vida do app: nome, id do pacote, versĂŁo, se o app estĂĄ em primeiro plano e eventos de pausa/retomada (@capacitor/app 8.1.0).
Retorna: getInfo() → { name, id, build, version }; getState() → { isActive }; getLaunchUrl() → { url } ou nada; getAppLanguage() → { value }; exitApp() / minimizeApp() → void. addListener() → uma Promise de um handle com remove(), como na própria API do Capacitor - use await nele ou encadeie .then(); o valor retornado também tem remove(). Requer: nada para ativar - todo app hospeda o plugin. window.Capacitor existe em páginas que o próprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Site, no seu próprio site (seu domínio e subdomínios) - nunca em outros sites que o app abre. Detecte o recurso.
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 e retomar - salve um rascunho quando o usuĂĄrio sair e atualize quando ele voltar:
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'); });
}Em um app criado com IA:
import { App } from '@/lib/appmintNative';
const info = await App.getInfo(); // { name, id, build, version }
App.exitApp(); // closes the app on AndroidObservaçþes: O evento backButton nunca dispara: o shell mantĂ©m o botĂŁo voltar (o plugin roda com disableBackButtonHandler). Trate o voltar com AppMint.setBackHandler(fn) ou o wrapper onBackGesture. Para links diretos (deep links) use WebToApk.getLaunchUrl() / o evento appmint:deep-link (ou launchUrl() / onDeepLink() em apps criados com IA). minimizeApp() Ă© sĂł para Android. Nunca faça de um botĂŁo Sair o Ășnico caminho adiante.
Capacitor.AppLauncher Capacitor#
Capacitor.Plugins.AppLauncher — canOpenUrl({ url }), openUrl({ url })
Exemplo
Abre outro app por link (whatsapp://send?text=…, tel:, geo:, um link https) e pergunta se algum app consegue tratĂĄ-lo (@capacitor/app-launcher 8.0.1).
Retorna: canOpenUrl() → Promise { value: boolean }. openUrl() → Promise { completed: boolean } (false quando nenhum app aceitou o link). Requer: nada para ativar - todo app hospeda o plugin. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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');
}Em um app criado com IA:
import { appLauncher } from '@/lib/appmintNative';
if (await appLauncher.canOpen('tel:+15551234567')) await appLauncher.open('tel:+15551234567');Abra um link de mapa sem perguntar 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');
}Observaçþes: No Android 11+ um app sĂł consegue "ver" outros apps que ele declara. Os apps gerados declaram links https, geo, google.navigation, tel, mailto, sms, whatsapp, intent e upi, entĂŁo canOpenUrl responde false para outros esquemas (por exemplo spotify:) mesmo com o app instalado. openUrl ainda funciona para eles - chame-o e verifique completed. No Android canOpenUrl tambĂ©m aceita um nome de pacote ('com.whatsapp'), com o mesmo limite de visibilidade.
Capacitor.AppUpdate Capacitor#
Capacitor.Plugins.AppUpdate — getAppUpdateInfo(), performImmediateUpdate(), startFlexibleUpdate(), completeFlexibleUpdate(), openAppStore()
Exemplo
Verifica no Google Play se hĂĄ uma versĂŁo mais nova do app e inicia a atualização no app do Play. Incluso @capawesome/capacitor-app-update (template/plugins/app-update).
Retorna: getAppUpdateInfo() → { currentVersionName, currentVersionCode, availableVersionCode, updateAvailability, updatePriority, immediateUpdateAllowed, flexibleUpdateAllowed, clientVersionStalenessDays?, installStatus } (cĂłdigos de versĂŁo sĂŁo strings; updateAvailability 2 = hĂĄ uma atualização disponĂvel). performImmediateUpdate() / startFlexibleUpdate() → { code }: 0 OK, 1 cancelado, 2 falhou, 3 indisponĂvel, 4 nĂŁo permitido, 5 chame getAppUpdateInfo() primeiro. openAppStore() → void. Requer: nada para ativar; o app precisa estar instalado pelo Google Play. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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
}
}Atualização flexĂvel - baixe em segundo plano e reinicie quando o usuĂĄrio concordar:
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(); }Em um app criado com 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 updateObservaçþes: Use updateAvailability === 2 como Ășnico teste de "atualização disponĂvel". O check() do wrapper compara currentVersionName com availableVersionCode, que nunca sĂŁo iguais no Android, entĂŁo seu updateAvailable nĂŁo Ă© confiĂĄvel ali - teste inPlace em vez disso. start() resolve true mesmo quando o usuĂĄrio cancela.
Capacitor.AppwrightDocScanner Capacitor#
Capacitor.Plugins.AppwrightDocScanner — scan({ pageLimit, pdf, quality }), isSupported()
Exemplo
Abre o scanner de documentos do Google ML Kit: o usuĂĄrio fotografa uma ou mais pĂĄginas (ou as importa), as bordas sĂŁo encontradas e endireitadas, e as pĂĄginas voltam como imagens JPEG. Plugin prĂłprio do Appwright (AppwrightDocScannerPlugin.kt).
Retorna: scan() → Promise que sempre Ă© RESOLVIDA: { ok: true, pages: string[] (JPEG data URLs), pdfDataUrl?, pdfPath?, pdfError? } em caso de sucesso, { ok: false, cancelled: true } quando o usuĂĄrio desiste, { ok: false, error } quando o scanner nĂŁo consegue iniciar. isSupported() → { value: boolean } (Google Play services presente). Requer: nada para ativar e nenhuma permissĂŁo de cĂąmera (o scanner roda dentro do Play services, que baixa o modelo no primeiro uso).
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 = sem limite. quality Ă© de 0,1 a 1 para o JPEG. Com pdf: true o scanner tambĂ©m grava um PDF: pdfDataUrl Ă© ele como uma URL data:application/pdf;base64,… que a pĂĄgina pode baixar, enviar ou exibir, e pdfPath Ă© a cĂłpia dele na pasta de cache do app. Se o PDF nĂŁo pĂŽde ser lido, as pĂĄginas ainda voltam e pdfError diz o motivo.
Em um app criado com IA (null ao cancelar, em erro ou na 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
}Escaneie vĂĄrias pĂĄginas e ofereça o 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');
}Observaçþes: As pĂĄginas sĂŁo data URLs completos e podem ser grandes - reduza-as antes de salvar muitas em localStorage. Use pdfDataUrl, nĂŁo pdfPath - o caminho de um arquivo do dispositivo nĂŁo Ă© uma URL que a pĂĄgina consiga carregar. Uma pĂĄgina que nĂŁo puder ser lida Ă© ignorada; as demais ainda voltam.
Capacitor.AppwrightGallery Capacitor#
Capacitor.Plugins.AppwrightGallery — save({ source, fileName, album, kind })
Exemplo
Salva uma foto ou um vĂdeo na galeria do celular (Pictures/<album> ou Movies/<album>). Plugin prĂłprio do shell do app (AppwrightGalleryPlugin.kt).
Retorna: Promise de { uri } do item salvo. Ă rejeitada com um code: bad-source, download-failed, permission-denied (Android 7-9, armazenamento recusado) ou failed. Requer: nada para ativar; nenhuma permissĂŁo no Android 10+ (o Android 7-9 pede armazenamento na primeira 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);
}
}Salve um vĂdeo do seu servidor em um ĂĄlbum prĂłprio, com uma mensagem para cada cĂłdigo de falha:
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);
}
}Salve uma foto que o usuĂĄrio editou como Blob (por exemplo de canvas.toBlob) convertendo-a antes em uma 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);
}Observaçþes: source Ă© uma URL data:, uma URL http(s) ou uma URI content:///file://; kind ('image'/'video') Ă© lido do tipo MIME quando omitido. Apps criados com IA usam saveToGallery() de @/lib/appmintNative.
Capacitor.AppwrightHaptics Capacitor#
Capacitor.Plugins.AppwrightHaptics
Exemplo
Plugin prĂłprio do AppMint para padrĂ”es de vibração ricos: uma lista de batidas, cada uma com seu prĂłprio inĂcio, duração e intensidade.
Retorna: play({ events }) resolve { ok: true } ou { ok: false, error } ('unsupported' = sem vibrador, 'empty' = sem eventos, ou a mensagem do sistema). Nunca Ă© rejeitada. isSupported() resolve { value: true/false }. Requer: nada para ativar - todo app declara a permissĂŁo de vibração, estando ou nĂŁo Vibrar marcado na Etapa 4 (Acesso). window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
Cada evento Ă© { at, duration, intensity, sharpness }: at = inĂcio em ms, duration = duração em ms (abaixo de 20 vira um toque de 30 ms), intensity = 0-1 (padrĂŁo 0,8). sharpness Ă© aceito mas ignorado no 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);Esconda o botĂŁo em celulares sem 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;
})();Toque duas vezes rapidamente em uma ação bem-sucedida e avise quando nĂŁo for possĂvel tocar:
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');
}Observaçþes: A intensidade sĂł funciona em celulares com controle de amplitude; os outros mantĂȘm o ritmo com uma intensidade fixa. Se o sistema recusar a vibração, play responde { ok: false, error: '<the system message>' }. Em apps criados com IA use hapticPlay de @/lib/appmintNative, que tambĂ©m tem padrĂ”es nomeados.
Capacitor.AppwrightLiveProgress Capacitor#
Capacitor.Plugins.AppwrightLiveProgress — start / update / end
Exemplo
O plugin Android prĂłprio do AppMint (seu nome em JS Ă© AppwrightLiveProgress) para uma notificação de status fixa, silenciosa e atualizada em tempo real (barra de progresso, indicador de carregamento ou relĂłgio em contagem) que abre uma rota quando tocada.
Retorna: start(opts) / update(opts) → Promise<{ ok: true, id }>, ou { ok: false, error } sem nada publicado - 'permission' quando as notificaçÔes nĂŁo sĂŁo permitidas (Android 13+: ainda nĂŁo concedidas, ou desativadas para o app), 'channel_disabled' quando o usuĂĄrio desativou a categoria "Live status"; end({ id }) → Promise<void>. Requer: o app Android e a permissĂŁo de notificação (Android 13+). NĂŁo disponĂvel na web.
Em um app criado com IA use o 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');Em uma pĂĄgina escrita Ă mĂŁo:
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' });
}Um cronĂŽmetro de treino: startedAt faz o cartĂŁo contar para cima sozinho, entĂŁo ele Ă© publicado uma vez e encerrado quando o treino para:
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 });
}OpçÔes: id (padrĂŁo 'live'), title, text, progress (0-1, omita para nĂŁo ter barra), indeterminate, startedAt (epoch em ms, mostra um relĂłgio em contagem), route.
Observaçþes: start e update fazem a mesma coisa (publicam ou substituem o cartĂŁo com esse id). O cartĂŁo nĂŁo pode ser dispensado com um gesto - chame sempre end. Peça a permissĂŁo antes: no Android 13+ sem ela start responde error: 'permission' e nĂŁo publica nada.
Capacitor.AppwrightSystemPalette Capacitor#
Capacitor.Plugins.AppwrightSystemPalette — get()
Exemplo
Retorna as cores Material You do celular (a paleta que o Android 12+ gera a partir do papel de parede), para que o app combine com os apps do sistema. Plugin prĂłprio do AppMint (AppwrightSystemPalettePlugin.kt).
Retorna: Promise { available: false } abaixo do Android 12, senĂŁo { available: true, accent1, accent2, accent3, neutral1, neutral2 } - cada um um objeto de tom para cor hexadecimal, com tons '0', '10', '50', '100' … '900', '1000' (por exemplo accent1['600'] === '#3F5F90'). Requer: nada para ativar - todo app hospeda o plugin. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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();Em um app criado com IA:
import { systemPalette } from '@/lib/appmintNative';
const p = await systemPalette();
if (p.available && p.accent1) document.documentElement.style.setProperty('--accent', p.accent1['600']);Escolha tons claros ou escuros para combinar com o tema do sistema e leia a paleta de novo quando o usuĂĄrio voltar de trocar o papel de parede:
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();Observaçþes: Verifique o contraste do texto antes de aplicar as cores da paleta - nĂŁo hĂĄ garantia de que um tom do papel de parede seja legĂvel sobre o seu fundo. Os navegadores nĂŁo expĂ”em cores do papel de parede: na web o wrapper responde { available: false }. As cores mudam quando o usuĂĄrio troca o papel de parede; chame get() de novo ao retomar.
Capacitor.AppwrightWidget Capacitor#
Capacitor.Plugins.AppwrightWidget — set(card), clear(), placedCount(), requestPin()
Exemplo
Preenche o widget da tela inicial do app: um cartĂŁo com tĂtulo, um valor grande, atĂ© doze linhas, suas cores e uma rota ao tocar - o mesmo cartĂŁo que AppMint.widget.set() aceita, com todas as chaves. O cartĂŁo Ă© salvo no celular e continua aparecendo mesmo depois de reiniciar. Plugin prĂłprio do AppMint (AppwrightWidgetPlugin.kt).
Retorna: set({ title?, value?, caption?, lines?, route?, bg?, ink?, accent?, textSize?, align?, wrap?, … }) → Promise { ok: true, placed }, rejeitada com o motivo de um cartĂŁo invĂĄlido (placed = widgets atualmente na tela inicial). clear() → void. placedCount() → { value }. requestPin() → { value: boolean } (true quando a folha "adicionar widget" do launcher foi aberta). Requer: nada para ativar - todo app declara o widget. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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'
});
}Ofereça adicionå-lo (somente quando nenhum estiver adicionado ainda):
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.');
}Em um app criado com 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();Observaçþes: As cores sĂŁo #RRGGBB, #AARRGGBB (alfa primeiro) ou rgba(); as vazias usam um cartĂŁo escuro com um valor ciano. Veja AppMint.widget para linhas estilizadas, caption, textSize, align, wrap e font (seu prĂłprio arquivo .ttf/.otf, informado como um caminho no seu app). O toque abre o app em route como um deep link (leia com WebToApk.getLaunchUrl() ou o evento appmint:deep-link). Antes de qualquer set() o widget diz "Nothing to show yet"; clear() o devolve a esse estado. Em um navegador can('widget') Ă© 'none'.
Capacitor.Badge Capacitor#
Capacitor.Plugins.Badge — the launcher-icon count
Exemplo
O plugin Badge (capawesome) que define o nĂșmero no Ăcone do app no launcher.
Retorna: Promises: set({ count }), clear(), increase(), decrease() → void; get() → { count }; isSupported() → { isSupported }. O plugin Android nĂŁo tem mĂ©todos de permissĂŁo. Requer: nada no Android. NĂŁo disponĂvel na web.
Em um app criado com IA use o wrapper badge de @/lib/appmintNative:
import { badge } from '@/lib/appmintNative';
await badge.set(3);
await badge.clear();Em uma pĂĄgina escrita Ă mĂŁo:
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);
});Conte para cima e para baixo conforme os itens chegam e sĂŁo lidos:
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);
}Observaçþes: no Android a aparĂȘncia depende do launcher (um nĂșmero, um ponto ou nada). navigator.setAppBadge(n) no app grava no mesmo badge (sĂł existe em launchers que conseguem mostrar uma contagem).
Capacitor.BarcodeScanner Capacitor#
Capacitor.Plugins.BarcodeScanner — scan, startScan, readBarcodesFromImage, isSupported
Exemplo
Leitura de QR e códigos de barras com a API @capacitor-mlkit/barcode-scanning - o plugin próprio do app (BarcodeScannerPlugin.kt) sobre o mesmo scanner de códigos do Google que AppMint.scanCode(). As chamadas mais antigas de @capacitor-community/barcode-scanner (startScan() resolvendo { hasContent, content }, checkPermission, prepare, hideBackground) compartilham este nome e também funcionam.
Retorna: scan({ formats?, autoZoom? }) → { barcodes: [{ rawValue, displayValue, format, valueType, bytes?, cornerPoints?, urlBookmark?, wifi?, email?, phone?, sms?, geoPoint?, contactInfo?, calendarEvent?, driverLicense? }] } (rejeita "scan canceled." quando o usuĂĄrio desiste); readBarcodesFromImage({ path, formats? }) → { barcodes }; isSupported() → { supported }; isGoogleBarcodeScannerModuleAvailable() → { available }; installGoogleBarcodeScannerModule() (progresso como googleBarcodeScannerModuleInstallProgress); checkPermissions() / requestPermissions() → { camera }; openSettings(). format Ă© 'QR_CODE', 'EAN_13', 'CODE_128'… Requer: nada para ativar e nenhuma permissĂŁo de cĂąmera - o scanner do Google desenha a prĂłpria tela (o Play services o baixa no primeiro uso). window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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 preço a partir do cĂłdigo de barras de um produto, com o estilo de listener (startScan + barcodesScanned) que os apps ML Kit jĂĄ usam:
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'] });
}Leia um QR code de uma foto que o usuĂĄrio jĂĄ tem:
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;
}Observações: O startScan() original mostra uma prévia ao vivo da câmera atrás de uma página transparente e continua escaneando até stopScan(); aqui ele abre a tela do scanner, o primeiro código dispara barcodeScanned / barcodesScanned e a sessão termina (a chamada então resolve { hasContent, content, format } para código da comunidade; um scanner fechado resolve { hasContent: false }). A lanterna e o zoom pertencem a essa prévia, então isTorchAvailable() é false e os setters de lanterna/zoom rejeitam - a tela do scanner tem seu próprio botão de lanterna. checkPermissions() responde granted quando o app não tem nenhuma permissão de câmera (o scanner não precisa de nenhuma); um app que também usa a câmera recebe o estado real. Apps criados com IA usam scanCode() de @/lib/appmintNative.
Capacitor.Browser Capacitor#
Capacitor.Plugins.Browser — open({ url, toolbarColor }), close(), addListener('browserFinished')
Exemplo
Abre uma pĂĄgina web em uma aba de navegador dentro do app (Chrome Custom Tabs), para que o usuĂĄrio leia termos, documentação ou uma pĂĄgina de login e volte com um Ășnico gesto (@capacitor/browser 8.0.3).
Retorna: open() / close() → Promise void. Eventos: browserFinished (o usuĂĄrio fechou a aba) e browserPageLoaded. Requer: nada - todo app hospeda o plugin (um navegador que suporte Custom Tabs, como o Chrome, precisa estar instalado). window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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' });
}Em um app criado com IA (uma nova aba na 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 careAbra um link e feche a aba quando o retorno de um login chegar Ă 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 () {});
});Observaçþes: url nĂŁo pode estar vazio. toolbarColor Ă© uma cor hexadecimal; uma invĂĄlida Ă© ignorada. close() tambĂ©m funciona no Android nesta versĂŁo do plugin (ele encerra a activity host da aba) - Ăștil depois que um link de login volta para o app. A aba Ă© um navegador separado: ela nĂŁo compartilha os cookies do app nem localStorage.
Capacitor.Calendar Capacitor#
Capacitor.Plugins.Calendar — createEvent, findEvents, deleteEvent, listCalendars, openCalendar
Exemplo
Adiciona, encontra e exclui eventos na agenda do prĂłprio celular (Android CalendarContract) e abre o app de agenda em uma data. Incluso @capacitor/calendar (template/plugins/calendar).
Retorna: createEvent() → { id }; findEvents() → { events: [{ id, title, location?, notes?, startDate, endDate, isAllDay, calendarId, calendarName?, attendees? }] }; listCalendars() → { calendars: [{ id, name, displayName?, isPrimary }] }; deleteEvent(), openCalendar() → void. As datas sĂŁo em milissegundos desde a Ă©poca (epoch). Requer: marque Agenda na Etapa 4 (Acesso) ao compilar. Em apps HTML, ZIP e criados com IA, o build tambĂ©m adiciona a permissĂŁo de agenda sozinho quando seus arquivos contĂȘm uma chamada Calendar.<method>( escrita exatamente assim (como abaixo) ou o calendar.createEvent( do wrapper. O plugin pede ao usuĂĄrio acesso Ă agenda no primeiro uso. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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);
}
}Leia esta semana, exclua um evento, abra a agenda:
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 });
}Em um app criado com IA (na web createEvent baixa um arquivo .ics; ler retorna []):
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());
}Observaçþes: Sem a permissĂŁo de agenda no app, nenhum diĂĄlogo aparece e toda chamada de evento Ă© rejeitada (missing permission); um usuĂĄrio que diz nĂŁo recebe OS-PLUG-CLDR-0020. recurrence: { frequency: 'daily' | 'weekly' | 'monthly' | 'yearly', interval?, count?, endDate? } cria um evento recorrente. createEventInteractively({ title, startDate, endDate }) abre o prĂłprio editor do app de agenda: resolve { id } do evento salvo e Ă© rejeitada com OS-PLUG-CLDR-0006 quando o usuĂĄrio fecha o editor sem salvar (precisa de acesso de leitura e de escrita para distinguir os dois casos). deleteEvent({ id, fromDate }) encerra um evento recorrente antes de fromDate e mantĂ©m as ocorrĂȘncias anteriores. O wrapper retorna null / [] / false em vez de gerar erro.
Capacitor.Camera Capacitor#
Capacitor.Plugins.Camera
Exemplo
O plugin oficial Capacitor Camera, incluĂdo no app: tire uma foto com a cĂąmera ou escolha fotos da galeria.
Retorna: Promises. getPhoto(opts) → { dataUrl | base64String | webPath, format, saved } (qual campo depende de resultType), e Ă© REJEITADA quando o usuĂĄrio cancela; pickImages(opts) → { photos: [{ webPath, format }] }; checkPermissions() / requestPermissions({ permissions }) → { camera, photos }. Requer: marque CĂąmera na Etapa 4 (Acesso). Em apps HTML, ZIP e criados com IA, o build tambĂ©m adiciona a permissĂŁo de cĂąmera sozinho quando seus arquivos contĂȘm Camera.getPhoto( escrito exatamente assim (como abaixo), getUserMedia com vĂdeo, ou <input capture>. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
Tire uma foto e mostre-a.
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.
}
}Escolha até 5 fotos da galeria.
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 */ }
}Em um app criado com IA use o wrapper, que também funciona na web (e retorna null em vez de gerar erro ao cancelar):
import { camera } from '@/lib/appmintNative';
const photo = await camera.take({ source: 'camera' });Observaçþes: pickImages nĂŁo precisa de permissĂŁo de cĂąmera. Se a permissĂŁo de cĂąmera nĂŁo estĂĄ no app (a opção estava desligada e o build nĂŁo achou nenhuma chamada de cĂąmera), a permissĂŁo Ă© recusada sem nenhum aviso. Um <input type="file" accept="image/*" capture> tambĂ©m abre a cĂąmera. A cĂąmera Ă© sensĂvel: declare-a no seu formulĂĄrio de Segurança dos dados do Play.
Capacitor.CapacitorBarcodeScanner Capacitor#
Capacitor.Plugins.CapacitorBarcodeScanner — scanBarcode({ hint })
Exemplo
Leitura de QR / cĂłdigo de barras em uma chamada com a API oficial @capacitor/barcode-scanner - o plugin prĂłprio do app (CapacitorBarcodeScannerPlugin.kt) sobre o mesmo scanner de cĂłdigos do Google que AppMint.scanCode(). O cĂłdigo escrito para o pacote npm (CapacitorBarcodeScanner.scanBarcode({ hint: CapacitorBarcodeScannerTypeHint.ALL })) funciona sem alteraçÔes.
Retorna: scanBarcode({ hint, scanInstructions?, cameraDirection?, scanOrientation? }) → { ScanResult, format }. hint / format sĂŁo os nĂșmeros do pacote: 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. Ă rejeitada com o cĂłdigo OS-PLUG-BARC-0006 quando o usuĂĄrio fecha o scanner. Requer: nada para ativar e nenhuma permissĂŁo de cĂąmera - o scanner do Google desenha a prĂłpria tela (o Play services o baixa no primeiro uso). window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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);
}
};Aceite qualquer cĂłdigo e diga ao usuĂĄrio de que tipo ele 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;
}Trate uma rejeição que nĂŁo seja o usuĂĄrio fechando o scanner:
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;
}
}Observaçþes: scanInstructions, scanButton, cameraDirection e scanOrientation estilizam a tela de cĂąmera do projeto original e nĂŁo tĂȘm efeito no scanner do Google (sempre a cĂąmera traseira). MAXICODE, RSS_14, RSS_EXPANDED e UPC_EAN_EXTENSION nĂŁo sĂŁo suportados como hint (rejeita OS-PLUG-BARC-0008); 17 (ALL) lĂȘ todos os tipos suportados. Apps criados com IA usam scanCode() de @/lib/appmintNative.
Capacitor.CapacitorCookies Capacitor#
Capacitor.Plugins.CapacitorCookies — getCookies / setCookie / deleteCookie / clearCookies / clearAllCookies
Exemplo
LĂȘ e grava os cookies do app, incluindo os de outro host com o qual sua pĂĄgina conversa (do nĂșcleo do Capacitor, CapacitorCookies).
Retorna: getCookies({ url? }) → { [name]: value } - com um url, os cookies que essa URL (host e caminho) enviaria; sem ele, o document.cookie da própria página. Rejeita uma url que não seja http(s). setCookie({ key, value, url?, path?, expires? }), deleteCookie({ key, url? }), clearCookies({ url? }), clearAllCookies() → Promise void; setCookie / deleteCookie rejeitam sem uma key string (e value) e então não gravam nada. Requer: nada para ativar - todo app hospeda o plugin. window.Capacitor existe em páginas que o próprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Site, no seu próprio site (seu domínio e subdomínios) - nunca em outros sites que o app abre. Detecte o recurso.
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 });
}Sair da conta: apague os cookies desse host, ou todos os cookies que o app guarda.
async function signOut(everything) {
if (!Cookies) return;
if (everything) await Cookies.clearAllCookies();
else await Cookies.clearCookies({ url: 'https://api.example.com' });
}Observaçþes: Um cookie definido com um path sĂł Ă© devolvido para um url sob esse caminho. Os valores sĂŁo decodificados de URL ao ler. Os cookies sĂŁo compartilhados por todas as pĂĄginas que o app mostra, entĂŁo nunca guarde segredos em um que uma pĂĄgina externa possa ler - eles pertencem a Preferences ou ao armazenamento seguro do app.
Capacitor.CapacitorSQLite Capacitor#
Capacitor.Plugins.CapacitorSQLite — createConnection, open, execute, query, run, executeSet, close
Exemplo
Um banco de dados SQLite de verdade no celular, com a API @capacitor-community/sqlite. Incluso @capacitor-community/sqlite (template/plugins/sqlite), rodando no SQLite do prĂłprio Android. O cĂłdigo escrito para o pacote npm (new SQLiteConnection(CapacitorSQLite)) funciona sem alteraçÔes; uma pĂĄgina escrita Ă mĂŁo chama o objeto do plugin diretamente, como abaixo.
Retorna: 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 backups. Requer: nada para ativar e nenhuma permissĂŁo. O banco de dados fica no armazenamento privado do app e sobrevive Ă s atualizaçÔes do app. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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 || [];
}VĂĄrias gravaçÔes que devem ser todas concluĂdas ou nenhuma - uma transação com 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()] },
] });
}Abra o banco de dados apenas uma vez por inicialização do app, mesmo quando duas telas pedem ao mesmo tempo:
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;
}Observaçþes: O app Ă© compilado sem SQLCipher, entĂŁo os bancos de dados nĂŁo sĂŁo criptografados: encrypted: true, setEncryptionSecret, changeEncryptionSecret, isSecretStored e as demais chamadas de criptografia sĂŁo rejeitadas com "Encryption is not available in this app". isInConfigEncryption() responde false. Todo o resto (consultas, valores vinculados, transaçÔes, atualizaçÔes versionadas com addUpgradeStatement, importação/exportação JSON) Ă© cĂłdigo do prĂłprio plugin. As rejeiçÔes trazem o texto de erro do SQLite.
Capacitor.Clipboard Capacitor#
Capacitor.Plugins.Clipboard — write(options), read()
Exemplo
Copia texto (ou um link) para a ĂĄrea de transferĂȘncia do sistema e o lĂȘ de volta (@capacitor/clipboard 8.0.1).
Retorna: write({ string?, url?, image?, label? }) → Promise void. read() → Promise { value, type } (type é 'text/plain' para texto). Requer: nada para ativar - todo app hospeda o plugin. window.Capacitor existe em páginas que o próprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Site, no seu próprio site (seu domínio e subdomínios) - nunca em outros sites que o app abre. Detecte o recurso.
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);
}
}Em um app criado com IA o wrapper no formato Capacitor transforma uma ĂĄrea de transferĂȘncia vazia em '':
import { Clipboard } from '@/lib/appmintNative';
await Clipboard.write({ string: 'ABC-123' });
const { value } = await Clipboard.read(); // '' when the clipboard is emptyCopie um link e confirme com um toque de feedback:
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;
}Observaçþes: write precisa de um entre string, url ou image (um data URL), senĂŁo Ă© rejeitado com "No data provided". O Android 12+ mostra o prĂłprio aviso "pasted from…" ao ler - isso Ă© do sistema, nĂŁo do app. O write do wrapper envia apenas string || url.
Capacitor.Contacts Capacitor#
Capacitor.Plugins.Contacts — getContacts, getContact, pickContact, createContact, deleteContact
Exemplo
A agenda de contatos do celular com a API @capacitor-community/contacts. Incluso @capacitor-community/contacts (template/plugins/contacts). O cĂłdigo escrito para o pacote npm funciona sem alteraçÔes.
Retorna: checkPermissions() / requestPermissions() → { contacts, contactsWrite } (cada 'granted' | 'denied' | 'prompt'; contacts Ă© leitura, contactsWrite Ă© adicionar e excluir); getContacts({ projection }) → { contacts: [ContactPayload] }; getContact({ contactId, projection }) e pickContact({ projection }) → { contact }; createContact({ contact }) → { contactId }; deleteContact({ contactId }) → void. projection escolhe os campos: { name, phones, emails, organization, birthday, note, urls, postalAddresses, image } (cada true). Requer: marque Contatos na Etapa 4 (Acesso) para ler, e tambĂ©m Editar contatos para adicionar ou excluir. Builds HTML, ZIP e AI-Studio marcam essas opçÔes sozinhos quando o cĂłdigo chama Contacts.getContacts( / getContact( / pickContact( (leitura) ou Contacts.createContact( / deleteContact( (ambos). O plugin pergunta ao usuĂĄrio no primeiro uso; sem a opção marcada a chamada Ă© rejeitada com "Permission is required to access contacts." - e em um app sem Contatos, SMS ou Registro de chamadas marcados o plugin nem estĂĄ no app (o Capacitor rejeita com "not implemented"). window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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 }));
}Deixe o usuário escolher uma pessoa no seletor do 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.
}
};Salve um cartĂŁo de visita do app na agenda de contatos:
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;
}Observações: pickContact() rejeita com o código CANCELLED quando o usuário sai do seletor. O Android só preenche contactId, name, phones, emails, organization, birthday, note, urls, postalAddresses e image quando a projeção os pede - peça apenas o que você mostra. Ler contatos é uma permissão sensível no Google Play: descreva o motivo no formulário de segurança de dados da ficha. Apps criados com IA usam listContacts(), pickContact() e addContact() de @/lib/appmintNative.
Capacitor.Device Capacitor#
Capacitor.Plugins.Device
Exemplo
O plugin oficial Capacitor Device, incluĂdo no app: modelo do celular, versĂŁo do sistema, bateria, um ID estĂĄvel e o idioma.
Retorna: Promises. getInfo() → { model, platform, operatingSystem, osVersion, androidSDKVersion, manufacturer, isVirtual, webViewVersion, … }; getId() → { identifier }; getBatteryInfo() → { batteryLevel (0–1), isCharging }; getLanguageCode() → { value }. Requer: nada para ativar. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
Mostre o celular e a bateria.
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';
}
}Um ID estĂĄvel e o 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 })
});
}Em um app criado com IA use o wrapper, que também funciona na web:
import { Device } from '@/lib/appmintNative';
const info = await Device.getInfo();Observaçþes: Para o ID de build do Android, patch de segurança, tela, memĂłria e rede, o WebToApk.getDeviceInfo() do shell dĂĄ mais detalhes. Os ids do plugin nĂŁo sĂŁo ids de hardware; eles podem mudar depois de uma restauração de fĂĄbrica.
Capacitor.Dialog Capacitor#
Capacitor.Plugins.Dialog — alert, confirm, prompt
Exemplo
Mostra um diĂĄlogo real do sistema Android: uma mensagem, uma pergunta de sim/nĂŁo ou uma pergunta de texto de uma linha (@capacitor/dialog 8.0.1).
Retorna: alert({ title?, message, buttonTitle? }) → Promise void. confirm({ title?, message, okButtonTitle?, cancelButtonTitle? }) → { value: boolean }. prompt({ title?, message, okButtonTitle?, cancelButtonTitle?, inputPlaceholder?, inputText? }) → { value: string, cancelled: boolean }. Requer: nada para ativar - todo app hospeda o plugin. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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 e 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());
}Em um app criado com IA o wrapper nunca rejeita: dispensar Ă© { value: false } / { cancelled: true }, e na web ele usa as prĂłprias caixas de diĂĄlogo do navegador:
import { Dialog } from '@/lib/appmintNative';
const { value } = await Dialog.confirm({ title: 'Delete note?', message: 'This cannot be undone.' });
if (value) removeNote(id);Observaçþes: message Ă© obrigatĂłrio - sem ele o plugin rejeita com "Please provide a message for the dialog". Os diĂĄlogos sĂŁo modais; use-os apenas para decisĂ”es que precisam bloquear.
Capacitor.Filesystem Capacitor#
Capacitor.Plugins.Filesystem
Exemplo
O plugin Filesystem padrĂŁo do Capacitor: lĂȘ e grava arquivos no armazenamento PRĂPRIO do app (nĂŁo em uma pasta escolhida pelo usuĂĄrio - para isso use WebToApkFS).
Retorna: todo mĂ©todo retorna uma Promise e Ă© rejeitado em caso de falha (por exemplo, ler um arquivo que nĂŁo existe). readFile → { data }, writeFile → { uri }, readdir → { files: [{ name, type, size, mtime, uri }] }, mkdir / deleteFile → nada. Requer: nada para ativar; 'DATA' e 'CACHE' nĂŁo precisam de permissĂŁo.
Uma pågina não tem imports de Directory / Encoding, então passe as strings simples 'DATA' (arquivos privados do app, mantidos até desinstalar) ou 'CACHE' (o sistema pode limpar) e '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
}
}Omita encoding para gravar ou ler dados binĂĄrios em 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); });
}Em apps criados com IA, o wrapper @/lib/appmintNative que usa este plugin Ă© fileTransfer (ele prepara downloads e uploads em '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 insteadObservações: window.Capacitor existe apenas dentro do app - sempre detecte o recurso. Os arquivos em 'DATA' são privados do app e apagados ao desinstalar; para colocar arquivos onde o usuário possa vê-los, use WebToApkFS (uma pasta que o usuário concede) ou um download.
Capacitor.FileTransfer Capacitor#
Capacitor.Plugins.FileTransfer
Exemplo
O plugin oficial Capacitor File Transfer: baixa uma URL para um arquivo no celular, ou envia um arquivo do celular, de forma nativa, com eventos de progresso.
Retorna: downloadFile({url, path, headers?, progress?}) → Promise<{path}>; uploadFile({url, path, fileKey?, mimeType?, method?, headers?, progress?}) → Promise<{bytesSent, responseCode, response, headers}>. O progresso chega como eventos de listener 'progress' {type, url, bytes, contentLength, lengthComputable}. As falhas sĂŁo rejeitadas com {message, code}. Requer: nada para ativar. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites. Sempre detecte o recurso antes de usar.
Baixe para o cache do app com progresso:
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();
}
}Envie um arquivo que jĂĄ estĂĄ no celular:
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); });
}Informe uma transferĂȘncia que falhou pelo 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;
}
}Observaçþes: O caminho deve ser um caminho de arquivo ou uma URI file://, nĂŁo um Blob - grave antes o Blob no cache com Filesystem.writeFile. No Android 10 e anteriores, um caminho no armazenamento pĂșblico pede permissĂŁo de armazenamento. Em apps criados com IA prefira fileTransfer de @/lib/appmintNative, que faz tudo isso e tambĂ©m funciona na web.
Capacitor.FileViewer Capacitor#
Capacitor.Plugins.FileViewer
Exemplo
O plugin oficial Capacitor File Viewer: abre um documento ou arquivo de mĂdia no app visualizador do celular, a partir de um endereço web, de um caminho de arquivo local ou de um arquivo incluĂdo no app.
Retorna: cada mĂ©todo retorna uma Promise<void> que Ă© rejeitada com {message, code} quando nada consegue abrir o arquivo. Requer: nada para ativar. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites. Sempre detecte o recurso antes de usar.
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.');
}
}Um arquivo no celular, por exemplo um escrito com 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 um arquivo empacotado na pasta de assets do prĂłprio APK. Os mesmos trĂȘs mĂ©todos tambĂ©m existem como previewMediaContentFromUrl, previewMediaContentFromLocalPath e previewMediaContentFromResources para vĂdeo e ĂĄudio.
Baixe um arquivo e abra-o quando chegar:
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:\/\//, '') });
}Observaçþes: Em apps criados com IA prefira fileViewer.open(target) de @/lib/appmintNative, que escolhe o mĂ©todo certo e tambĂ©m funciona na web. Um caminho local Ă© um caminho simples (sem file://).
Capacitor.Geolocation Capacitor#
Capacitor.Plugins.Geolocation
Exemplo
O plugin oficial Capacitor Geolocation, incluĂdo no app: a posição do celular uma vez, ou atualizaçÔes contĂnuas.
Retorna: Promises. getCurrentPosition(opts) → { timestamp, coords: { latitude, longitude, accuracy, altitude, speed, heading, … } }; watchPosition(opts, callback) → o id da observação (uma string); clearWatch({ id }); checkPermissions() / requestPermissions() → { location, coarseLocation } ('granted' | 'denied' | 'prompt' | …). Requer: GPS e/ou Localização na Etapa 4 (Acesso) - em apps HTML, ZIP e criados com IA o build tambĂ©m os ativa sozinho quando seus arquivos chamam getCurrentPosition ou watchPosition. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
Posição uma vez, pedindo permissĂŁo 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, …
}
}Atualizaçðes contĂnuas. O callback recebe (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; }
}Em um app criado com IA use o wrapper, que também funciona na web:
import { Geolocation } from '@/lib/appmintNative';
const pos = await Geolocation.getCurrentPosition({ enableHighAccuracy: true });Observaçþes: O navigator.geolocation simples tambĂ©m funciona no app. Se os interruptores de localização estavam desligados na hora da compilação, a permissĂŁo Ă© recusada sem nenhum aviso. No Android 12+ o usuĂĄrio pode permitir apenas a localização aproximada (coarseLocation concedida). A localização Ă© um dado pessoal: declare-a no seu formulĂĄrio de Segurança dos dados do Play.
Capacitor.Haptics Capacitor#
Capacitor.Plugins.Haptics
Exemplo
O plugin oficial Capacitor Haptics (@capacitor/haptics), incluĂdo no app: toques leves/mĂ©dios/fortes, feedback de sucesso/aviso/erro, tiques de seleção e vibração simples.
Retorna: todo método retorna uma Promise que resolve sem valor. Requer: nada para ativar - todo app declara a permissão de vibração, esteja ou não Vibrar marcado na Etapa 4 (Acesso). window.Capacitor existe em páginas que o próprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Site, no seu próprio site (seu domínio e subdomínios) - nunca em outros sites que o app abre. Detecte o recurso.
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'); });Tiques de seleção para um seletor ou controle deslizante, e uma vibração simples:
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
});Vibre em um erro e combine com uma mensagem visĂvel:
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 () {});
}Observaçþes: As strings sĂŁo em maiĂșsculas ('HEAVY', nĂŁo 'heavy'). Em apps criados com IA, import { Haptics } from '@/lib/appmintNative' oferece os mesmos nomes. Para ritmos personalizados com intensidade por batida, use Capacitor.Plugins.AppwrightHaptics.
Capacitor.InAppReview Capacitor#
Capacitor.Plugins.InAppReview — requestReview()
Exemplo
Pede ao Google Play que mostre a prĂłpria folha "avalie este app" dentro do app. Incluso @capacitor-community/in-app-review (template/plugins/in-app-review).
Retorna: Promise void - ela resolve quando o fluxo do Play termina, e o Play nunca diz se a folha foi exibida nem o que o usuĂĄrio fez. Ă rejeitada quando o Play nĂŁo conseguiu iniciar o fluxo. Requer: nada para ativar; o app precisa estar instalado pelo Google Play para a folha aparecer. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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
}Em um app criado com IA:
import { requestReview } from '@/lib/appmintNative';
// after a success moment, not on launch
const asked = await requestReview(); // false where nothing could be asked (web)Pergunte uma vez, depois de um momento de sucesso, e lembre-se de que jĂĄ perguntou:
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); }
}Observaçþes: O Play limita a frequĂȘncia com que a folha aparece e nĂŁo a mostra a cada chamada - nunca vincule uma recompensa a ela e nunca peça a partir de um botĂŁo "Avalie-nos" esperando que ela abra (para isso abra a pĂĄgina do app na loja). Peça depois de um momento de sucesso, nĂŁo na inicialização. Uma instalação por sideload ou de debug geralmente nĂŁo mostra nada.
Capacitor.KeepAwake Capacitor#
Capacitor.Plugins.KeepAwake — keepAwake(), allowSleep(), isKeptAwake(), isSupported()
Exemplo
Impede que a tela escureça e bloqueie enquanto algo precisa continuar visĂvel - uma receita, uma rota, um QR code, um cronĂŽmetro. Incluso @capacitor-community/keep-awake (template/plugins/keep-awake).
Retorna: keepAwake() / allowSleep() → Promise void. isKeptAwake() → { isKeptAwake: boolean }. isSupported() → { isSupported: true }. Requer: nada - todo app hospeda o plugin; nenhuma permissĂŁo. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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); });Em um app criado com IA (a Screen Wake Lock API na web):
import { keepAwake } from '@/lib/appmintNative';
useEffect(() => {
void keepAwake(true);
return () => { void keepAwake(false); };
}, []);Mantenha a tela ligada apenas enquanto um cronĂŽmetro estiver rodando:
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');
}Observaçþes: O sinalizador pertence Ă janela do app: sĂł funciona enquanto o app estĂĄ em primeiro plano e continua atĂ© allowSleep() - libere-o em toda saĂda da tela. keepAwake() retorna false quando nada conseguiu manter a tela ligada.
Capacitor.Keyboard Capacitor#
Capacitor.Plugins.Keyboard — show(), hide(), addListener('keyboardDidShow' | ...)
Exemplo
Abre ou fecha o teclado virtual e avisa a pĂĄgina quando ele aparece e qual Ă© a altura (@capacitor/keyboard 8.0.5).
Retorna: show() / hide() → Promise void. addListener(event, fn) → uma Promise de um handle com remove(), como na API do prĂłprio Capacitor - use await nele ou encadeie .then(); o valor retornado tambĂ©m tem remove() por si sĂł; os eventos de exibição passam { keyboardHeight } em pixels CSS. Eventos: keyboardWillShow, keyboardDidShow, keyboardWillHide, keyboardDidHide. Requer: nada para ativar - todo app hospeda o plugin. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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
}Em um app criado com IA use onKeyboard() para o layout - ele informa apenas a parte do teclado que a pĂĄgina redimensionada ainda nĂŁo liberou - e hideKeyboard() para fechĂĄ-lo:
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();Mostre o teclado para um campo depois de tocar em um botĂŁo:
var Keyboard = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Keyboard;
searchBtn.addEventListener('click', function () {
searchInput.focus();
if (Keyboard) Keyboard.show().catch(function () {});
});Observaçþes: O shell jĂĄ redimensiona a pĂĄgina para o teclado, entĂŁo NĂO adicione o keyboardHeight inteiro como preenchimento - uma barra inferior jĂĄ fica acima das teclas. setAccessoryBarVisible, setStyle, setResizeMode e setScroll nĂŁo estĂŁo implementados no Android - nĂŁo os chame. hide() rejeita com "Can't close keyboard, not currently focused" quando nada tem o foco.
Capacitor.LocalNotifications Capacitor#
Capacitor.Plugins.LocalNotifications — schedule, cancel, getPending, requestPermissions, events
Exemplo
NotificaçÔes que o prĂłprio app publica - agora ou em um horĂĄrio - com a API oficial @capacitor/local-notifications (com.capacitorjs:local-notifications). O cĂłdigo escrito para o pacote npm funciona sem alteraçÔes.
Retorna: 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 Ă© 'tap' para um toque na prĂłpria notificação). Requer: marque NotificaçÔes na Etapa 4 (Acesso) - sem isso o plugin nĂŁo estĂĄ no app e toda chamada Ă© rejeitada com "not implemented". Para notificaçÔes agendadas marque tambĂ©m â° Lembretes (horĂĄrio exato e sobreviver a uma reinicialização). Builds HTML, ZIP e AI-Studio marcam as duas sozinhos quando o cĂłdigo importa @capacitor/local-notifications e chama LocalNotifications.schedule(. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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;
}Abra a tela certa quando o usuĂĄrio tocar em uma notificação - tambĂ©m quando o toque iniciou o app, jĂĄ que o evento espera pelo 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;
}
});
}Um lembrete diårio de håbito com botÔes Concluir / Adiar:
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) } }] });
}
});
}Observaçþes: No Android 12+ uma notificação agendada precisa da concessĂŁo de alarme exato: o primeiro schedule() pode abrir a pĂĄgina "Alarmes e lembretes" do sistema; se o usuĂĄrio deixar desativado, a notificação ainda dispara, um pouco depois (o resultado traz um warning). As notificaçÔes do plugin usam o prĂłprio canal "Default", separado das outras notificaçÔes do app. Um sound vindo dos arquivos web nĂŁo Ă© suportado (o Android toca o som padrĂŁo do canal). Os toques chegam Ă pĂĄgina pela tela de desbloqueio quando o app tem PIN. Apps criados com IA usam notify() / LocalNotifications.schedule de @/lib/appmintNative, que publica pela pilha de notificaçÔes do prĂłprio app.
Capacitor.Network Capacitor#
Capacitor.Plugins.Network — getStatus(), addListener('networkStatusChange')
Exemplo
Informa Ă pĂĄgina se o celular estĂĄ online e em que tipo de conexĂŁo, e quando isso muda (@capacitor/network 8.0.1).
Retorna: getStatus() → Promise { connected: boolean, connectionType: 'wifi' | 'cellular' | 'none' | 'unknown' }. O evento networkStatusChange passa o mesmo formato. Requer: nada para ativar - todo app hospeda o plugin. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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');
});
}Em um app criado com 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 unmountPause um envio grande quando estiver em dados mĂłveis:
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?');
}Observaçþes: connected significa que o celular tem rede, nĂŁo que seu servidor responde - continue tratando requisiçÔes que falham. O Network.getStatus() e o networkStatus() do wrapper leem navigator.onLine / navigator.connection, nĂŁo o plugin, entĂŁo o tipo pode ser 'unknown' ou uma classe de velocidade como '4g'; onNetworkChange() usa o evento do plugin no app.
Capacitor.Preferences Capacitor#
Capacitor.Plugins.Preferences — get / set / remove / keys / clear
Exemplo
Um pequeno armazenamento nativo de chave-valor (Android SharedPreferences) para strings (@capacitor/preferences 8.0.1).
Retorna: set({ key, value }), remove({ key }), clear() → Promise void; get({ key }) → { value } (null quando a chave nĂŁo existe); keys() → { keys: string[] }. Requer: nada para ativar - todo app hospeda o plugin. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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
}Objetos precisam ser convertidos em string antes:
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' });
}Liste e apague as chaves salvas a partir de uma tela de configurações:
async function resetSettings() {
if (!Prefs) return;
var k = (await Prefs.keys()).keys;
console.log('clearing', k.length, 'saved values');
await Prefs.clear();
}Observaçþes: @/lib/appmintNative NĂO tem wrapper de Preferences, de propĂłsito: localStorage jĂĄ Ă© real e persistente no app, e um segundo armazenamento dividiria os dados de um app em dois lugares. Apps criados com IA devem continuar usando localStorage (ou o runtime de dados). Use Preferences em uma pĂĄgina escrita Ă mĂŁo apenas se quiser todas as suas configuraçÔes ali, e escolha um armazenamento por valor. configure({ group }) muda o nome do armazenamento (padrĂŁo CapacitorStorage).
Capacitor.PrivacyScreen Capacitor#
Capacitor.Plugins.PrivacyScreen — enable(), disable(), isEnabled()
Exemplo
O plugin oficial @capacitor/privacy-screen: bloqueia capturas e gravaçÔes de tela e esconde o conteĂșdo do app na visualização de apps recentes. IncluĂdo para que projetos Capacitor importados que o chamam funcionem.
Retorna: enable({android}) → {success}; disable() → {success}; isEnabled() → {enabled}. Requer: nada para ativar.
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();
}Verifique o estado atual antes de alternar:
async function toggleProtection() {
if (!Privacy) return;
var s = await Privacy.isEnabled();
if (s.enabled) await Privacy.disable();
else await Privacy.enable();
}Proteja a tela apenas enquanto uma visualização sensĂvel estiver aberta:
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();
}Observaçþes: privacyModeOnActivityHidden: 'none', 'dim' ou 'splash'. O cĂłdigo escrito para o prĂłprio app deve usar WebToApk.setSecureScreen(true) / privacyScreen.enable() de @/lib/appmintNative, que acompanha a pĂĄgina (liberado quando o app sai dela); se misturar os dois, vale a Ășltima chamada.
Capacitor.PushNotifications Capacitor#
Capacitor.Plugins.PushNotifications — register, requestPermissions, registration, pushNotificationReceived
Exemplo
NotificaçÔes push do SEU prĂłprio servidor pelo SEU projeto Firebase, com a API oficial @capacitor/push-notifications (com.capacitorjs:push-notifications, registrada pelo PushNotificationsPlugin.kt do shell). O cĂłdigo escrito para o pacote npm funciona sem alteraçÔes: register() e depois envie para o token do evento registration com o Firebase Admin SDK ou a API FCM HTTP v1.
Retorna: requestPermissions() / checkPermissions() → { receive: 'granted' | 'denied' | 'prompt' }; register() / unregister() → void (o token chega como o evento registration { value }, uma falha como registrationError { error }); getDeliveredNotifications() → { notifications }; removeDeliveredNotifications({ notifications }), removeAllDeliveredNotifications(); createChannel({ id, name, importance? }), listChannels(), deleteChannel({ id }). Eventos: pushNotificationReceived (uma mensagem com o app aberto: { id, title?, body?, data }) e pushNotificationActionPerformed ({ actionId: 'tap', notification: { id, data } }). Requer: compile com AppMint Push ativado e seu google-services.json enviado (etapa Notificaçþes) - esse Ă© o projeto Firebase ao qual o token pertence. Sem isso register() Ă© rejeitado com o cĂłdigo PUSH_NOT_CONFIGURED ("Push is not set up in this app"). Builds HTML, ZIP e AI-Studio marcam Notificaçþes sozinhos quando o cĂłdigo chama PushNotifications.register( / requestPermissions( / addListener(. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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.'); }
}Reaja a uma mensagem enquanto o app estĂĄ aberto e ao toque em uma que chegou com o app fechado (o evento de toque espera pelo seu listener, entĂŁo uma inicialização a frio nĂŁo se perde):
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;
});
}Um canal para alertas importantes (Android 8+), usado por mensagens que o nomeiam em 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 });
}Observações: Uma mensagem enviada com um bloco notification é exibida pelo próprio Android enquanto o app está em segundo plano; o toque nela abre o app (pela tela de desbloqueio quando o app tem PIN) e dispara pushNotificationActionPerformed. Com o app aberto, as mensagens chegam como pushNotificationReceived e não são desenhadas na bandeja. Mensagens somente de dados chegam à página apenas enquanto ela está aberta. As mensagens do AppMint Push continuam funcionando lado a lado - elas nunca chegam a este plugin. Em um app criado com OneSignal em vez de AppMint Push, as mensagens são entregues pelo OneSignal e nunca chegam a este plugin. Apps criados com IA recebem pushes do criador por meio de pushInbox() de @/lib/appmintNative.
Capacitor.ScreenBrightness Capacitor#
Capacitor.Plugins.ScreenBrightness — getBrightness(), setBrightness({ brightness })
Exemplo
Define o brilho da tela da janela do app - brilho mĂĄximo para um cartĂŁo de embarque ou QR code e depois de volta ao normal. Incluso @capacitor-community/screen-brightness (template/plugins/screen-brightness).
Retorna: getBrightness() → Promise { brightness } (0-1, ou -1 quando o app nĂŁo o alterou e a tela segue o sistema). setBrightness({ brightness }) → Promise void. Requer: nada - todo app hospeda o plugin; nenhuma permissĂŁo (ele altera sĂł a janela deste app, nĂŁo a configuração do sistema). window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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;
}Em um app criado com 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 availableLeia primeiro o nĂvel atual e restaure exatamente esse:
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 });
}Observaçþes: Passe sempre um nĂșmero - setBrightness({}) nĂŁo tem valor a aplicar. Restaure com -1 quando a visualização fechar; a substituição tambĂ©m termina quando o app fecha. Uma pĂĄgina web nĂŁo controla a luz de fundo, entĂŁo can('brightness') Ă© 'none' em um navegador.
Capacitor.ScreenOrientation Capacitor#
Capacitor.Plugins.ScreenOrientation — orientation(), lock({ orientation }), unlock()
Exemplo
LĂȘ a orientação da tela, a fixa para uma visualização (um jogo, um grĂĄfico, um campo de assinatura) e a libera (@capacitor/screen-orientation 8.0.1).
Retorna: orientation() → Promise { type } (por exemplo 'portrait-primary'). lock() / unlock() → Promise void. O evento screenOrientationChange passa { type }. Requer: nada para ativar - todo app hospeda o plugin. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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); });
}Em um app criado com 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();Trate um bloqueio recusado e avise o usuĂĄrio:
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' });
}
}Observaçþes: Os wrappers sĂł conhecem portrait / landscape / any: ScreenOrientation.lock({ orientation: 'landscape-secondary' }) trava em landscape simples. DĂȘ ao usuĂĄrio uma saĂda de uma visualização travada.
Capacitor.ScreenReader Capacitor#
Capacitor.Plugins.ScreenReader — isEnabled(), speak({ value, language }), addListener('stateChange')
Exemplo
Informa Ă pĂĄgina se o TalkBack estĂĄ ligado e fala um anĂșncio (@capacitor/screen-reader 8.0.1).
Retorna: isEnabled() → Promise { value: boolean }. speak() → Promise void. O evento stateChange passa { value: boolean } quando o TalkBack Ă© ligado ou desligado. Requer: nada para ativar - todo app hospeda o plugin. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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' });
}Em um app criado com IA (speak usa texto para fala na web; isEnabled() Ă© false lĂĄ):
import { screenReader } from '@/lib/appmintNative';
const on = await screenReader.isEnabled();
const off = screenReader.onChange((enabled) => setCalmMode(enabled));
await screenReader.speak('Order placed', 'en');Detecte o recurso e mantenha a pĂĄgina utilizĂĄvel sem o 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
}Observaçþes: language tem como padrĂŁo 'en'. Prefira marcação acessĂvel normal (rĂłtulos, regiĂ”es aria-live) para a maioria dos anĂșncios; use speak para mudanças de estado curtas e importantes. NĂŁo existe API web para detectar um leitor de tela, entĂŁo can('screenReader') Ă© 'none' em um navegador.
Capacitor.SpeechRecognition Capacitor#
Capacitor.Plugins.SpeechRecognition
Exemplo
Transforma a fala do usuĂĄrio em texto com o reconhecedor de voz do Android (o plugin da comunidade @capacitor-community/speech-recognition, incluĂdo no app). O WebView do Android nĂŁo tem reconhecimento de voz Web Speech prĂłprio, entĂŁo este Ă© o caminho para ditado.
Retorna: Promises. available() → { available }. checkPermissions() / requestPermissions() → { speechRecognition: 'granted' | 'denied' | 'prompt' }. start({ partialResults: false }) → { status: 'success', matches: [...] } depois que o usuĂĄrio para de falar; Ă© rejeitada em erros como nenhuma fala ou nenhuma correspondĂȘncia. Requer: marque Microfone na Etapa 4 (Acesso) ao compilar (em apps HTML, ZIP e criados com IA o build tambĂ©m adiciona a permissĂŁo de microfone sozinho quando seus arquivos mencionam SpeechRecognition), e o usuĂĄrio precisa permitir o microfone. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
Ditado de uma vez (do mesmo jeito que @/lib/appmintNative speech o usa):
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 ao vivo enquanto o usuĂĄrio fala (partialResults: true) e o estado de escuta:
// 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(); });Mostre o botão de microfone apenas quando o ditado puder funcionar e pare de ouvir quando a página for ocultada:
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();
});Observaçþes:
- No modo ao vivo (
partialResults: true), o texto final chega depois do estado'stopped', entĂŁo nĂŁo remova o listenerpartialResultsem'stopped'. Um erro apĂłs o inĂcio (nenhuma fala, nenhuma correspondĂȘncia) nĂŁo Ă© informado neste modo. languageĂ© uma tag como'en-US'ou'ta-IN'(padrĂŁo: o idioma do celular).popup: truemostra a prĂłpria caixa de escuta do Google.getSupportedLanguages()→{ languages }eisListening()→{ listening }tambĂ©m existem.start()rejeita com'Missing permission'se vocĂȘ nĂŁo pediu a permissĂŁo antes. A escuta para sozinha depois de uma pausa na fala.
Capacitor.SplashScreen Capacitor#
Capacitor.Plugins.SplashScreen — show(), hide()
Exemplo
A API @capacitor/splash-screen sobre a tela de abertura personalizada do prĂłprio app, para que projetos Capacitor / AI Studio importados que chamam SplashScreen.hide() quando a primeira tela estĂĄ pronta funcionem no app Android.
Retorna: hide() → Promise (a tela de abertura sai depois que o tempo mĂnimo definido pelo criador passou); show({showDuration, autoHide}) → Promise (a tela de abertura volta sobre a pĂĄgina e, com autoHide - o padrĂŁo - sai depois de showDuration ms, padrĂŁo 3000). Requer: nada para ativar.
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();Cubra uma troca lenta de conta com a tela de abertura, mantida até os novos dados aparecerem na tela:
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();
}
}Mostre a tela de abertura personalizada por um instante depois de sair da conta; ela some sozinha depois 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);
}
}
}Observaçþes: sem uma chamada hide() a tela de abertura ainda sai na primeira renderização, como em todo app. Apps criados com IA usam splash.hold() / splash.ready() de @/lib/appmintNative.
Capacitor.StatusBar Capacitor#
Capacitor.Plugins.StatusBar — setStyle, setBackgroundColor, show, hide, getInfo
Exemplo
Altera o estilo dos Ăcones, a cor e a visibilidade da barra de status (@capacitor/status-bar 8.0.2).
Retorna: todo mĂ©todo → Promise void, exceto getInfo() → { visible, style, color, overlays, height }. Requer: nada para ativar - todo app hospeda o plugin. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
style indica o FUNDO que combina: 'DARK' = ícones claros (para uma barra escura), 'LIGHT' = ícones escuros, 'DEFAULT' = seguir o 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();
}Pinte a barra com a ponte do shell, nĂŁo com o plugin. No Android 15+ o setBackgroundColor do plugin nĂŁo faz nada (o modo edge-to-edge o ignora). O shell pinta a faixa por conta prĂłpria e recebe o estilo dos Ăcones na mesma chamada:
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
}Em um app criado com IA use setStatusBar(color, contentStyle); ele prefere a ponte do shell e define cor e Ăcones em uma sĂł chamada:
import { setStatusBar, StatusBar } from '@/lib/appmintNative';
setStatusBar('#0B0F1A', 'light'); // dark bar, light icons
await StatusBar.setBackgroundColor({ color: '#FFFFFF' }); // colour only; icons picked from luminanceObservaçþes: setBackgroundColor rejeita uma cor que nĂŁo seja uma string hexadecimal. Em builds de tela cheia / quiosque as barras sĂŁo ocultadas pelo shell. No app Android o StatusBar.setStyle() do wrapper sozinho nĂŁo muda nada (a ponte precisa de uma cor para pintar) - passe o estilo para setStatusBar() junto com uma cor.
Capacitor.TextToSpeech Capacitor#
Capacitor.Plugins.TextToSpeech — speak(), stop(), getSupportedLanguages(), getSupportedVoices()
Exemplo
O plugin da comunidade @capacitor-community/text-to-speech sobre o mecanismo de texto para fala do telefone. Incluído para que projetos Capacitor importados que o chamam funcionem.
Retorna: speak({text, lang, rate, pitch, volume, voice}) → Promise que resolve quando a frase foi falada; stop(); getSupportedLanguages() → {languages}; getSupportedVoices() → {voices}; isLanguageSupported({lang}) → {supported}. Requer: nada para ativar.
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();Verifique o idioma antes de falar e mostre uma mensagem quando ele nĂŁo estiver 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;
}Leia um parĂĄgrafo em voz alta com um botĂŁo de parar e trate um erro de fala:
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);
}
}Observaçþes: window.speechSynthesis tambĂ©m funciona no app (o motor do prĂłprio shell) e Ă© o que os apps criados com IA usam por meio de speak(); este plugin Ă© o caminho no formato Capacitor.
Capacitor.TextZoom Capacitor#
Capacitor.Plugins.TextZoom — get(), getPreferred(), set({ value })
Exemplo
LĂȘ e altera o tamanho do texto da pĂĄgina do app, para um controle de "tamanho do texto" dentro do app (@capacitor/text-zoom 8.0.1).
Retorna: get() → Promise { value } (zoom atual, 1 = 100%). getPreferred() → { value } (o tamanho que o usuĂĄrio escolheu nas configuraçÔes do Android). set({ value }) → Promise void. Requer: nada para ativar - todo app hospeda o plugin. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
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 });
}Em um app criado com IA (na web ele escala o tamanho da fonte da raiz):
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 sizeUm controle deslizante de tamanho de texto que lembra a escolha:
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;
}Observaçþes: O app jĂĄ segue o tamanho de texto do sistema; isto Ă© para um controle extra dentro do app. Teste seu layout em tamanhos grandes - alturas fixas em controles de texto vĂŁo cortar o conteĂșdo.
Capacitor.Toast Capacitor#
Capacitor.Plugins.Toast — show({ text, duration, position })
Exemplo
Mostra um toast curto do sistema Android como "Salvo" ou "Copiado" (@capacitor/toast 8.0.1).
Retorna: Promise void. Requer: nada para ativar - todo app hospeda o plugin. window.Capacitor existe nas pĂĄginas que o prĂłprio app serve (apps HTML, ZIP e criados com IA) e, em um app no modo Website, no seu prĂłprio site (seu domĂnio e subdomĂnios) - nunca em outros sites que o app abre. Detecte o recurso antes de usar.
var Toast = window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Toast;
function saved() {
if (Toast) Toast.show({ text: 'Saved', duration: 'short', position: 'bottom' });
}duration Ă 'short' (cerca de 2 s) ou 'long' (cerca de 3,5 s). position Ă© 'top', 'center' ou 'bottom'.
Em um app criado com IA use toast() ou o Toast no formato Capacitor; na web eles desenham uma snackbar nas cores do app:
import { Toast, toast } from '@/lib/appmintNative';
await Toast.show({ text: 'Added to list', duration: 'long' });
toast('Copied'); // short form, same resultDetecte o recurso e mostre uma mensagem na pĂĄgina quando o plugin nĂŁo existir:
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);
}Observações: text é obrigatório ("Must provide text"). O sistema desenha o toast no estilo do fabricante do telefone, e versões mais novas do Android ignoram position em toasts de texto. Um toast é fácil de perder - nunca o use para um erro que o usuário precise tratar; use Dialog.alert para isso.
Capacitor.Torch Capacitor#
Capacitor.Plugins.Torch — enable(), disable(), toggle(), isEnabled(), isAvailable()
Exemplo
A lanterna do celular, com a API @capawesome/capacitor-torch. Plugin prĂłprio do shell do app (TorchPlugin.kt).
Retorna: enable() / disable() / toggle() → Promise (rejeita CAMERA_IN_USE enquanto o fluxo da cĂąmera do prĂłprio app estĂĄ aberto, UNAVAILABLE sem flash); isEnabled() → {enabled}; isAvailable() → {available}. Requer: nada para ativar e nenhuma permissĂŁo.
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);
}
};
}Pisque um sinal de SOS a partir de um botão e desligue a luz se a câmera tomar o flash no meio:
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);
}
};Mantenha um botĂŁo de lanterna em sincronia com o sistema, jĂĄ que o usuĂĄrio pode ligar a lanterna pelo bloco de configuraçÔes rĂĄpidas enquanto o app estĂĄ em 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();Observaçþes: a luz segue o estado do sistema (desligĂĄ-la pelo bloco de configuraçÔes rĂĄpidas aparece como desligada) e Ă© apagada quando o app fecha. Enquanto um fluxo getUserMedia estiver aberto, acenda-a pela faixa: track.applyConstraints({ advanced: [{ torch: true }] }). Apps criados com IA usam torch de @/lib/appmintNative.