Universal Links do iOS
Domínios associados, apple-app-site-association e hospedagem em CDN - o guia do iOS para abrir URLs de marketing https:// diretamente no seu app Expo SDK 57 sem uma folha de desambiguação de esquema personalizado.
Busque em todas as páginas da documentação
Domínios associados, apple-app-site-association e hospedagem em CDN - o guia do iOS para abrir URLs de marketing https:// diretamente no seu app Expo SDK 57 sem uma folha de desambiguação de esquema personalizado.
Cartão de receita de referência rápida - pronto para copiar e colar.
// app.config.ts
export default {
expo: {
scheme: "shopapp",
ios: {
bundleIdentifier: "com.example.shopapp",
associatedDomains: ["applinks:shop.example.com"],
},
},
};// https://shop.example.com/.well-known/apple-app-site-association
{
"applinks": {
"apps": [],
"details": [
{
"appID": "TEAMID.com.example.shopapp",
"paths": ["/orders/*", "/product/*", "/invite/*"]
}
]
}
}Quando usar isso:
https:// que devem abrir o app quando instalado.myapp://.Configuração de ponta a ponta para https://shop.example.com/orders/* em um app Expo com prebuild.
Passo 1 - Entitlements via app.config.ts
// app.config.ts
import type { ExpoConfig } from "expo/config";
const config: ExpoConfig = {
name: "ShopApp",
slug: "shop-app",
scheme: "shopapp",
ios: {
bundleIdentifier: "com.example.shopapp",
associatedDomains: ["applinks:shop.example.com"],
},
android: {
package: "com.example.shopapp",
},
};
export default config;Passo 2 - Hospede AASA no seu CDN
{
"applinks": {
"apps": [],
"details": [
{
"appID": "ABCDE12345.com.example.shopapp",
"paths": [
"/orders/*",
"/product/*",
"NOT /admin/*",
"NOT /api/*"
]
}
]
},
"webcredentials": {
"apps": ["ABCDE12345.com.example.shopapp"]
}
}Sirva em ambos os caminhos (a Apple verifica qualquer um):
https://shop.example.com/apple-app-site-associationhttps://shop.example.com/.well-known/apple-app-site-associationPasso 3 - Cabeçalhos de resposta do CDN
Content-Type: application/json
Cache-Control: max-age=3600.json é necessária; corpo JSON bruto.ABCDE12345 pelo seu Apple Team ID do portal do Desenvolvedor.Passo 4 - Tela do Expo Router
// app/orders/[id].tsx
import { useLocalSearchParams } from "expo-router";
import { Text, View } from "react-native";
export default function OrderScreen() {
const { id } = useLocalSearchParams<{ id: string }>();
return (
<View style={{ padding: 16 }}>
<Text>Order {id}</Text>
</View>
);
}Passo 5 - Construa e verifique
npx expo prebuild --platform ios
npx expo run:ios
# Simulador: abra o universal link
xcrun simctl openurl booted "https://shop.example.com/orders/42"O que isso demonstra:
/orders/42.applinks: nos seus entitlements.https://, o iOS abre seu app e passa a URL para o React Native.| Padrão | Corresponde |
|---|---|
/orders/* | /orders/42, /orders/42/receipt |
/product/* | /product/widget |
NOT /admin/* | Exclui URLs de admin mesmo que o pai corresponda |
* | Tudo no domínio - evite a menos que o app possua o host inteiro |
| Verificação | Critério de aprovação |
|---|---|
| TLS | Certificado válido; sem http:// misturado |
| Redirecionamentos | URL AASA retorna 200 diretamente |
| Content-Type | application/json ou application/pkcs7-mime (assinado) |
| Tamanho | Abaixo de 128 KB |
| Acessibilidade | Internet pública - sem VPN ou lista de permissão de IP |
# Valide o AASA com o CDN da Apple (o dispositivo eventualmente verá os mesmos dados)
curl -s "https://app-site-association.cdn-apple.com/a/v1/shop.example.com" | jq .appID.TEAMID.bundleIdentifier do Apple Developer → Membership.www para apex quebra a busca. Correção: sirva o AASA no host exato em associatedDomains.eas build --platform ios após alteração de configuração./api/* em paths - respostas JSON da API não devem abrir o app. Correção: regras NOT explícitas ou prefixos estreitos.SFSafariViewController ou <a target="_blank"> para abrir externamente.| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| Apenas esquema personalizado | Ferramentas internas, redirecionamentos OAuth | Campanhas de e-mail ao consumidor |
| Firebase Dynamic Links (descontinuado) | Projetos legados já integrados | Greenfield - Google fechou em agosto de 2025 |
| Branch.io / AppsFlyer OneLink | Links profundos adiados + atribuição | Links verificados simples são suficientes |
| Apenas Smart App Banner | Impulso web-para-app sem universal links completos | Você precisa de toque-para-abrir sem Safari |
TEAMID.com.example.shopapp - sem espaços.details com valores appID diferentes para IDs de bundle de desenvolvimento e produção.applinks:staging.example.com vs applinks:shop.example.com.curl -I para redirecionamentos e tipo de conteúdo.applinks:*.example.com nos entitlements e details separados por subdomínio no AASA.*.example.com em paths não é válido - liste cada subdomínio explicitamente./orders/42?ref=email funciona se /orders/* corresponder; a query não afeta as regras de caminho.details - o iOS escolhe o app instalado que corresponde ao appID.https://shop.example.com/orders/42 para app/orders/[id].tsx automaticamente quando o esquema/host são configurados.Versões da Stack: Esta página foi escrita para React 19.2.3, React Native 0.86.0 e Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última atualização: 19 de jul. de 2026