O que é o Capacitor e por que ele muda a forma de executar seu app
O Capacitor é a camada que conecta seu aplicativo Ionic (que é essencialmente uma aplicação web) aos recursos nativos do dispositivo (Android/iOS). Na prática, ele empacota o seu build web dentro de um WebView e oferece uma ponte (bridge) para acessar APIs nativas por meio de plugins (como câmera, geolocalização, arquivos, notificações, etc.).
Isso significa que existem dois “mundos” no projeto: (1) o código web (HTML/CSS/TypeScript) e (2) os projetos nativos gerados (Android Studio / Xcode). Você desenvolve majoritariamente no mundo web, mas precisa sincronizar o resultado do build para o mundo nativo sempre que quiser rodar no dispositivo/emulador.
Como o app web vira um app Android/iOS
Empacotamento em alto nível
- Você gera os arquivos web (bundle) do app (por exemplo, em
www/). - O Capacitor copia esses arquivos para dentro do projeto nativo (Android/iOS).
- O app nativo abre um
WebViewapontando para esses assets locais. - Quando seu código web chama um plugin, o Capacitor encaminha a chamada para o código nativo e devolve o resultado para o JavaScript.
Arquivos web vs. código nativo
Uma regra prática: alterações em páginas/estilos/lógica web exigem novo build e sincronização para refletirem no app nativo. Já alterações nativas (por exemplo, permissões, configurações de Gradle, Info.plist) são feitas diretamente dentro das pastas nativas e não “voltam” automaticamente para o código web.
Estrutura de pastas: o que observar no projeto
Ao usar Capacitor, você normalmente verá (além do código do app) estas partes importantes:
capacitor.config.ts(oucapacitor.config.json): configurações do app para o Capacitor (id, nome, diretório web, servidor, etc.).www/: saída do build web (assets que serão empacotados).android/: projeto nativo Android (Gradle, Manifest, código Java/Kotlin, resources).ios/: projeto nativo iOS (Xcode project, Info.plist, Swift/Obj-C, assets).
capacitor.config.ts: configurações essenciais
Um exemplo típico (os valores variam conforme seu app):
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
import { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { appId: 'com.seuapp.exemplo', appName: 'SeuApp', webDir: 'www', bundledWebRuntime: false }; export default config;appId: identificador único (impacta Android package e iOS bundle id).appName: nome exibido do app.webDir: pasta onde fica o build web que será copiado para nativo.
Passo a passo: adicionar e configurar Capacitor no projeto
1) Instalar dependências do Capacitor
No diretório do projeto, instale os pacotes principais:
npm i @capacitor/core @capacitor/cliEm muitos projetos Ionic modernos, isso já vem configurado. Ainda assim, é importante entender os comandos e o fluxo.
2) Inicializar o Capacitor (se necessário)
Se o projeto ainda não tiver o Capacitor inicializado, use:
npx cap initVocê informará appName e appId. Isso cria/atualiza o arquivo de configuração do Capacitor.
3) Gerar o build web antes de ir para o nativo
O Capacitor não “empacota seu código fonte”; ele empacota o resultado do build web. Então, antes de sincronizar, gere os assets:
npm run buildApós isso, verifique se a pasta www/ foi atualizada.
Comandos essenciais: add, sync e open
npx cap add: criar o projeto nativo
Use uma vez para criar as pastas nativas:
npx cap add android npx cap add ios- Cria
android/e/ouios/. - Gera arquivos base e configura o projeto para carregar os assets do
webDir.
npx cap sync: sincronizar web + plugins
Este é o comando mais usado no dia a dia quando você alterou o app web ou instalou/removou plugins:
npx cap syncO que ele faz, em geral:
- Copia os assets do
www/para os projetos nativos. - Atualiza a integração de plugins nativos (Android/iOS).
- Garante que dependências e configurações necessárias estejam aplicadas nos projetos nativos.
Você também pode sincronizar uma plataforma específica:
npx cap sync android npx cap sync iosnpx cap open: abrir no Android Studio/Xcode
Para trabalhar/rodar pelo ambiente nativo:
npx cap open android npx cap open ios- No Android Studio, você compila e executa no emulador/dispositivo.
- No Xcode, você executa no simulador/dispositivo (exige ambiente macOS).
Sincronização de assets: quando preciso rodar build e sync?
| Você mudou... | Precisa fazer | Por quê |
|---|---|---|
| HTML/CSS/TypeScript do app | npm run build + npx cap sync | O nativo usa os arquivos gerados em www/ |
| Instalou um plugin Capacitor | npx cap sync | Atualiza integração nativa do plugin |
| Somente assets estáticos (imagens) no build | npm run build + npx cap sync | Precisa recopiá-los para o nativo |
| Configuração nativa (Manifest/Info.plist) | Rebuild pelo Android Studio/Xcode | Alteração é no projeto nativo |
Dica prática: se você abriu o Android Studio/Xcode e não está vendo suas mudanças web, quase sempre faltou rodar o build e/ou o sync.
Ciclo de vida no dispositivo: o que muda em relação ao browser
WebView não é “igual ao Chrome do desktop”
No dispositivo, seu app roda dentro de um WebView. Isso afeta:
- Performance e memória: dispositivos mais modestos podem encerrar o app em background com mais frequência.
- Rede: mudanças de conectividade são comuns; trate offline/timeout.
- Permissões: recursos como câmera e localização exigem consentimento do usuário e configuração nativa.
- Eventos de app: o app pode ir para background/foreground, ser pausado e retomado.
Eventos de ciclo de vida via Capacitor
Você pode reagir a eventos do app (útil para pausar timers, salvar estado, revalidar sessão, etc.). Exemplo com App do Capacitor:
import { App } from '@capacitor/app'; App.addListener('appStateChange', ({ isActive }) => { if (isActive) { // voltou para foreground: revalidar dados, retomar tarefas } else { // foi para background: salvar estado, pausar tarefas } }); App.addListener('backButton', ({ canGoBack }) => { // Android: tratar botão voltar if (!canGoBack) { // ex.: pedir confirmação antes de sair } });Esses eventos não aparecem do mesmo jeito quando você roda apenas no navegador.
Permissões: como lidar corretamente (Android/iOS)
Dois níveis de permissão
- Permissão em tempo de execução (runtime): o app pede ao usuário quando precisa do recurso.
- Declaração nativa: Android e iOS exigem que você declare no projeto nativo quais permissões/descrições o app usa.
Se você só testar no browser, pode achar que “funciona” (ou nem conseguir testar), mas no dispositivo a permissão pode bloquear totalmente a funcionalidade.
Exemplo prático: Geolocalização
Instale o plugin:
npm i @capacitor/geolocation npx cap syncNo código, solicite e use:
import { Geolocation } from '@capacitor/geolocation'; async function obterLocalizacao() { const perm = await Geolocation.requestPermissions(); if (perm.location === 'granted' || perm.coarseLocation === 'granted') { const pos = await Geolocation.getCurrentPosition({ enableHighAccuracy: true }); console.log(pos.coords.latitude, pos.coords.longitude); } }Android (declaração): o plugin geralmente adiciona entradas necessárias, mas você deve conferir o android/app/src/main/AndroidManifest.xml (por exemplo, permissões de localização). Em versões recentes do Android, pode haver diferenças entre localização aproximada e precisa.
iOS (declaração): você precisa ter descrições no Info.plist (por exemplo, mensagens explicando por que o app usa localização). Sem isso, o app pode falhar ao solicitar permissão.
Exemplo prático: Câmera
Instale e sincronize:
npm i @capacitor/camera npx cap syncUso básico:
import { Camera, CameraResultType } from '@capacitor/camera'; async function tirarFoto() { const photo = await Camera.getPhoto({ resultType: CameraResultType.Uri, quality: 80 }); console.log(photo.webPath); }No iOS, é obrigatório ter descrições no Info.plist para câmera e, dependendo do caso, biblioteca de fotos. No Android, verifique permissões e comportamento por versão (principalmente a partir do Android 10+).
Diferenças práticas: browser vs dispositivo/emulador
1) Origem e CORS não se comportam igual
No browser, você está sujeito às regras de CORS do navegador. No dispositivo, o WebView também tem regras, mas o contexto pode mudar (por exemplo, capacitor://localhost como origem). Se uma API falha no dispositivo e funciona no browser (ou vice-versa), investigue:
- URL base e origem (scheme/host)
- HTTPS obrigatório em iOS (ATS) e políticas de rede
- Configurações de proxy/VPN no dispositivo
2) Acesso a hardware só existe no nativo
Plugins como câmera, notificações push e sensores não funcionam (ou funcionam de forma limitada) no browser. Para testar de verdade, rode no emulador/dispositivo.
3) Logs e depuração mudam
- Android: use o Logcat no Android Studio para erros nativos e
console.logdo WebView. - iOS: use o console do Xcode para logs nativos e logs do WebView.
Quando um plugin falha, o erro pode aparecer apenas no log nativo, não no console do navegador.
Fluxo de trabalho recomendado (rotina)
Rotina para testar no Android/iOS
- 1) Alterou o app web:
npm run build - 2) Atualize o nativo:
npx cap sync - 3) Abra a IDE nativa:
npx cap open androidounpx cap open ios - 4) Execute no emulador/dispositivo pela IDE
Quando usar npx cap add novamente?
Normalmente, apenas uma vez por plataforma. Depois disso, você usa sync para manter tudo atualizado.
Cuidados comuns ao trabalhar com as pastas nativas
Não edite arquivos gerados sem entender o impacto
Alguns arquivos são gerados/atualizados pelo Capacitor e por plugins. Ajustes manuais são comuns e necessários (especialmente permissões e configurações de build), mas mantenha disciplina:
- Documente mudanças nativas importantes (por exemplo, permissões extras).
- Evite apagar e recriar
android/eios/sem necessidade, pois você pode perder ajustes. - Após instalar/remover plugins, sempre rode
npx cap sync.
IDs e nomes: cuidado ao mudar depois
Alterar appId depois de já ter publicado/instalado pode causar conflitos (assinatura, pacote, bundle id). Se precisar mudar, revise também configurações no Android Studio/Xcode e considere o impacto em atualizações do app.