eduardweb.
Navigație & StateAvansat#react-native#android#ios#deep-linking#expo-router

Deep linking universal în Expo Router: de la Custom Schemes la Universal Links

De Paul Ene, 8 aug. 2026 · 8 vizualizări · 3 like-uri

Postat 8 aug. 2026
json
{
  "expo": {
    "name": "MyApp",
    "slug": "my-app",
    "scheme": "myapp",
    "ios": {
      "bundleIdentifier": "com.company.myapp",
      "associatedDomains": [
        "applinks:myapp.com",
        "applinks:www.myapp.com"
      ]
    },
    "android": {
      "package": "com.company.myapp",
      "intentFilters": [
        {
          "action": "VIEW",
          "autoVerify": true,
          "data": [
            {
              "scheme": "https",
              "host": "myapp.com",
              "pathPrefix": "/"
            }
          ],
          "category": ["BROWSABLE", "DEFAULT"]
        }
      ]
    }
  }
}

Am trecut recent prin calvarul configurării de Universal Links și App Links pe un proiect în Expo Router v3, pentru o aplicație mobilă cu peste 30k utilizatori activi. Dacă ai încercat vreodată să legi domeniul web de aplicația nativă fără să pierzi contextul când userul dă click pe un link de resetare parolă sau pe un referral, știi ce durere de cap e. În postarea asta îți arăt setup-ul exact care mie îmi merge impecabil în producție și greșelile prostute care mi-au mâncat două nopți.

Custom Scheme vs. Universal Links: de ce le vrei pe ambele

Custom schemes (myapp://profile/123) sunt extrem de simplu de setat. Le trântești în app.json și funcționează instanțiat în staging. Problema e că nu sunt unice. Orice altă aplicație instalată pe telefonul userului poate înregistra myapp://, iar pe iOS sistemul alege aleatoriu pe cine deschide. Pe Android primești un prompt urât care întreabă utilizatorul ce aplicație vrea să folosească. În plus, dacă omul nu are aplicația instalată, un link de tip myapp:// e mort – browserul aruncă o eroare.

Universal Links (iOS) și App Links (Android) folosesc domeniul tău real (https://myapp.com/profile/123). Dacă aplicația e instalată, sistemul de operare o deschide direct, fără nicio confirmare. Dacă nu e instalată, ești direcționat pe site-ul tău web unde poți face fallback elegant. Câștigul pe conversion rate pe fluxul nostru de referral a fost de 14% imediat după tranziție.

Cum simplifică Expo Router lucrurile

Pe vremea React Navigation clasic, trebuia să-ți construiești manual un obiect uriaș de mapping (linking.config) în care specificai fiecare screen și parametru. Expo Router elimină mizeria asta complet pentru că se bazează pe file-based routing. Structura ta din folderul app/ este direct oglindită în URL.

Dacă ai fișierul app/user/[id].tsx, ruta va fi automat accesibilă prin https://myapp.com/user/123 sau myapp://user/123. Nu trebuie să scrii niciun rând de JS suplimentar pentru mapping în codul aplicației.

Bătălia cu serverul: AASA și assetlinks.json

Aici se blochează 80% dintre developeri. Apple și Google nu cred pe cuvânt aplicația ta că deține domeniul myapp.com. Ele fac un request HTTP pe serverul tău la instalarea aplicației.

Pentru iOS, trebuie să servești fișierul apple-app-site-association la adresa https://myapp.com/.well-known/apple-app-site-association. Atenție: fără extensia .json în URL! Header-ul de răspuns trebuie să fie neapărat Content-Type: application/json.

Pentru Android, pui assetlinks.json la https://myapp.com/.well-known/assetlinks.json. Aici trebuie să extragi SHA-256 fingerprint-ul din keystore-ul tău de producție (sau din Google Play Console dacă folosești App Signing).

Cea mai frecventă greșeală pe care am făcut-o? Am avut un redirect de 301 de pe www.myapp.com pe myapp.com în Cloudflare, iar iOS Apple Bot refuză să urmărească redirect-urile când validează domeniul. Rezultatul: Universal Links nu funcționau deloc pe iOS în build-ul de Release, deși pe simulator funcționau perfect.

Debugging și testare în viața reală

Nu testa Universal Links în Safari scriind URL-ul în bara de adrese. Safari presupune că dacă ești deja în browser, vrei să rămâi pe web. Trimite-ți link-ul într-un mesaj pe Slack, Notes sau iMessage și dă click pe el de acolo.

Pe Android, poți forța verificarea prin ADB direct din terminal: adb shell am start -a android.intent.action.VIEW -d "https://myapp.com/user/123"

Trade-off-ul principal la Universal Links e efortul inițial de DevOps și faptul că testarea pe iOS necesită un build compilat (Development Build sau TestFlight), custom schemes fiind mult mai rapide pentru prototyping rapid.

Voi ce soluție folosiți pentru deferred deep linking când userul NU are aplicația instalată — un serviciu terț gen Branch/AppsFlyer sau v-ați făcut un redirect custom din web server?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.