Recursos do dispositivo
Web APIs Bridge
Polyfills nativos para notificações, compartilhamento, área de transferência e mais
1O que são as Web API Bridges?#
O WebView do Android não aceita várias APIs web modernas que o Chrome aceita. O app gerado cria polyfills dessas APIs automaticamente, para os sites funcionarem como no Chrome:
✅ Notificações da Web (Notification API)
✅ Web Share (navigator.share)
✅ Área de transferência (navigator.clipboard)
✅ window.close()
✅ links target="_blank" e window.open()
Sem configuração - isso funciona automaticamente em todo app gerado.
2Notificações da Web#
Sites que usam Notification.requestPermission() e new Notification() vão mostrar notificações reais do Android.
- No Android 13+, o usuário recebe uma caixa de permissão do sistema
- No Android 12 e anteriores, as notificações são permitidas por padrão
- Tocar em uma notificação abre o app
- A opção 'tag' substitui notificações anteriores (conforme a especificação Web)
// Your website JS — works the same as in Chrome:
Notification.requestPermission().then(function(result) {
if (result === 'granted') {
new Notification('Hello!', {
body: 'This is a native Android notification',
tag: 'my-notif'
});
}
});3Web Share API#
navigator.share() abre a tela de compartilhamento nativa do Android, permitindo compartilhar conteúdo com WhatsApp, Telegram, e-mail etc.
- Aceita title, text e url
- navigator.canShare() retorna true
- Funciona exatamente como a caixa de compartilhamento do Chrome
// Share content from your website:
navigator.share({
title: 'Check this out',
text: 'Amazing content!',
url: 'https://example.com/page'
});4Clipboard API#
navigator.clipboard.writeText() e readText() são conectados à área de transferência nativa do Android.
- writeText() copia o texto para a área de transferência do sistema
- readText() lê da área de transferência do sistema
- Ambos retornam Promises (conforme a especificação Web)
// Copy to clipboard:
await navigator.clipboard.writeText('Hello World');
// Read from clipboard:
const text = await navigator.clipboard.readText();5window.close() e target="_blank"#
Duas falhas comuns do WebView também são corrigidas:
- window.close() - fecha/encerra a activity do app (útil para páginas de retorno de pagamento/autenticação)
- links target="_blank" - carregam dentro do WebView em vez de serem descartados em silêncio
- chamadas window.open() - tratadas da mesma forma
Não precisa alterar o site - isso simplesmente funciona.
6Correspondência de domínios em links externos#
Quando 'External Links → Open in Browser' está definido, o app compara os domínios de forma inteligente:
- google.com e www.google.com são tratados como o mesmo domínio
- Somente domínios realmente diferentes abrem no Chrome
- Redirecionamentos dentro do mesmo site permanecem no WebView
Isso evita o problema de um site como google.com redirecionar para www.google.com e abrir no Chrome por engano.
7UPI e links de apps de pagamento (Razorpay, GPay, PhonePe, Paytm)#
Qualquer link cujo esquema não seja uma página web abre automaticamente o app Android responsável - sem configuração, sem lista de esquemas para ajustar:
- upi://pay - intent UPI genérico (o usuário escolhe o app UPI)
- paytmmp:// (Paytm), phonepe://, tez:// (Google Pay), gpay://
- tel:, mailto:, sms:, whatsapp://, tg://, intent://
Funciona em qualquer lugar em que uma página possa navegar:
✅ Um link <a href="upi://pay?..."> tocado
✅ Um redirecionamento JS (window.location.href = 'upi://...')
✅ Um popup - window.open('paytmmp://...') - que é como o Razorpay Checkout repassa para os apps UPI
Assim as páginas de checkout do Razorpay / Cashfree / PhonePe funcionam sem alterações: o cliente toca em uma opção UPI, o app de pagamento abre, ele aprova e o handler de sucesso da sua página dispara quando ele volta. Se nenhum app do celular souber tratar o esquema, o usuário vê um aviso claro em vez de uma página de erro em branco.
⚠️ Vendendo bens DIGITAIS em um app da Play Store? O Google exige o Play Billing para isso - use o guia de compras no app. O checkout com UPI/cartão serve para bens físicos, serviços e apps distribuídos fora da Play.
<!-- Simplest form — a plain UPI intent link. The user's phone
shows every installed UPI app (GPay/PhonePe/Paytm/BHIM): -->
<a href="upi://pay?pa=merchant@bank&pn=MyStore&am=99.00&cu=INR&tn=Order%20123">
Pay ₹99 via UPI
</a>8Exemplo completo - Razorpay Checkout com UPI, de ponta a ponta#
Um fluxo completo, pronto para copiar, usando o Razorpay Checkout. O que acontece no celular:
- O cliente toca em 'Pay ₹499' → o Razorpay Checkout abre na página
- O cliente escolhe UPI → o app UPI dele abre automaticamente (esse é o repasse paytmmp:// / phonepe:// que o app faz por você)
- O cliente aprova no app UPI e volta - o Android traz seu app de volta sozinho
- A função handler dispara com um ID de pagamento → mostre sua tela de sucesso
- dismiss dispara se ele cancelar → deixe-o tentar de novo
Troque rzp_test_XXXXXXXX pela sua chave de dashboard.razorpay.com. Teste primeiro com uma chave key_test - o modo de teste do Razorpay simula a aprovação do UPI.
⚠️ Em uma loja de verdade, confirme o pagamento no servidor (webhook do Razorpay ou Orders API + verificação de assinatura) antes de enviar produtos - o handler no navegador sozinho pode ser falsificado.
<!doctype html>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://checkout.razorpay.com/v1/checkout.js"></script>
<h2>Premium Plan — ₹499</h2>
<button id="payBtn">Pay ₹499</button>
<p id="result"></p>
<script>
document.getElementById('payBtn').onclick = function () {
var rzp = new Razorpay({
key: 'rzp_test_XXXXXXXX', // your Razorpay Key ID
amount: 49900, // paise — ₹499.00
currency: 'INR',
name: 'My Store',
description: 'Premium Plan',
prefill: { contact: '', email: '' },
theme: { color: '#2563eb' },
// Fires after the customer returns from their UPI app
handler: function (response) {
document.getElementById('result').textContent =
'✅ Paid! Payment ID: ' + response.razorpay_payment_id;
// Real store: send response.razorpay_payment_id to your
// server / webhook flow and verify before unlocking anything.
},
modal: {
ondismiss: function () {
document.getElementById('result').textContent =
'Payment cancelled — tap Pay to try again.';
}
}
});
rzp.open();
};
</script>