Skip to content
useffect.sh
Book 30 min with a senior
UI

Universal links and App Links

Ordinary https links that open the app when installed, proven by a file hosted on your domain (AASA, assetlinks.json).

Definition

Universal links (iOS) and App Links (Android) are ordinary https links that open the app directly when it is installed, and the website otherwise. Unlike a custom scheme, the association is verified: the domain hosts a file declaring which apps may claim which paths. On iOS it is apple-app-site-association at the root or under /.well-known/, served over https, with the TEAMID.bundleId identifier; the app declares the domain in its Associated Domains entitlement (applinks:example.com). On Android it is /.well-known/assetlinks.json, served as application/json, listing the package name and the SHA-256 fingerprints of the signing certificates; the app declares an intent filter with autoVerify. They replace custom schemes for anything starting from an email, an SMS, or a web page, where a myapp:// link opened on a laptop does nothing. You meet them as soon as a shared link has to work with or without the app.

In a real app

With Expo, ios.associatedDomains (["applinks:example.com"], no protocol, the most frequent mistake) and android.intentFilters (with autoVerify: true) in app.json cover the app side; EAS Build registers the entitlement with Apple. Without EAS or prebuild, you enable the Associated Domains capability in Xcode and the com.apple.developer.associated-domains entitlement. Android fingerprints come from eas credentials -p android or the Play Console (App Signing), and you need one per signing variant: debug, local release, Play App Signing.

The iOS pitfall is caching: the system downloads the AASA at install or update time, through Apple’s CDN, and does not refresh it often. Changing paths in production therefore needs a new App Store version, and an AASA broken on launch day stays broken for the users who installed that day. The file must be under 128 KB uncompressed and the * wildcard does not cross dots or slashes. On Android, verification runs after install and can take twenty seconds or more; adb shell pm get-app-links <package> shows its state.

I check both files with curl -I (200, no redirect, correct content type), that the declared paths match the actual Expo Router routes, and that a fallback web page exists for every path, because a universal link without a web page is a dead link for everyone without the app.

Sources

All 35 glossary terms

One of these is blocking your app?

30 minutes with a senior to look at the problem in your code. Free.