Deep linking support for iOS and Android with rules for allowed and ignored links

Universal Links on iOS and App Links on Android are platform features that allow applications to open directly from regular HTTPS URLs. When configured, clicking a link such as https://visuality.pl/dashboard/15 does not open the browser first. It launches the application on the correct screen. If the application is not installed, the same link behaves like any other URL and opens the browser. This makes deep linking predictable and safe, without custom URL schemes or pop-ups asking the user for permission.
iOS
To support Universal Links, the web domain and the application must trust each other. The iOS application declares the domain in its entitlements. The domain confirms this relationship by serving a file named apple-app-site-association. The file is placed under the .well-known directory, served over HTTPS, without redirects, and importantly without a .json extension. For the visuality.pl domain the correct location is:
https://visuality.pl/.well-known/apple-app-site-association
The file describes which app is authorised to open the domain and which paths should trigger the application. A minimal example looks as follows:
{
"applinks": {
"apps": [],
"details": [
{
"appID": "YOUR_TEAM_ID.pl.visuality.app",
"paths": [ "*" ]
}
]
}
}
Some applications need more granular control. It is common to limit deep linking only to pages that make sense inside the native interface and to explicitly ignore others. iOS supports this by allowing a combination of specific prefixes and exclusions:
{
"applinks": {
"apps": [],
"details": [
{
"appID": "YOUR_TEAM_ID.pl.visuality.app",
"paths": [
"/dashboard/*",
"/tasks/*",
"/profile/*",
"/calendar/*",
"NOT /admin/*",
"NOT /api/*"
]
}
]
}
}
This configuration allows the most important authenticated areas of the product to open in the application, while administrative and API routes remain in the browser. Because the rules live on the server, the behaviour of the links can change without shipping a new version to the App Store.
Android
Android provides a similar mechanism called App Links. The idea is identical: clicking an HTTPS link opens the application if it is installed. The verification step is also handled by the domain, but Android expects a different file. Instead of apple-app-site-association, Android uses a file named assetlinks.json, stored in the same .well-known directory:
https://visuality.pl/.well-known/assetlinks.json
The file must contain the package name of the Android application and the SHA-256 fingerprint of the signing certificate. A typical configuration looks like this:
[
{
"relation": [ "delegate_permission/common.handle_all_urls" ],
"target": {
"namespace": "android_app",
"package_name": "pl.visuality.app",
"sha256_cert_fingerprints": [
"ANDROID_RELEASE_CERTIFICATE_SHA256_FINGERPRINT_HERE"
]
}
}
]
Unlike iOS, the Android verification file does not define path filtering. Android checks only that the application owns the domain. Deciding which URLs should open the application happens inside the mobile codebase, in the application manifest. Path-level control is implemented through the intent filter. A fragment of configuration might look like this:
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="visuality.pl"
android:pathPrefix="/dashboard" />
<data
android:scheme="https"
android:host="visuality.pl"
android:pathPrefix="/tasks" />
<data
android:scheme="https"
android:host="visuality.pl"
android:pathPrefix="/profile" />
</intent-filter>
Each <data> entry specifies one allowed area of the website. Links outside those paths will continue to open in the browser. Because the logic sits in the manifest, any changes to link behaviour require an update of the Android application and distribution of a new build. For that reason iOS and Android complement each other: iOS makes the server authoritative for path decisions, while Android expects the application to define them.
Closing remarks
Although the implementation details differ slightly between iOS and Android, both platforms provide a secure and predictable way to handle deep links. The web domain verifies ownership using a public file stored under .well-known, and the application declares which links it is capable of handling. This creates a consistent experience: a single HTTPS link works in email, in a browser, in a push notification or inside another application. If the app is installed, navigation continues inside the native interface. If not, the user ends up in the browser without additional friction.
Universal Links and App Links solve a practical problem for modern mobile products: users should be able to move directly to relevant screens without manually searching through the interface. Controlled deep linking, supported by clear rules for allowed and ignored URLs, makes this possible in a maintainable way.