Deep Linking with React Native Push Notifications

Daniel Yo
Knock Engineering
Published in
5 min readMay 26, 2021

How we implemented deep linking via push notifications and React-Navigation

How can we reach our target users on mobile, increase retention rate and provide them with necessary information as quickly and efficiently as possible? This is a common problem with many different solutions and ideas. We can send them push notifications to turn their attention back to the app, but sometimes that is not enough. We want our users to immediately be presented with information they care about. That’s where deep links come in.

This is what we’re building towards

Table of Contents

What is a deep link?

Generally, a deep link is a type of link with a custom scheme for taking users to a specific point or content in the app. In our case we want our users to be taken to the details page of our app. For example, since we want to deep link into the details page, we can construct our deep links like so: myapp://user/details/123456

This is not to be confused with universal links, which serve a similar purpose, but are typically triggered from a website link and require more setup.

What resources did we use?

Considerations

⚠️ This article will only cover some of these considerations

There were several things that we had to consider before and during the implementation process.

  1. What should the push payload look like?
  2. How will it work based on different app states? (foreground, background, exited/terminated)
  3. What should happen on a failed page load or invalid deep link payload?
  4. What if the user is not logged in when they tap the push notification?

Registering custom schemes for deep links

Before anything can happen, we need to set up our custom scheme in the native project (iOS/Android). It is very straightforward through their documentation here

Navigation link config

Next, we need to tell React-Navigation how to react to our scheme. React-Navigation provides great documentation on how to set up the linking config for our navigation container.

  1. Custom scheme goes here so React-Navigation knows when to deep link
  2. Our navigation flow consists of 2 main Stack.Screen components
    AuthenticatedStack — displayed only after a user has been authenticated (basically consists of all other screens)
    LoginStack — displayed if user is not authenticated
  3. This is the screen we want to deep link to
    3-a. by default, the deep link path needs to have a relative match to how it is set up in the app. Given the complexity of our screens, our matching path would be too long and complex. Instead we can use a custom path by setting up exact paths
  4. We will cover getInitialURL in the upcoming section
  5. subscribe callback is used to handle incoming links instead of the default deep link handling
    5-a. onReceiveUrl callback will forward the url to React-Navigation to decide whether or not it should navigate somewhere
    5-b. listens to any Linking.openUrl() requests — this will be important later

That’s it! Now our app can respond properly when given a scheme that looks something like myapp://user/details/123

We can test this on the simulators by following this guide, but we’re going to test it on a real device by hitting the url manually in Safari.

As soon as the deep link is hit, it launches the app and navigates to the details view

That’s great, but how does that tie into push notification? It doesn’t, at least not yet.

Configuring the push notification payload

Before we can add code to handle our deep link, we need to figure out how to send that data within a push notification. We know that all the app needs is access to the scheme we created above, so we just need to add a custom payload.

FCM and APNS have their own way of passing in custom data, you can read more about them below:

We need to shape them in a way that we can extract the data the same way. So something like this:

Android

{
"message": {
"notification": { // notification data },
"data": {
"link":"myapp://user/details/123456"
}
}
}
An example Android notification with our deep link content

iOS

{
"aps": {
"alert": { // alert data },
"badge": 1,
},
"link":"myapp://user/details/123456"
}
An example iOS notification with our deep link content

Configuring the push notification handler

The push notification configuration for react-native-push-notification is well explained in their usage docs. We only care about the onNotification configuration since this is the function being called when a push notification is opened or received (foreground only).

  1. We are extracting the custom link property we defined in the payload
  2. The subscribe method from the previous section will react to this call and start the navigation process that we saw earlier

Push notification tapped > app launch > onNotification > Linking.openUrl() > linking.subscribe()

Making it work in different app states

By default, if the app is active (foreground/background), what we’ve set up so far will automatically work. Exit/terminated state on the other hand is a little bit different. Since the app is not initialized, our subscriber method has not been initialized and will not be reacting to any Linking.openURL calls.

Push Notification tapped > app launch > onNotification > Linking.openUrl() > undefined

We can resolve this issue by updating our Linking config with getInitialURL which gets called as soon as the app is initialized.

  1. react-native-navigation provides us with a method popInitialNotification which basically gives us the last notification item we interacted with
  2. Start the navigation process (same as before)

What happens now is something like:

Push Notification tapped > app launch > onNotification > Linking.openUrl() > undefined > app load > getInitialURL > popInitialNotification > Linking.openURL() > linking.subscribe()

Welp, we’ve basically covered all the essentials. We hope this article has given you some insight on how deep linking could be integrated with push notifications, or maybe you’ve got some new ideas on how to better implement them. We are always open for improvements, so feel free to share your thoughts and ideas!

--

--