In a React Native app, what is a Universal Link or Android App Link, and what happens when someone taps one without the app installed?
answer
- an ordinary https URL, not myapp://
- the domain vouches for the app
- a file under /.well-known on the site
- app missing: the OS treats it as a web link
- the same URL must be a real web page
basics
~20 sA Universal Link (iOS) or App Link (Android) is a plain https URL the OS opens straight in your app because the domain has verified the app. Without the app installed, the same URL opens the website in the browser.
solid answer
~40 sUniversal Links on iOS and App Links on Android let an ordinary `https://` URL, such as `https://recipes.example.com/r/42`, open the React Native app instead of the browser. The OS only does this after verifying a **two-way association**: the app declares the domain (the `applinks:` Associated Domains entitlement on iOS, an intent filter with `android:autoVerify="true"` on Android), and the domain hosts a file naming the app (`apple-app-site-association` or `assetlinks.json` under `/.well-known/`). Once the app opens, JavaScript receives the URL through the `Linking` module like any other deep link. If the app is not installed, or verification failed, the OS treats the tap as a normal web link and opens the browser, so the site must serve a real page at that path, usually the recipe itself plus a prompt to install the app.
go deeper
Recall that these are normal https URLs the OS opens in the app after checking a file on the domain, and that without the app the browser opens the same page.
Explain the two-way association: the entitlement or autoVerify intent filter on the app side, the AASA or assetlinks.json file on the domain side, and how the URL then reaches Linking.
Show you know the failure is silent and indistinguishable from not having the app installed, and that the website must therefore serve real content at every shared path.
Weigh one-URL-everywhere sharing against the operational cost of hosting verification files and web fallbacks for every domain and path the app claims.
## What a domain-verified link is A **deep link** is any URL that opens a specific place inside an app. The oldest form is a **custom scheme** such as `recipes://r/42`, which any app can claim by registering the scheme. A **domain-verified link** is different: it is an ordinary `https://` URL on a website you control, for example `https://recipes.example.com/r/42`, which the operating system routes into your app instead of the browser. The two platforms name the feature differently: - **Universal Links** on iOS. - **App Links** on Android (the React Native docs also simply call these deep links on Android). Neither feature is part of React Native. Both are operating-system features; React Native's only job is to receive the URL once the OS has opened the app, through `Linking.getInitialURL()` on a cold start and the `Linking` `'url'` event while the app is running. ## The two-way association The OS does not trust an app that merely *says* it handles `recipes.example.com`, because any app could say that. It requires both sides to agree: | Side | iOS Universal Links | Android App Links | |---|---|---| | App declares the domain | `com.apple.developer.associated-domains` entitlement with `applinks:recipes.example.com` | intent filter for `https` + host, with `android:autoVerify="true"` | | Domain names the app | `/.well-known/apple-app-site-association` listing `<TeamID>.<bundleID>` and paths | `/.well-known/assetlinks.json` listing the package name and **SHA-256 signing-certificate fingerprints** | | In an Expo project | `ios.associatedDomains` in app config | `android.intentFilters` with `autoVerify: true` | Only when the file on the domain matches the installed app does the OS treat the URL as belonging to that app. This is why the feature is described as **domain-verified**: ownership of the website is the proof. ## What the user sees in each case 1. **App installed and verified**: tapping the link in Messages, Mail or Notes opens the React Native app directly, with no browser flash and no chooser. The app receives the full URL. 2. **App not installed**: the OS has no app to hand the URL to, so it opens the page in the browser like any other `https` link. Nothing fails; the user simply lands on the website. 3. **App installed but verification failed**: the OS behaves as if the app were not there. On iOS the link opens Safari. On Android 12 and later an unverified web link opens in the default browser; on older Android versions the user could see a chooser dialog listing the app and browsers. Case 3 is the one interviews probe, because it is **silent**: no error appears in the React Native app or in Metro. The link just opens the browser. ## Why the web fallback matters The built-in fallback is the main reason to share `https` links instead of custom-scheme links: - A custom-scheme link like `recipes://r/42` does nothing useful on a device without the app, or on a desktop computer. The same `https://recipes.example.com/r/42` link works everywhere. - Because the URL is a real web address, **the website must serve real content at that path**. For a shared recipe that means rendering the recipe on the web, not a blank page or a 404. - The page is also where you convert visitors: iOS supports a Smart App Banner through an `apple-itunes-app` meta tag, and a plain link to the store listing works on both platforms. - One URL serves three audiences: users with the app, users without it, and desktop users. A useful mental test: if you delete the app from your phone and tap a shared recipe link, you should still see the recipe. ## Where React Native fits Inside the app, a Universal Link and a custom-scheme link arrive through the same `Linking` API as a string URL. In a bare React Native iOS project the `AppDelegate` must forward the universal-link callback to `RCTLinkingManager`, which reads the `webpageURL` of the incoming browsing activity and emits it as the `'url'` event. On Android the URL arrives in the launching `Intent` with action `VIEW`, which `Linking.getInitialURL()` reads. Everything that happens after the URL reaches JavaScript, such as mapping `/r/42` to a recipe screen or validating the id, is ordinary deep-link handling. The part that is specific to domain-verified links is the verification step before the app ever opens, and the fact that when it fails, the user is quietly sent to the website.
- On Android, what changed in Android 12 for an https link whose App Link verification failed?From Android 12, a web intent that is not verified for any installed app opens in the user's default browser. Before that, an unverified `https` intent filter could still make Android show a chooser dialog listing the app next to the browsers. So on current devices a broken `assetlinks.json` no longer produces a visible chooser; the link silently opens the website instead.
- What should the web page at a shared recipe URL do for a visitor without the app?It should render the recipe itself, because that URL is the fallback the OS uses whenever the app is absent or not verified. It can then offer the app: on iOS an `apple-itunes-app` meta tag shows the Smart App Banner, and on both platforms a store link works. A 404 or an empty redirect page breaks the whole point of sharing an `https` link.
saying these in an interview costs you the question
- A Universal Link also needs a custom scheme such as myapp:// registered
- Without the app, iOS automatically opens the App Store page
- Declaring the domain in the app is enough; the website needs nothing
- Universal Links are a React Native feature rather than an OS feature
- A failed verification shows an error dialog in the app
- The shared URL only needs to exist inside the app, not on the website