{
"expo": {
"scheme": "myapp",
"ios": {
"bundleIdentifier": "com.yourcompany.myapp",
"associatedDomains": [
"applinks:myapp.com",
"applinks:staging.myapp.com"
]
},
"android": {
"package": "com.yourcompany.myapp",
"intentFilters": [
{
"action": "VIEW",
"autoVerify": true,
"data": [
{ "scheme": "https", "host": "myapp.com", "pathPrefix": "/produs" },
{ "scheme": "https", "host": "myapp.com", "pathPrefix": "/profil" }
],
"category": ["BROWSABLE", "DEFAULT"]
}
]
}
}
}Am tot văzut colegi de breaslă care se bat cu capul de pereți când vine vorba de deep linking în React Native, mai ales de când cu Expo Router. Săptămâna trecută am configurat cap-coadă fluxul ăsta pentru un client cu 15.000 de utilizatori activi și am pierdut o zi întreagă doar din cauza cache-ului de la Apple. Am zis să scriu ghidul ăsta scurt și pragmatic, ca să nu repetați greșelile mele.
Expo Router ne ușurează mult viața pentru că mapează rutele direct pe structura de fișiere. Totuși, partea grea rămâne configurarea nativă și validarea domeniilor pe server.
Custom Schemes vs. Universal Links
Să lămurim un lucru clar din start. Custom schemes (de tipul myapp://) sunt bune doar pentru dezvoltare sau integrări simple (cum ar fi redirect-ul după un login OAuth). În producție, pentru un UX curat, ai nevoie de Universal Links (iOS) și App Links (Android).
De ce? Pentru că dacă trimiți un mail cu myapp://produs/123 și userul nu are aplicația instalată, link-ul e mort. Cu https://myapp.com/produs/123, dacă are aplicația se deschide direct în app, dacă nu, se deschide în browser pe site-ul tău.
Pasul 1: Configurația în app.json
Trebuie să îi spui lui Expo ce domenii deții și ce scheme folosești. Adaugă configurația de mai jos în app.json. Atenție la formatul pentru iOS: domeniul trebuie prefixat obligatoriu cu applinks:.
Pasul 2: Fișierele de asociere de pe server
Sistemele de operare trebuie să verifice că tu chiar deții domeniul respectiv. Altfel, oricine ar putea pretinde că deschide link-urile de la facebook.com.
Pentru iOS, trebuie să pui un fișier JSON numit apple-app-site-association (fără extensie!) în folderul .well-known/ al site-ului tău.
{
"applinks": {
"apps": [],
"details": [
{
"appID": "TEAM_ID.bundle.identifier",
"paths": ["/produs/*", "/profil/*"]
}
]
}
}
Pentru Android, creezi .well-known/assetlinks.json. Aici ai nevoie de SHA256-ul certificatului cu care semnezi aplicația. Atenție mare: dacă folosești Google Play App Signing, trebuie să iei SHA-ul din consola Google Play, nu cel pe care îl generează local build-ul de Expo.
Capcane din producție și trade-offs
Cea mai mare problemă pe iOS este că Apple folosește un CDN propriu pentru a cache-ui fișierele AASA. Când userul instalează aplicația, iOS nu descarcă fișierul direct de pe serverul tău, ci de pe CDN-ul Apple. Dacă ai greșit o virgulă în JSON pe server și ai făcut update, Apple poate păstra cache-ul vechi și până la 24-48 de ore.
Cum fentezi asta în debug? Adaugă ?mode=developer la finalul domeniului în configurația de iOS din app.json (de ex: applinks:myapp.com?mode=developer) și activează "Associated Domains Development" din meniul de Developer al iPhone-ului. Asta va forța telefonul să descarce fișierul direct de pe serverul tău, ignorând CDN-ul Apple.
Ca trade-off, Expo Router se ocupă de parsarea URL-ului impecabil dacă structura ta de foldere reflectă path-urile de pe server. Dacă ai app/produs/[id].tsx, un link către /produs/42 va deschide exact ecranul corect cu parametrul id deja injectat în useLocalSearchParams(). Totuși, dacă ai rute legacy pe site pe care nu le poți mapa 1:1 în app, va trebui să scrii un middleware destul de urât de redirect-uri în _layout.tsx.
Cum gestionați testarea link-urilor universale în local? Folosiți ngrok sau preferați să faceți deploy direct pe un mediu de staging?