Deep linking 🔗 in React Native
Tags: reactnative, mobile, android, ios
Published: 2022-12-19 07:14:10

Hello Dev 👋 trust you're hacking good. Let's talk about setting up deep linking for react native projects. Grab your laptop and let's grab some knowledge .

### So what is deep linking?
Deep linking is a way to move directly to a particular screen in a particular mobile app through URLs.

You know the way you click a link for e.g dev.to/stanleyugwu and it takes you to a particular page within a website, with mobile deep linking, you'll be able to achieve the same result for mobile apps. In short you'll be able to navigate to a particular screen/view of a mobile app by clicking a link.

### Without deep linking
The traditional way of getting to where you want in any mobile app without deep linking is to launch the app, and then follow whichever route the app puts you through, till you get to where you want.

Consider below diagram as the UI flow of an example mobile app. Each box represents a screen within the app.

![App UI flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ib6u2ncms77km04kk01a.png)

Say you want to edit your profile from the **Profile** screen, you have to move from **Home** to **Settings** then to **Profile** screen.

### With deep linking
With deep linking setup for our example app, we'll be able to move directly to the **Profile** screen without going through the intermediate screens (Home, Settings).
![App UI flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pv8rdihr807uj5ybhh0t.png)

A common use-case scenario of deep linking is when slack sends you an email with a magic link which you click on and it takes you to slack app if you have it installed. That's deep linking at work there 😎

### Benefits of deep links
There are numerous advantages of setting up deep links for your mobile app:
- Improves app discoverability
- Improves user engagement
- Enhances the user experience
- Re-Engages users to your app fast
- Campaign opportunity (campaign can be run for individual screen)
- e.t.c

### Configuring deep links
Deep links are regular links, it's just the underlying operating system and the mobile app been deep-linked into that makes them powerful.

Configuring your mobile app to support deep linking is just about informing the operating system that the app can handle certain URLs and/or URL schemes. So that when the user clicks on a URL matching the specifications, your app can take over, and handle the user's request.

A typical URL has different parts or segments as denoted by the image below:
![URL segments](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rbdfjfjyk7s55jo7fry3.png)

You can configure your app to handle each segment or combination of segments. What that means is you can configure your app to handle URLs with certain **scheme**, **second-level domain**, **top-level domain**, **subdirectory**, or a combination of them.

In this tutorial, we will be setting up our [React Native](https://reactnative.dev) app to handle the scheme `myapp://` so that URLs having `myapp://` scheme would be handled by our app.

I think I've said enough 🤐, let's get to work 💻.

#### 1. Create a new React Native app (let's call it deepLinkApp 😉)
```console
npx react-native init deepLinkApp
```
Move into the app's directory
```console
cd ./deepLinkApp
```
Click [here](https://reactnative.dev/docs/environment-setup) to learn how to setup your environment for React Native.

#### 2. Configure deep links for android
On Android, deep links works through intents. The Android OS broadcasts an intent when a link is clicked, and apps that can handle the intent and link shows up for user to choose. Now let's tell Android that our app can handle `myapp://` scheme.
The easiest way to do this is with the [`uri-scheme`](https://www.npmjs.com/package/uri-scheme) package: 
```console
npx uri-scheme add myapp --android
```

If you want to set it up manually, open up `deepLinkApp/android/app/src/main/AndroidManifest.xml`, and make the following adjustments:

1. Set `launchMode` of `MainActivity` to `singleTask` in order to receive intent on existing `MainActivity`.

2. Create a new `intent-filter` inside the `MainActivity` entry with a `VIEW` type action

Below is how your `.MainActivity` activity tag should look like with the `intent-filter` and `launchMode` set, so you can just copy and paste it:

```xml
...
<activity
    android:name=".MainActivity"
    android:launchMode="singleTask">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <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>
...
```

#### 3. Configure deep links for iOS
Include the following lines in your project's `AppDelegate.m` file in order to be able to listen to incoming app links:

Copy/paste below code at the top of the file
`#import <React/RCTLinkingManager.h>`

Copy/paste below code inside `@implementation AppDelegate` above `@end`:
```obj-c
- (BOOL)application:(UIApplication *)application
   openURL:(NSURL *)url
   options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
  return [RCTLinkingManager application:application openURL:url options:options];
}
```

Now let's add the scheme to our iOS project configuration.
The easiest way to do this is again with the `uri-scheme` package. Run the following command:
```console
npx uri-scheme add myapp --ios
```

Again, if you want to do it manually, open up the project `deepLinkApp/ios/deepLinkApp.xcworkspace` in Xcode. Select the project in sidebar and navigate to the info tab. Scroll down to "URL Types" and add one. In the new URL type, set the identifier and the URL scheme to `myapp`.

This is how it should look in Xcode:

![Xcode scheme configuration interface](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fqq0go1ls188lhgz9d72.png)
Imge Source: [react-navigation](https://reactnavigation.org)


#### 4. Rebuild and install the app
We have made changes on the native side of our app, so you need to rebuild and install the app in your emulator, simulator, or device.

For iOS, run:
```console
npx react-native run-ios
```

For Android, run:
```console
npx react-native run-android
```

#### 5. Test out the deep link (the moment of truth 😆)
Now we're going to use our handy `uri-scheme` command line package to test out the deep link we just set up for both Android and iOS.

For iOS run:
```console
npx uri-scheme open "myapp://any/host/and/path" --ios
```

For Android run:
```console
npx uri-scheme open "myapp://any/host/and/path" --android
```

Running above command will launch/start-up our app on the emulator/simulator/device if it's not already running, otherwise nothing really happens. Yes nothing 😎.
The reason is because we didn't specify what happens next after our app is granted permission to handle the deep link.

#### 6. Handle the deep link
We need to handle the deep link on the Javascript side of our app so that we can specify what happens next after our app is launched or foregrounded as a result of running above command, or user clicking on URL with `myapp://` scheme. Fortunately, React Native provides us with a `Linking` module which we can call from JavaScript to handle deep linking easily 😇👌.

**There are two ways to handle deep links that open your app:**
1. If the app is already open/launched, the app is foregrounded and a Linking 'url' event is fired
You can handle these events with `Linking.addEventListener('url', callback)` - it calls `callback({ url })` with the URL which was used to open the app.

2. If the app is not already open/launched, it is opened and the url which was used to open the app is passed in as the `initialURL`
You can handle these events with `Linking.getInitialURL()` - it returns a Promise that resolves to the URL, if there is one.

To handle these cases in our app, open up `App.js` and add the following code to it:
```js
useEffect(() => {
      // handles deep link when app is already open
      Linking.addEventListener('url', evt => {
        console.log(evt.url);
      });

      // handles deep link when app is not already open
      Linking.getInitialURL()
        .then(url => console.log('Initial URL:', url))
        .catch(console.warn);

    return () => {
      // clears listener when component unmounts
      Linking.removeAllListeners('url');
    };
  }, []);
```

Now lets' run the `uri-scheme` test command one more time:

For iOS run:
```console
npx uri-scheme open "myapp://any/host/and/path" --ios
```

For Android run:
```console
npx uri-scheme open "myapp://any/host/and/path" --android
```

Now you should see your app opened, and "myapp://any/host/and/path" logged to the console. Bravo!! 💃🕺 your deep link setup is working.

Note that we're just logging the URL (which opened our app) to the console, in real apps however, you might need to parse the URL and perform further operations such as navigating the user to the appropriate screen. Luckily if you use [`react-navigation`](https://www.npmjs.com/package/@react-navigation/native) package for your app navigation, there's an easy way to bind certain deep link URLs to certain screens in your app. You can read more on that [here](https://reactnavigation.org/docs/deep-linking/).

#### Summary
We've just learnt how to setup deep links for our React Native (Android and iOS) app. If you've not been doing this for your apps, you really need to consider it as it comes with so many benefits.

The technicalities involved in setting up deep links are not really that much, the lengthiness of this article can be attributed to the stretch in explanations (I was more concerned with how it worked, sorry 😉).

Phew! 😌 that was a long one 😅. I hope you learnt something?. happy hacking 💻 ✌🖖