Organizing your app to handle deeplinks and push notifications

Push Notifications

Software Architecture

dynamic link

This article presents a way to organize in the same module the code for handling deeplinks and the code for handling push notifications. The code that is presented is written in Swift and for iOS but the architecture of the module and the logic of the code can be transposed to other languages and technologies.

The code is available here.

Deeplinks and push notifications

Before diving into how the module is structured, let's briefly describe what deeplinks and push notifications are.

A deeplink is a special kind of link that, when opened in the browser of a mobile phone, opens a specific screen of a native application. For example, for a company that provides a website and an application dedicated to weather forecasts, a deeplink could be used to open the screen of the app that shows the weather forecast for a specific day. If the user doesn't have the app installed or isn't on mobile, then the corresponding webpage can be opened in the browser. On iOS, deeplinks are called universal links but we'll keep the term deeplink because it is more general.

A push notification is a piece of data that can be sent from a backend to a mobile device. It often provides information to the user and can also encourage them to act. For example, a football app may send push notifications to its users whenever a player is transferred from one club to another. By tapping on the push notification, the user would expect the app to open a screen that shows information about the transfer.

Both deeplinks and push notifications are a good way to enrich an app. As the action performed when opening a deeplink or when tapping a push notification is often the same, it makes sense to create a single module for handling both structures.

A simple example app that uses deeplinks and universal links

To keep the implementation concrete, we choose to design the module for a fictional recipe app called bestrecipes. This app could for example contain recipes that are posted by chefs, a way for the user to follow chefs, a grading system for the recipes...

We'll focus on implementing deeplinks and push notifications that can either link to a home feed or to a "recipes" screen. Here are some examples of possible deeplinks and push notifications:

Home

Deeplink: https://bestrecipes.com/home

Push notification:

Recipe by id

Deeplink: https://bestrecipes.com/recipe?id=1234

Push notification:

Recipes by country and with a limit

Deeplink: https://bestrecipes.com/recipe?country=FR&limit=7

Push notification:

A single module for handling deeplinks and push notifications

The following picture is a UML class diagram of the module:

app_linkerWe'll study the various parts of the module in the following sections:

Models

As deeplinks and push notifications can be used to perform the same actions, they should also be able to contain the same information. So, instead of creating a model for deeplinks and one for push notifications, we abstract the concepts in a Payload structure:

As you can see, a Payload keeps a dictionary of parameters and has a field of type Target, which is just an enum that lists all the possible screens that can be reached by a deeplink or a push notification:

In our example, we only support two screens (home and recipes) but we can always extend the module by adding more cases.

Parsing

The first action the module should perform is to parse the incoming deeplink or push notification into an instance of Payload. To do so, we define a protocol that describes the ability to parse an object into a Payload:

The associated type corresponds to the input type of the parser. For example, the following classes are implementations of Parser whose associated types are respectively URL and [String: String]:

On a side note, the classes and protocols responsible for producing payloads are an example of implementation of the strategy pattern.

Handling payloads

Once the parsing has been done, the next step is to perform the action associated with the parsed payload. To do so, we create a simple PayloadHandler class:

Putting things together

The final step is to combine the parsing and the creation of actions in a single place. Thus, we create an AppLinker which should be the entry point of the module:

The code is pretty simple: AppLinker has two public methods, one for handling deeplinks and the other for handling push notifications. Both methods start by parsing their input into a Payload that is then used by the PayloadHandler to perform the associated action.

Conclusion

The goal of this article was to provide a possible way to architecture a single module for handling both deeplinks and push notifications. There is certainly room for improvement but the code that is presented should constitute a solid start.

To receive the content of a deeplink or a push notification on iOS, there are several steps to follow, including overwriting functions in the AppDelegate or the SceneDelegate depending on what you're using. For more information, see this article for implementing deeplinks and this one for push notifications.

Finally, I would like to thank David Rico. We worked together on the module and I learned a lot by working with him.