Universal Deeplink (React Native Bare App)
This guide provides step-by-step instructions for setting up deep linking on both iOS and Android platforms. It ensures that users can navigate directly to specific screens within your app from external links, such as URLs or shared content. This guide ensures deep linking is properly configured for both iOS and Android, using:
- π
apple-app-site-association
(iOS) - π
assetlinks.json
(Android)
β Common Hosting Requirementsβ
These requirements apply to both platforms:
Requirement | Value |
---|---|
Protocol | HTTPS only |
Location | https://your-domain.com/.well-known/ |
Content-Type | application/json |
Request type | Only GET requests |
No redirects | No 301/302 redirects allowed |
Access | Publicly accessible (no auth headers or cookies) |
Path | Must be exactly /.well-known/apple-app-site-association and /.well-known/assetlinks.json (no extensions for iOS!) |
π Replace your-domain.com with your actual hosted domain, e.g., myapp.example.com, xyz.co.in, etc.
β Test Hostingβ
Use this in terminal:
curl -I https://your-domain.com/.well-known/apple-app-site-association
curl -I https://your-domain.com/.well-known/assetlinks.json
Expected:
HTTP/2 200
Content-Type: application/js
π iOS Setup β Universal Linksβ
1. π File: apple-app-site-association
β
Location:
https://your-domain.com/.well-known/apple-app-site-association
Content:
{
"applinks": {
"apps": [],
"details": [
{
"appID": "TEAM_ID.BUNDLE_ID",
"paths": ["/deeplink/*"]
}
]
}
}
π Replace:
TEAM_ID
: Apple Developer Team ID (get it from Apple Dev portal)BUNDLE_ID
: iOS bundle identifier (e.g.,com.example.myapp
)
2. π Add Entitlementsβ
You must enable associated domains in your iOS app:
Option A: Xcode GUI (Recommended)β
-
Open your iOS project in Xcode.
-
Select your target β Go to Signing & Capabilities
-
Click + Capability β add Associated Domains
-
Under Domains, add:
applinks:your-domain.com
Option B: Manually edit .entitlements
fileβ
In ios/YourApp/YourApp.entitlements
, add:
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:your-domain.com</string>
</array>
Also, make sure this file is included in your target's build settings.
π€ Android Setup β App Linksβ
1. π File: assetlinks.json
β
Location:
https://your-domain.com/.well-known/assetlinks.json
Content:
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.yourcompany.app",
"sha256_cert_fingerprints": ["AA:BB:CC:...:ZZ"]
}
}
]
π Replace:
package_name
: your appβs package name (e.g.,com.example.myapp
)sha256_cert_fingerprints
: SHA-256 of your release keystore
π Get SHA-256 Fingerprint:β
keytool -list -v -keystore your-release-key.jks -alias your-alias
Youβll find:
SHA256: AA:BB:CC:...:ZZ
2. π§Ύ AndroidManifest.xml Setupβ
Update android/app/src/main/AndroidManifest.xml
:
<activityandroid:name=".MainActivity"
android:launchMode="singleTask"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:label="@string/app_name"
android:windowSoftInputMode="adjustResize">
<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" />
<dataandroid:scheme="https"
android:host="your-domain.com"
android:pathPrefix="/deeplink" />
</intent-filter>
</activity>
π Replace your-domain.com and path as needed.
π Summary Checklistβ
Step | iOS (Universal Links) | Android (App Links) |
---|---|---|
β | Host .well-known file | Host .well-known file |
β | Enable Associated Domains | Add intent-filter to manifest |
β | Add .entitlements with applinks | Add assetlinks.json with SHA-256 |
β | HTTPS, JSON, No Redirects | HTTPS, JSON, No Redirects |
β | Test with curl -I | Test with curl -I |
π§ͺ Testingβ
iOS Simulatorβ
xcrun simctl openurl booted https://your-domain.com/deeplink/anything
Android Emulatorβ
adb shell am start -W -a android.intent.action.VIEW -d "https://your-domain.com/deeplink/anything" bundleId
π‘ Optional: Deep Linking Test Linksβ
Try opening:
- iOS:
https://your-domain.com/deeplink/test
- Android:
https://your-domain.com/deeplink/test
Or manually test in browser or using adb
:
adb shell am start -a android.intent.action.VIEW -d "https://your-domain.com/deeplink/test" com.yourcompany.app
β UPI Deep Linking Support in React Native App (Android + iOS)
π Common JS Code (React Native)
Ensure you're intercepting UPI schemes like upi://
in WebView or navigation handlers:
import { Linking } from "react-native";
const handleNavigationStateChange = (navState: any) => {
const url = navState?.url;
if (url?.startsWith("upi://")) {
Linking.openURL(url).catch((err) => {
console.warn("Unable to open UPI link", err);
});
return false;
}
};
π iOS Configuration (Info.plist
)β
Add LSApplicationQueriesSchemes
to allow launching or checking if UPI apps are installed:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>upi</string>
<string>phonepe</string>
<string>tez</string>
<string>paytm</string>
<string>bhim</string>
<string>amazonpay</string>
<string>cred</string>
<string>freecharge</string>
</array>
β οΈ This is mandatory for Linking.canOpenURL and Linking.openURL to work for these schemes on iOS.
π€ Android Configuration (AndroidManifest.xml
)β
1. Add <queries>
for Android 11+ (API 30+) β Required to check if apps are installedβ
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<queries>
<!-- UPI base scheme -->
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="upi" />
</intent>
<!-- Specific UPI apps -->
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="bhim" />
<data android:host="pay" />
<data android:pathPrefix="/" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="paytm" />
<data android:host="pay" />
<data android:pathPrefix="/" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="amazonpay" />
<data android:host="pay" />
<data android:pathPrefix="/" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="cred" />
<data android:host="pay" />
<data android:pathPrefix="/" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="freecharge" />
<data android:host="pay" />
<data android:pathPrefix="/" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="phonepe" />
<data android:host="pay" />
<data android:pathPrefix="/" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="tez" />
<data android:host="pay" />
<data android:pathPrefix="/" />
</intent>
</queries>
π Testing UPI Deep Linksβ
Androidβ
adb shell am start -a android.intent.action.VIEW -d "upi://pay?pa=xyz@upi&pn=Test&am=1&cu=INR"
iOS (Safari or in-app)β
Linking.openURL("upi://pay?pa=xyz@upi&pn=Test&am=1&cu=INR");