Implementing Deep Linking and Universal Links in React Native: A Complete Guide

Sahil MohammadSahil Mohammad
4 min read

What is Deep Linking?

Deep linking enables your app to respond to external URLs and custom URI schemes, allowing users to:

  • Open your app from web links

  • Navigate directly to specific screens or content

  • Share direct links to app content

  • Handle marketing campaign links

  • Deep linking in React Native comes in two flavours:

  • Custom URL Schemes (e.g., myapp://)

  • Universal Links (iOS) and App Links (Android) using HTTPS URLs

While custom URL schemes are easier to implement, Universal/App Links provide better security and user experience since they use verified HTTPS URLs.

Prerequisites

Before we begin, ensure you have:

  • A React Native project set up

  • React Navigation installed (@react-navigation/native)

  • Basic understanding of React Navigation

Implementation Steps

First, you'll need to modify your Android and iOS configurations to recognise your deep links.

For Android (in android/app/src/main/AndroidManifest.xml):

xmlCopy<activity
    android:name=".MainActivity"
    android:launchMode="singleTask">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="myapp" />
    </intent-filter>
</activity>

For iOS (in ios/YourApp/Info.plist):

xmlCopy<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>myapp</string>
    </array>
  </dict>
</array>

First we will start with config concerned to server side. Here I will be taking a node.js server for explaining the configs.

Create a public folder in root directory of your project, in that folder create another folder named ".well-known”.

Make sure you add below line of code in your App.js/index.js file of your server
app.use(express.static(path.join(__dirname, "public")));
Server Code GitHub Link

For IOS:

In ".well-known” directory create a file named apple-app-site-association (no extension):

{
  "applinks": {
    "apps": [],
    "details": [
      {
        "appID": "TEAM_ID.com.yourapp.bundleid",
        "paths": ["*"]
      }
    ]
  }
}

Note: You can find the Team_ID on apple developer account website in Membership details section. The string after Team_ID is your bundle ID, you can find in general section by opening your project in Xcode.

Update Info.plist

<key>com.apple.developer.associated-domains</key>
<array>
    <string>applinks:yourdomain.com</string>
</array>

For Android:

In ".well-known” directory create a file named assetlinks.json:

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.yourapp.package",
    "sha256_cert_fingerprints": ["YOUR-SHA256-CERTIFICATE"]
  }
}]

Replace the "com.yourapp.package" with value available at “namespace” key in your app level build.gradle file.

The sha256_cert_fingerprints can be generated by runnning ./gradlew signingReport command in android directory of your project. It will generate two-three SHA-keys. You need to add only distinctive keys here.

Update AndroidManifest.xml

<activity
    android:name=".MainActivity"
    android:launchMode="singleTask"
    android:usesCleartextTraffic="true"
    android:exported="true">
    <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="yourdomain.com"
            android:pathPrefix="/" />
    </intent-filter>
</activity>

Verify that below written snippets are present in AndroidManifest.xml file.
android:usesCleartextTraffic="true" android:launchMode="singleTask android:autoVerify="true"

3. Configure Navigation

const linking = {
  prefixes: [
    'myapp://',                // Basic deep linking
    'https://yourdomain.com'   // Universal/App Links
  ],

  config: {
    screens: {
      Home: 'home',
      Profile: {
        path: 'user/:id',
        parse: {
          id: (id) => `${id}`,
        },
      },
      Settings: 'settings',
    },
  },
};

// In your Navigation Container
function App() {
  return (
    <NavigationContainer linking={linking}>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Profile" component={ProfileScreen} />
        <Stack.Screen name="Settings" component={SettingsScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

In our ProfileScreen component, we can then access the id parameter from the route.params object:

import { useRoute } from '@react-navigation/native';

function ProfileScreen() {
  const route = useRoute();
  const { id } = route.params;

  return (
    <View>
      <Text>User Profile: {id}</Text>
      {/* Render profile content */}
    </View>
  );
}

Most important thing to do after All the Configs:

Delete the app from your emulator/ simulator/device, reinstall the pods(for IOS) and build your app with reset-cache command.

# Verify AASA file
curl -v https://yourdomain.com/.well-known/apple-app-site-association
# Verify Asset Links
curl -v https://yourdomain.com/.well-known/assetlinks.json

Testing Using uri-scheme

For testing deep links on the iOS simulator, you can use the uri-scheme package. This tool allows you to easily open deep links in your app during development and testing.

To install the uri-scheme package, run the following command:

npm install -g uri-scheme

Once installed, you can open deep links in the iOS simulator using the following command:

npx uri-scheme open "YOUR_DEEP_LINK_URL" --ios

Replace "YOUR_DEEP_LINK_URL" with the actual deep link you want to test. For example:

npx uri-scheme open "myapp://profile/123" --ios
npx uri-scheme open "https://myapp.com/profile/456" --ios

npx uri-scheme open "myapp://profile/123" --android
npx uri-scheme open "https://myapp.com/profile/456" --android
0
Subscribe to my newsletter

Read articles from Sahil Mohammad directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sahil Mohammad
Sahil Mohammad