Todos os artigos
mobiledeep linksiOSAndroid

Testes de deep links móveis com um túnel localhost

Universal Links no iOS e App Links no Android exigem ambos um arquivo JSON servido por HTTPS na raiz do seu domínio. O iOS quer /.well-known/apple-app-site-association. O Android quer /.well-known/assetlinks.json. O localhost não consegue servir nenhum sobre um hostname que um SO associe ao seu app. Então tunelizamos.

O requisito real em cada plataforma

iOS Universal Links

O SO busca https://seu-dominio.com/.well-known/apple-app-site-association (ou /apple-app-site-association) quando seu app é instalado. Compara o conteúdo com o entitlement de domínios associados do seu app. A busca precisa ter sucesso sobre HTTPS real. O iOS não confia em certificados autoassinados para isso, nem no localhost.

Android App Links

O Android verifica os App Links buscando https://seu-dominio.com/.well-known/assetlinks.json. O arquivo precisa listar as fingerprints SHA-256 do seu app. A verificação acontece na instalação e no primeiro lançamento. A mesma restrição: HTTPS real, domínio real.

Por que o localhost não consegue fazer isso diretamente

Mesmo com o mkcert te dando HTTPS confiável no navegador do seu laptop, o SO móvel não confia na sua CA local. E o domínio no seu apple-app-site-association tem que bater com o domínio associado no entitlement do app — que é um domínio real resolúvel por DNS, não localhost.

Alguns times contornam isso com um domínio de staging dedicado. Funciona, mas o ciclo de iteração é lento. Um túnel localhost te dá uma URL HTTPS real num subdomínio real que os dispositivos móveis alcançam sem reclamar.

Como conectar

  1. Sirva seu apple-app-site-association e assetlinks.json do seu servidor de desenvolvimento local em /.well-known/. Ambos os arquivos. Ambas as rotas.
  2. Rode npx portpreview 3000 (ou a porta que seu servidor de desenvolvimento usa).
  3. Anote o hostname do túnel — algo como abc123.portpreview.dev.
  4. No entitlement de domínios associados do seu app iOS, adicione applinks:abc123.portpreview.dev. No intent filter do Android, adicione o mesmo host.
  5. Compile e instale o app num dispositivo real (simuladores têm comportamento estranho com Universal Links).
  6. Abra a URL a partir de outro app — Notas, Mail, um QR code — e veja-a rotear para o seu app instalado em vez do navegador.

O porém de tunelizar para deep links: o hostname do túnel muda entre sessões a menos que você tenha um subdomínio reservado. Cada rotação significa recompilar o app com a nova entrada de domínio associado. Se você itera no comportamento de deep links com frequência, consiga um subdomínio reservado.

O content-type importa para o apple-app-site-association

O iOS espera o arquivo sem extensão e com content-type application/json (iOS mais novo) ou application/pkcs7-mime (formato antigo, assinado). Quase todos os apps modernos usam a variante JSON simples. Garanta que seu servidor de desenvolvimento retorne o content-type certo ou o iOS rejeita o arquivo em silêncio sem erro útil.

Teste primeiro de um navegador desktop: abra https://seu-tunel.portpreview.dev/.well-known/apple-app-site-association e confirme que o JSON renderiza e o cabeçalho content-type nas dev tools está certo. Se estiver errado, corrija antes de caçar bugs de Universal Link no simulador.

As outras armadilhas de depuração de deep links

Incompatibilidade de entitlement do app

Se seu entitlement de domínios associados diz applinks:abc.portpreview.dev mas seu apple-app-site-association lista def.portpreview.dev, o iOS não busca. O hostname precisa ser consistente.

Universal Link de dentro do Safari

Tocar um Universal Link dentro do Safari (o mesmo app onde a aba está) às vezes abre no Safari em vez do app. Isso é por design — o iOS evita o truque de "abrir o app sempre que o usuário clica num link". Teste a partir das Notas ou do Mail.

Android App Links e digital asset links

O Android também suporta esquemas de URL personalizados (seuapp://caminho), que não precisam de HTTPS nem de assetlinks.json. São mais fáceis de testar mas menos seguros — qualquer app pode registrar o mesmo esquema. Para deep linking com qualidade de produção, os App Links são a resposta.

O fluxo de testes móveis que usamos

Para um projeto que entrega iOS e Android com deep links:

  1. Inicie o backend servindo os arquivos .well-known.
  2. Tunelize-o com npx portpreview 3000.
  3. Quando a URL do túnel estiver estável para a sessão (ou use um subdomínio reservado), atualize as entradas de domínio associado do app e compile.
  4. QA em dispositivos físicos — tanto instalações novas quanto atualizações.
  5. Para combos de OAuth-e-deep-link (provedores de login que redirecionam de volta para o app), combine isso com testes de callbacks OAuth.

A configuração é chata na primeira vez. Depois disso, a URL do túnel é só mais uma variável de ambiente no scheme do Xcode e do Gradle.

Para padrões mais amplos de testes móveis, veja testes móveis com um túnel localhost. Entre na lista de espera do PortPreview.

Perguntas frequentes

Posso testar Universal Links do iOS no localhost?
Não diretamente. Universal Links exigem que o iOS busque apple-app-site-association sobre HTTPS real a partir de um domínio real. O localhost não qualifica. Um túnel te dá uma URL HTTPS num subdomínio de túnel que o iOS associará ao seu app assim que você listá-lo no entitlement de domínios associados.
Qual content-type o apple-app-site-association deve usar?
O iOS moderno espera application/json. Versões antigas também aceitavam application/pkcs7-mime para arquivos assinados. A maioria dos apps hoje usa a variante JSON simples. Se o iOS não pegar seu arquivo, verifique primeiro o cabeçalho content-type de um navegador desktop.
Os Android App Links precisam de um túnel para testes locais?
Sim, se você quer a verificação completa de App Link (não esquemas de URL personalizados). O Android busca assetlinks.json sobre HTTPS real a partir do domínio no seu intent filter. Um túnel fornece uma URL HTTPS real num domínio que o dispositivo pode verificar. Esquemas personalizados não precisam disso mas são menos seguros.