API da ponte JavaScript
A janela
Tela cheia, picture-in-picture, as cores das barras do sistema, bloqueio de capturas de tela, se o build tem a proteção contra cópia ativada (AppMint.copyProtection), a tela de abertura e o fechamento de uma janela.
AppMint.copyProtection helper#
AppMint.copyProtection
Exemplo
true quando o app foi criado com Proteção contra cópia ativada; ausente (undefined) caso contrário. Somente leitura - uma página não pode ligar nem desligar a proteção, apenas perguntar se está ativa.
Retorna: true, ou undefined quando a proteção está desativada (e em um navegador). Requer: Proteção contra cópia ativada na Etapa 3 (Integrar), em Opções de exibição, ao compilar. Padrão: desativado.
Com a proteção ativada, o texto do app não pode ser selecionado, copiado nem recortado; copiar / recortar, o evento contextmenu e Ctrl/Cmd + C, X e A são cancelados fora de campos editáveis; e nenhum menu de toque longo aparece. Inputs, textareas, selects e regiões contenteditable continuam totalmente editáveis, então os formulários seguem funcionando.
Oculte seus próprios botões "Copiar" quando a proteção estiver ativa - eles não copiariam nada e pareceriam quebrados:
const protectedApp = !!(window.AppMint && window.AppMint.copyProtection === true);
document.querySelectorAll('[data-copy-button]').forEach((btn) => {
btn.hidden = protectedApp;
});Ou escolha o texto de uma dica uma única vez, na inicialização:
const hint = document.getElementById('share-hint');
hint.textContent = (window.AppMint && window.AppMint.copyProtection === true)
? 'Tap Share to send this lesson to a friend.'
: 'Select any text to copy it, or tap Share.';Combine com o bloqueio de captura de tela para uma página que não deve sair do app:
if (window.AppMint && AppMint.copyProtection === true && window.WebToApk && WebToApk.setSecureScreen) {
WebToApk.setSecureScreen(true); // also blocks screenshots and recents thumbnails
document.body.classList.add('protected');
}Observações: O menu de toque longo em links e imagens (abrir, copiar, compartilhar ou baixar) é uma opção de build separada, Menu de toque longo em links e imagens, no mesmo lugar. Ele vem desativado por padrão, então um toque longo em um link não faz nada a menos que você o ative; a proteção contra cópia o mantém sempre desativado. Uma página ainda pode recusar o menu em um elemento cancelando contextmenu (el.addEventListener('contextmenu', (e) => e.preventDefault())). A proteção impede a cópia dentro do app; ela não impede uma captura de tela - para isso, veja WebToApk.setSecureScreen(true).
screen.orientation padrão web#
screen.orientation.lock(type) / unlock()
Exemplo
O bloqueio padrão de Screen Orientation, que um WebView comum recusa: gira o app para paisagem em um vídeo ou jogo e de volta.
Retorna: lock(type) → uma Promise que é resolvida quando a orientação é solicitada; é rejeitada com TypeError para um tipo desconhecido e NotSupportedError na Android TV. unlock() volta à orientação com que o app foi criado. Requer: nada.
const player = document.getElementById('player');
document.getElementById('fullscreen').addEventListener('click', async () => {
try {
await screen.orientation.lock('landscape'); // either landscape, follows the sensor
} catch (e) {
console.log('Could not rotate:', e.name);
}
player.classList.add('wide');
});
document.getElementById('done').addEventListener('click', () => {
screen.orientation.unlock();
player.classList.remove('wide');
});
screen.orientation.addEventListener('change', () => console.log(screen.orientation.type));Gire um jogo para paisagem quando ele começar; na Android TV a tela já é paisagem, então siga em frente:
async function startGame() {
try {
await screen.orientation.lock('landscape');
} catch (e) {
if (e.name !== 'NotSupportedError') console.log('Could not rotate:', e.name);
}
runGame();
}
function quitGame() {
screen.orientation.unlock(); // back to the orientation the app was built with
showMenu();
}Acompanhe o formato do vídeo em reprodução e volte quando ele terminar:
const video = document.getElementById('clip');
video.addEventListener('play', () => {
const wide = video.videoWidth >= video.videoHeight;
screen.orientation.lock(wide ? 'landscape' : 'portrait').catch((e) => console.log(e.name));
});
video.addEventListener('ended', () => screen.orientation.unlock());Observações: tipos: any, natural, portrait, portrait-primary, portrait-secondary, landscape, landscape-primary, landscape-secondary. Ao contrário do Chrome, a página não precisa estar em tela cheia antes. Apps criados com IA usam lockOrientation() de @/lib/appmintNative.
window.close padrão web#
window.close()
Exemplo
Fecha a tela principal do app. O shell substitui window.close() para que um botão "Fechar" ou "Sair" na sua página funcione dentro do app.
Retorna: nada. Requer: nada.
document.getElementById('exit-btn').onclick = function () {
saveDraft(); // anything unsaved — the screen closes at once
window.close(); // in the app: WebToApk.closeWindow(); in a browser: normal behaviour
};Oculte o botão em um navegador, onde window.close() geralmente não faz nada em uma aba aberta pelo usuário:
if (!window.WebToApk) document.getElementById('exit-btn').hidden = true;Pergunte antes, porque o app fecha no instante em que window.close() é executado:
document.getElementById('quit').addEventListener('click', function () {
if (hasUnsavedChanges() && !confirm('You have unsaved changes. Close the app anyway?')) {
return;
}
window.close();
});Observações: A substituição é instalada depois que cada página termina de carregar, então uma chamada durante a primeira execução de script da página usa o window.close() do próprio WebView (que não faz nada). Não há confirmação de saída nesse caminho. Um popup de login que chama window.close() é tratado à parte: ele fecha o popup, não o app.
__lockOrientation ponte#
window.WebToApk.__lockOrientation(type: String): String
screen.orientation.lock(type): "ok", "type" para uma string que não é um OrientationLockType, ou "unsupported" (a Android TV é sempre paisagem).
Exemplo
Transporte interno por trás de screen.orientation.lock(type). As páginas usam a API padrão; nunca chame isso diretamente - os métodos __ podem mudar sem aviso.
Retorna: 'ok', 'type' para uma string que não é um tipo de bloqueio de orientação, ou 'unsupported' (Android TV). Requer: nada para ativar.
Use a API pública:
document.getElementById('play').addEventListener('click', async () => {
try { await screen.orientation.lock('landscape'); } catch (e) { /* NotSupportedError on TV */ }
});
document.getElementById('exit').addEventListener('click', () => screen.orientation.unlock());Diferencie um tipo de bloqueio inválido de um dispositivo que não consegue girar:
async function lockTo(type) {
if (!screen.orientation || typeof screen.orientation.lock !== 'function') return 'unsupported';
try {
await screen.orientation.lock(type);
return 'ok';
} catch (e) {
if (e instanceof TypeError) return 'bad-type'; // not an OrientationLockType string
return 'unsupported'; // NotSupportedError (Android TV)
}
}
lockTo('portrait-primary').then((r) => console.log('orientation lock:', r));Congele a tela do jeito que o usuário a está segurando enquanto ele assina e depois devolva a rotação:
async function startSigning() {
const current = screen.orientation.type; // e.g. 'landscape-primary'
try { await screen.orientation.lock(current); } catch (e) { /* keep going unlocked */ }
showSignaturePad();
}
function finishSigning() {
hideSignaturePad();
screen.orientation.unlock();
}Observações: Implementado no shell do app (WebApiPolyfills.kt). O mesmo código de página funciona sem alterações no Chrome.
__unlockOrientation ponte#
window.WebToApk.__unlockOrientation()
screen.orientation.unlock(): volta para a orientação com que o criador criou o app.
Exemplo
Transporte interno por trás de screen.orientation.unlock(). As páginas usam a API padrão; nunca chame isso diretamente - os métodos __ podem mudar sem aviso.
Retorna: nada; o app volta à orientação escolhida na compilação. Requer: nada para ativar.
Use a API pública:
document.getElementById('play').addEventListener('click', async () => {
try { await screen.orientation.lock('landscape'); } catch (e) { /* NotSupportedError on TV */ }
});
document.getElementById('exit').addEventListener('click', () => screen.orientation.unlock());Somente a rota do jogo é paisagem; todas as outras rotas voltam à orientação do próprio app:
function onRouteChange(path) {
if (path.startsWith('/play')) {
screen.orientation.lock('landscape').catch(() => {});
} else if (screen.orientation && typeof screen.orientation.unlock === 'function') {
screen.orientation.unlock(); // menus, settings and the store
}
}
window.addEventListener('popstate', () => onRouteChange(location.pathname));
onRouteChange(location.pathname);Mantenha os slides de introdução na vertical e depois desbloqueie quando terminarem:
async function showOnboarding() {
try { await screen.orientation.lock('portrait'); } catch (e) { /* TV: no lock */ }
await runOnboardingSlides(); // your own flow
screen.orientation.unlock(); // back to the orientation the app was built with
}Observações: Implementado no shell do app (WebApiPolyfills.kt). O mesmo código de página funciona sem alterações no Chrome.
__wakeLock ponte#
window.WebToApk.__wakeLock(docId: String, held: Boolean): Boolean
Screen Wake Lock: [held] true mantém a tela ligada enquanto o documento [docId] mantém um sentinel. Retorna false quando o bloqueio não pôde ser obtido.
Exemplo
Transporte interno por trás de navigator.wakeLock.request('screen') e WakeLockSentinel.release(). As páginas usam a API padrão; nunca chame isto diretamente - os métodos __ podem mudar sem aviso.
Retorna: true quando o sinalizador de tela ligada foi aplicado a esse documento. Requer: nada para ativar.
Use a API pública:
let lock = null;
async function keepScreenOn() {
if (!('wakeLock' in navigator)) return;
lock = await navigator.wakeLock.request('screen');
lock.addEventListener('release', () => { lock = null; });
}Retome o bloqueio quando o usuário voltar ao app, porque todos os bloqueios são soltos em segundo plano:
let lock = null;
let wantLock = false;
async function acquire() {
if (!('wakeLock' in navigator)) return;
try {
lock = await navigator.wakeLock.request('screen');
lock.addEventListener('release', () => { lock = null; });
} catch (e) {
lock = null; // NotAllowedError: the page was not visible
}
}
function startRecipeMode() { wantLock = true; acquire(); }
function stopRecipeMode() { wantLock = false; if (lock) lock.release(); }
document.addEventListener('visibilitychange', () => {
if (wantLock && !lock && document.visibilityState === 'visible') acquire();
});Mantenha a tela ligada somente enquanto um cronômetro de treino roda, e deixe-a dormir de novo quando ele termina:
async function runTimer(seconds) {
const lock = ('wakeLock' in navigator)
? await navigator.wakeLock.request('screen').catch(() => null)
: null;
try {
for (let left = seconds; left > 0; left--) {
showRemaining(left);
await new Promise((r) => setTimeout(r, 1000));
}
} finally {
if (lock && !lock.released) await lock.release();
}
}Observações: O app solta todos os bloqueios quando vai para segundo plano e dispara appmint:wakelock-lost, que libera os sentinels (o evento release deles é disparado).
closeWindow ponte#
window.WebToApk.closeWindow()
Use o wrapper de promessa: const r = await AppMint.requestReview(); // {result, openedStore} const r = await AppMint.requestReview({ openStore: true }); // página da loja se não houver janela r.result: 'shown' | 'not_from_play' | 'quota' | 'error'. Veja RatePrompt.
Descrito pelo seu grupo, Janela de avaliação no app do Google Play, e não isoladamente.
Exemplo
Fecha a tela principal do app (o mesmo que pressionar Voltar na última página). As páginas normalmente chamam o padrão window.close(), que o shell redireciona para cá.
Retorna: nada. Requer: nada.
document.getElementById('quit').onclick = function () {
if (confirm('Close the app?')) window.close(); // in the app: the screen closes
};A chamada bruta faz a mesma coisa:
if (window.WebToApk && typeof window.WebToApk.closeWindow === 'function') {
window.WebToApk.closeWindow();
}Um botão "Sair" que salva antes, e fica oculto em um navegador, onde não há tela de app para fechar:
var exitBtn = document.getElementById('exit-btn');
if (!(window.WebToApk && typeof window.WebToApk.closeWindow === 'function')) {
exitBtn.hidden = true;
} else {
exitBtn.onclick = async function () {
exitBtn.disabled = true;
await saveDraft(); // your own save; closing does not wait for anything
window.WebToApk.closeWindow();
};
}Observações: Ela encerra a tela do app de imediato - sem confirmação de saída, mesmo que o build tenha uma. Salve antes o que não foi salvo. Em um navegador, window.close() só fecha uma aba que o próprio script abriu.
enterPip ponte#
window.WebToApk.enterPip(): Boolean
Reduz o app inteiro a uma janela flutuante de picture-in-picture agora mesmo - um vídeo ou uma chamada que o usuário quer continuar assistindo enquanto sai. Android 8+ e somente quando o build ativou o PiP (o sinalizador de manifesto de que precisa); retorna se a janela abriu. Sair do app com o PiP ativado já faz isso sozinho; este é o botão explícito de "minimizar".
Exemplo
Reduz o app inteiro a uma pequena janela flutuante de picture-in-picture agora mesmo - um botão "minimizar" para um vídeo ou uma chamada.
Retorna: true se a janela flutuante abriu, false caso contrário (de forma síncrona). Requer: Picture-in-Picture (PiP) ativado na Etapa 3 (Integrar), em Opções de exibição, ao compilar. Android 8+.
var pipBtn = document.getElementById('pip-btn');
pipBtn.onclick = function () {
if (!(window.WebToApk && typeof window.WebToApk.enterPip === 'function')) return;
var ok = window.WebToApk.enterPip();
if (!ok) pipBtn.hidden = true; // PiP not enabled in this build, or Android 7 and older
};Adapte a página à janela pequena: a janela fica muito estreita, então um listener de resize pode ocultar tudo exceto o vídeo.
window.addEventListener('resize', function () {
var small = window.innerWidth < 300;
document.querySelector('nav').style.display = small ? 'none' : '';
});Acompanhe a abertura e o fechamento da janela flutuante com o evento appmint:pip (detail.inPip), por exemplo para ocultar os controles de uma chamada:
window.addEventListener('appmint:pip', function (e) {
var inPip = !!(e.detail && e.detail.inPip);
document.body.classList.toggle('pip', inPip); // CSS: .pip .call-controls { display: none; }
if (!inPip) {
document.getElementById('chat-panel').hidden = false; // back to the full-size screen
}
});
document.getElementById('minimise').onclick = function () {
if (window.WebToApk && typeof window.WebToApk.enterPip === 'function') {
document.getElementById('chat-panel').hidden = true;
window.WebToApk.enterPip();
}
};Observações: Com o PiP ativado, pressionar Início já entra na janela flutuante sozinho; este método serve apenas para um botão explícito. Retorna false em um build sem a opção de PiP, porque falta o sinalizador de manifesto de que ele precisa. O tamanho da janela PiP é escolhido pelo Android. Apps criados com IA podem usar pip de @/lib/appmintNative.
isFullscreen ponte#
window.WebToApk.isFullscreen(): Boolean
Permite que a página oculte a barra de status (relógio/bateria) e a barra de navegação por conta própria - por exemplo, um jogo entrando na tela de jogo: WebToApk.setFullscreen(true) // oculta as barras do sistema WebToApk.setFullscreen(false) // traz de volta WebToApk.toggleFullscreen() WebToApk.isFullscreen() A escolha é lembrada entre as aberturas. Não tem efeito em apps que o criador já travou em tela cheia/quiosque - não há para onde voltar. O item "Tela cheia" do menu lateral é o equivalente para os usuários finais e depende da opção enableFullscreenToggle do criador; esta ponte está sempre disponível para a página do próprio app.
Descrito pelo seu grupo, Ponte de tela cheia, e não isoladamente.
Exemplo
Informa se a barra de status e a de navegação do Android estão ocultas agora.
Retorna: true / false, de forma síncrona. Requer: nada.
function barsHidden() {
if (window.WebToApk && typeof window.WebToApk.isFullscreen === 'function') {
return window.WebToApk.isFullscreen();
}
return false; // in a browser
}
if (barsHidden()) {
document.getElementById('fs-btn').textContent = 'Exit fullscreen';
}Monte a página para a escolha lembrada ao iniciar, já que ela sobrevive às reinicializações:
document.addEventListener('DOMContentLoaded', function () {
var hidden = !!(window.WebToApk && typeof window.WebToApk.isFullscreen === 'function' &&
window.WebToApk.isFullscreen());
document.documentElement.classList.toggle('bars-hidden', hidden);
// CSS: .bars-hidden header { padding-top: env(safe-area-inset-top); }
});Coloque um botão "mostrar barras" quando o app foi criado em tela cheia e as barras não podem voltar:
function showBars() {
var W = window.WebToApk;
if (!(W && typeof W.isFullscreen === 'function')) return;
W.setFullscreen(false);
setTimeout(function () { // the change is applied on the UI thread
if (W.isFullscreen()) {
document.getElementById('bars-btn').hidden = true;
}
}, 100);
}Observações: Retorna true quando o criador criou o app com Tela cheia ou Modo Quiosque Imersivo, OU quando a página chamou setFullscreen(true) / toggleFullscreen(). No primeiro caso, setFullscreen(false) não consegue trazer as barras de volta.
isSecureScreen ponte#
window.WebToApk.isSecureScreen(): Boolean
WebToApk.setSecureScreen(true) // bloqueia capturas de tela NESTA página WebToApk.setSecureScreen(false) // libera antes do tempo WebToApk.isSecureScreen() // -> boolean A proteção pertence à página que a pediu. Ela é liberada no instante em que o app navega para qualquer outro lugar - um novo documento, uma rota pushState, uma rota #hash - de modo que uma tela protegida não deixa o resto do app bloqueado, e uma página que queira a proteção de volta após recarregar simplesmente pede de novo. O que ela faz: capturas de tela, gravação de tela, transmissão e a miniatura na tela de recentes são todas bloqueadas enquanto está ativa. O que ela não faz: impedir uma câmera apontada para a tela. Nada no Android consegue, e nenhuma ponte aqui vai fingir o contrário.
Descrito pelo seu grupo, Proteção contra captura de tela, e não isoladamente.
Exemplo
Informa se a proteção contra capturas de tela (setSecureScreen) está ativa agora.
Retorna: um boolean, imediatamente. Requer: nada.
function updateLockIcon() {
var on = !!window.WebToApk &&
typeof window.WebToApk.isSecureScreen === 'function' &&
window.WebToApk.isSecureScreen();
document.getElementById('shield').hidden = !on;
}Verifique antes de mostrar o número de um cartão e ative a proteção primeiro, se esta página ainda não a pediu:
function revealCardNumber(full) {
var W = window.WebToApk;
if (W && typeof W.isSecureScreen === 'function' && !W.isSecureScreen()) {
W.setSecureScreen(true); // the new state is committed when this returns
}
document.getElementById('card-number').textContent = full;
}Um interruptor "Ocultar das capturas de tela" que parte do estado real e o inverte:
var toggle = document.getElementById('privacy-toggle');
var W = window.WebToApk;
if (!W || typeof W.isSecureScreen !== 'function') {
toggle.hidden = true;
} else {
toggle.checked = W.isSecureScreen();
toggle.addEventListener('change', function () {
toggle.checked = W.setSecureScreen(!W.isSecureScreen());
});
}Observações: Ela volta para false sozinha quando o app navega para outra página ou rota, porque a proteção pertence à página que a pediu.
setFullscreen ponte#
window.WebToApk.setFullscreen(enabled: Boolean)
Permite que a página oculte a barra de status (relógio/bateria) e a barra de navegação por conta própria - por exemplo, um jogo entrando na tela de jogo: WebToApk.setFullscreen(true) // oculta as barras do sistema WebToApk.setFullscreen(false) // traz de volta WebToApk.toggleFullscreen() WebToApk.isFullscreen() A escolha é lembrada entre as aberturas. Não tem efeito em apps que o criador já travou em tela cheia/quiosque - não há para onde voltar. O item "Tela cheia" do menu lateral é o equivalente para os usuários finais e depende da opção enableFullscreenToggle do criador; esta ponte está sempre disponível para a página do próprio app.
Descrito pelo seu grupo, Ponte de tela cheia, e não isoladamente.
Exemplo
Oculta (true) ou mostra (false) a barra de status e a barra de navegação do Android, por exemplo quando um jogo entra na tela de jogo.
Retorna: nada. Requer: nada - está sempre disponível para a sua página. A escolha é lembrada entre as aberturas.
function enterPlayScreen() {
if (window.WebToApk && typeof window.WebToApk.setFullscreen === 'function') {
window.WebToApk.setFullscreen(true); // hide clock/battery and the nav bar
}
}
function leavePlayScreen() {
if (window.WebToApk && window.WebToApk.setFullscreen) {
window.WebToApk.setFullscreen(false); // bring the bars back
}
}Mantenha seu conteúdo fora de baixo do recorte da câmera quando as barras estiverem ocultas:
document.body.style.paddingTop = 'env(safe-area-inset-top)';
document.body.style.paddingBottom = 'env(safe-area-inset-bottom)';Oculte as barras enquanto um vídeo toca e traga-as de volta quando ele pausar ou terminar:
var video = document.getElementById('movie');
function hideBars(hidden) {
if (window.WebToApk && typeof window.WebToApk.setFullscreen === 'function') {
window.WebToApk.setFullscreen(hidden);
}
}
video.addEventListener('play', function () { hideBars(true); });
video.addEventListener('pause', function () { hideBars(false); });
video.addEventListener('ended', function () { hideBars(false); });Observações: Não faz nada em um app criado com Tela cheia (ou Modo Quiosque Imersivo) ativado na Etapa 3 (Integrar) - o criador travou essa escolha. Ela só oculta as barras do Android; a barra superior do próprio app (a que tem o botão do menu lateral) é o interruptor Mostrar barra superior. Quando ativada, o shell adiciona viewport-fit=cover à meta viewport para que a página ocupe a tela inteira. Veja toggleFullscreen e isFullscreen. Apps criados com IA podem usar fullscreen de @/lib/appmintNative.
setSecureScreen ponte#
window.WebToApk.setSecureScreen(enabled: Boolean): Boolean
Define a proteção para a página ATUAL e retorna o estado agora em vigor. O sinalizador da janela em si é aplicado na thread de interface, mas o estado retornado já está confirmado, então uma página pode chamar isto e revelar de imediato seu conteúdo sensível sem esperar por um callback.
Exemplo
Bloqueia capturas de tela, gravação de tela, transmissão e a prévia na tela de recentes enquanto a página ATUAL mostra algo privado.
Retorna: um boolean imediatamente - o estado agora em vigor (o valor que você passou). Você pode revelar o conteúdo privado logo após a chamada. Requer: nada.
function showStatement() {
if (window.WebToApk && typeof window.WebToApk.setSecureScreen === 'function') {
window.WebToApk.setSecureScreen(true);
}
render(statementView);
}Libere você mesmo somente quando ocultar o conteúdo privado SEM navegar (um modal fecha, uma aba muda dentro de uma página):
function closeCardDetails() {
hide(cardDetailsModal);
if (window.WebToApk && typeof window.WebToApk.setSecureScreen === 'function') {
window.WebToApk.setSecureScreen(false);
}
}Mostre um código de recuperação de uso único somente depois que a captura estiver bloqueada, já que a chamada responde com o estado em vigor:
function revealRecoveryCode(code) {
var W = window.WebToApk;
if (!(W && typeof W.setSecureScreen === 'function')) {
alert('Open the app to see your recovery code.');
return;
}
if (W.setSecureScreen(true)) {
document.getElementById('recovery-code').textContent = code;
}
}Observações: A proteção pertence à página que a pediu. Ela é liberada assim que o app navega para qualquer outro lugar - uma nova página, uma rota pushState ou uma rota #hash - então não há nada a limpar na saída, e após um recarregamento a página precisa pedir de novo. Não a reaplique em um temporizador: o sinalizador já deve estar ativo quando o usuário pressionar os botões de captura de tela. Nada consegue impedir uma câmera apontada para a tela.
setStatusBarColor ponte#
window.WebToApk.setStatusBarColor(color: String, style: String): Boolean
Pinta a barra de status e a de navegação com [color] e escolhe a cor dos ícones: [style] 'light' significa ícones claros em barra escura, 'dark' o inverso, '' deixa a luminância decidir. [color] é `#RGB`, `#RGBA`, `#RRGGBB`, `#AARRGGBB` (alfa PRIMEIRO - a ordem `#RRGGBBAA` do CSS também é lida como alfa primeiro) ou um nome de cor básico ('black', 'navy'…); `rgb()`/`hsl()` não são lidos. Retorna false quando a cor não é interpretada.
Exemplo
Pinta a barra de status do Android com uma cor e escolhe ícones claros ou escuros nela.
Retorna: true, ou false quando a cor não pode ser interpretada (de forma síncrona). Requer: nada.
style é 'light' (ícones claros, para uma barra escura), 'dark' (ícones escuros, para uma barra clara), ou '' (o shell escolhe pelo brilho da cor):
function paintBar(color, style) {
if (window.WebToApk && typeof window.WebToApk.setStatusBarColor === 'function') {
return window.WebToApk.setStatusBarColor(color, style);
}
return false; // in a browser
}
paintBar('#0B0F1A', 'light'); // dark bar, light icons
paintBar('#FFFFFF', 'dark'); // white bar, dark icons
paintBar('#0E7C86', ''); // icons chosen automaticallyCombine a barra com cada tela:
function showScreen(name) {
var colors = { home: '#0B0F1A', settings: '#FFFFFF' };
paintBar(colors[name] || '#0B0F1A', name === 'settings' ? 'dark' : 'light');
}Acompanhe o tema claro ou escuro do celular, inclusive uma troca enquanto o app está aberto:
var darkTheme = window.matchMedia('(prefers-color-scheme: dark)');
function matchTheme() {
if (!(window.WebToApk && typeof window.WebToApk.setStatusBarColor === 'function')) return;
if (darkTheme.matches) {
window.WebToApk.setStatusBarColor('#121212', 'light');
} else {
window.WebToApk.setStatusBarColor('#F5F5F5', 'dark');
}
}
matchTheme();
darkTheme.addEventListener('change', matchTheme);Observações: As cores são strings de cor do Android: #RRGGBB ou #AARRGGBB (e nomes como red). Formas CSS como rgb(...) ou #RGB retornam false. Funciona também no Android 15+, onde o plugin StatusBar do Capacitor não consegue pintar a barra. Enquanto as barras estão ocultas (tela cheia), a cor é guardada para quando elas voltarem. Apps criados com IA podem usar setStatusBar de @/lib/appmintNative.
splashHold ponte#
window.WebToApk.splashHold()
Mantém a tela de abertura de marca visível até [splashReady] ser chamado. Por padrão, a tela de abertura some assim que o corpo da página tem elementos já posicionados, o que, para um app que desenha um esqueleto e depois busca a primeira tela, significa "abertura e depois um esqueleto". Um app que prefira revelar uma primeira tela pronta chama isto na importação e [splashReady] quando essa tela estiver no ar. Limitado à mesma salvaguarda de 6s da verificação de desenho, então uma página que nunca informa estar pronta ainda abre.
Exemplo
Mantém a tela de abertura do app visível até você chamar splashReady() - assim o usuário vê sua primeira tela pronta, e não "abertura e depois um esqueleto de carregamento".
Retorna: nada. Requer: nada.
Chame o mais cedo possível (no topo do seu primeiro script) e depois chame splashReady() quando a primeira tela estiver desenhada:
if (window.WebToApk && typeof window.WebToApk.splashHold === 'function') {
window.WebToApk.splashHold();
}
loadFirstScreen() // your own async start-up (fetch data, render)
.catch(function (err) { showError(err); })
.then(function () {
if (window.WebToApk && window.WebToApk.splashReady) window.WebToApk.splashReady();
});Segure a tela de abertura até que a imagem principal da primeira tela tenha carregado, para que o app abra em uma imagem pronta:
if (window.WebToApk && typeof window.WebToApk.splashHold === 'function') {
window.WebToApk.splashHold();
}
function releaseSplash() {
if (window.WebToApk && window.WebToApk.splashReady) window.WebToApk.splashReady();
}
var hero = document.getElementById('hero');
if (hero.complete) {
releaseSplash();
} else {
hero.addEventListener('load', releaseSplash);
hero.addEventListener('error', releaseSplash); // a broken image must not keep the splash up
}Segure a tela de abertura somente quando a primeira tela precisar de dados, e deixe uma tela que se desenha de imediato abrir normalmente:
var signedIn = !!localStorage.getItem('session');
if (signedIn && window.WebToApk && typeof window.WebToApk.splashHold === 'function') {
window.WebToApk.splashHold(); // the dashboard needs its data before it looks right
}
if (signedIn) {
loadDashboard().finally(function () {
if (window.WebToApk && window.WebToApk.splashReady) window.WebToApk.splashReady();
});
} else {
showLoginScreen(); // paints at once; the splash hides by itself
}Observações: Sem splashHold(), a tela de abertura some assim que o corpo da página tem elementos visíveis. Uma tela de abertura retida ainda some sozinha após alguns segundos (a mesma salvaguarda da verificação normal de desenho), então uma página que nunca chama splashReady() ainda abre. Chame splashReady() também no caminho de erro. O tempo mínimo de abertura do criador continua valendo. Apps criados com IA podem usar splash de @/lib/appmintNative.
splashReady ponte#
window.WebToApk.splashReady()
A primeira tela está no ar - oculte a tela de abertura agora (sujeito à duração mínima de abertura do criador). Idempotente; inofensivo quando nada estava retido.
Exemplo
Informa ao shell que sua primeira tela está pronta, para que a tela de abertura some agora.
Retorna: nada. Requer: nada. Seguro de chamar mais de uma vez, e inofensivo quando nada estava retido.
Combina com splashHold():
if (window.WebToApk && window.WebToApk.splashHold) window.WebToApk.splashHold();
async function start() {
try {
var res = await fetch('/api/today');
renderToday(await res.json());
} catch (e) {
renderOfflineMessage();
} finally {
if (window.WebToApk && typeof window.WebToApk.splashReady === 'function') {
window.WebToApk.splashReady(); // hide the splash in every case
}
}
}
start();Revele a tela somente depois que o navegador desenhou o que você acabou de renderizar (dois quadros de animação):
renderApp(document.getElementById('root'));
requestAnimationFrame(function () {
requestAnimationFrame(function () {
if (window.WebToApk && typeof window.WebToApk.splashReady === 'function') {
window.WebToApk.splashReady();
}
});
});Espere várias tarefas de inicialização e oculte a tela de abertura mesmo que uma delas falhe:
if (window.WebToApk && window.WebToApk.splashHold) window.WebToApk.splashHold();
Promise.allSettled([
loadProfile(), // your own start-up requests
loadFeed(),
document.fonts.ready // no flash of the wrong font
]).then(function (results) {
results.forEach(function (r) { if (r.status === 'rejected') console.warn(r.reason); });
if (window.WebToApk && typeof window.WebToApk.splashReady === 'function') {
window.WebToApk.splashReady();
}
});Observações: A duração mínima da tela de abertura do criador continua sendo respeitada. Se você nunca chamar splashHold(), a tela de abertura some sozinha quando a página é desenhada, e splashReady() não faz nada a mais.
toggleFullscreen ponte#
window.WebToApk.toggleFullscreen()
Permite que a página oculte a barra de status (relógio/bateria) e a barra de navegação por conta própria - por exemplo, um jogo entrando na tela de jogo: WebToApk.setFullscreen(true) // oculta as barras do sistema WebToApk.setFullscreen(false) // traz de volta WebToApk.toggleFullscreen() WebToApk.isFullscreen() A escolha é lembrada entre as aberturas. Não tem efeito em apps que o criador já travou em tela cheia/quiosque - não há para onde voltar. O item "Tela cheia" do menu lateral é o equivalente para os usuários finais e depende da opção enableFullscreenToggle do criador; esta ponte está sempre disponível para a página do próprio app.
Descrito pelo seu grupo, Ponte de tela cheia, e não isoladamente.
Exemplo
Alterna a barra de status e a de navegação do Android entre ocultas e visíveis.
Retorna: nada. Requer: nada. O novo estado é lembrado entre as aberturas.
Um botão de "tela cheia" que também atualiza o próprio rótulo:
var btn = document.getElementById('fs-btn');
if (window.WebToApk && typeof window.WebToApk.toggleFullscreen === 'function') {
btn.onclick = function () {
window.WebToApk.toggleFullscreen();
// The change is applied on the UI thread; read the state a moment later.
setTimeout(function () {
btn.textContent = window.WebToApk.isFullscreen() ? 'Exit fullscreen' : 'Fullscreen';
}, 100);
};
} else {
btn.hidden = true; // in a browser
}Toque duas vezes em uma foto ou em uma tela de leitura para ocultar ou mostrar as barras:
var viewer = document.getElementById('photo-viewer');
viewer.addEventListener('dblclick', function () {
if (window.WebToApk && typeof window.WebToApk.toggleFullscreen === 'function') {
window.WebToApk.toggleFullscreen();
}
});Alterne com a tecla F em um teclado físico, mas não enquanto o usuário digita em um campo:
document.addEventListener('keydown', function (e) {
if (e.key !== 'f' || e.target.closest('input, textarea, [contenteditable]')) return;
if (window.WebToApk && typeof window.WebToApk.toggleFullscreen === 'function') {
e.preventDefault();
window.WebToApk.toggleFullscreen();
}
});Observações: Não faz nada em um app criado com Tela cheia ou Modo Quiosque Imersivo ativado (as barras ficam ocultas). O item "Tela cheia" do menu lateral para os usuários finais é uma opção de build separada (Botão de tela cheia na Etapa 3, em Opções de exibição); este método da ponte funciona sem ela.