Blog Infos
Author
Published
Topics
Published

This article is for those who are faced with the choice of implementing their own solution for processing deep links in Android app, or using what Google offers in the Navigation Component.

Recently, I needed to implement opening various app screens from the outside using deep links on one of the small projects, I wanted to try and understand what the guys from Google could come up with for deep linking, given how they talk beautifully about it in their presentations and documentation.

Next, I will describe the disadvantages that I had to face, and why I will no longer use deep linking from the Navigation Component.

Missing way to specify the host via manifest placeholder

The application used two build types for staging and production, respectively, each of them needs a different host, both for the API and for deep linking. It turned out that it is impossible to do this in a universal way, for example like this:

<fragment
android:id="@+id/favorites_fragment"
android:name="com.company.FavoritesFragment">
<deepLink app:uri="${deepLinkHost}/customer/favorites" />
</fragment>

I didn’t find a suitable solution how to get around this, and I had to specify the same deepLink twice:

<fragment
android:id="@+id/favorites_fragment"
android:name="com.company.FavoritesFragment">
<deepLink app:uri="company.com/customer/favorites" />
<deepLink app:uri="staging-company.com/customer/favorites" />
</fragment>

Far from ideal, because you have to duplicate deepLink, it’s easy to forget something, and besides, on the basis of this, intent filters will be generated in AndroidManifest.xml for both hosts, which I wouldn’t really like for prod build, so as not to increase its size and not reveal information about the staging host. The issue of this problem has been hanging in the Google tracker for several years as Won't fix (Infeasible), in another issue, it was reported that they added support for manifest placeholders for deepLink in AGP 7.3.0-alpha08, and now you can do this:

  • specify scheme and host in build.gradle:
staging {
manifestPlaceholders = [scheme: "https", host: "staging-company.com"]
}
prod {
manifestPlaceholders = [scheme: "https", host: "company.com"]
}
view raw build.gradle hosted with ❤ by GitHub
  • and use them in the deepLink tag:
<deepLink app:uri="${scheme}://${host}/customer/favorites" />

But navigation through such a deep link stops working, apparently, the alpha version of AGP makes itself felt, but there is hope that this will be fixed in a stable release.

Necessary to specify deep links in xml

At first glance, it seemed convenient to me, since deepLink is indicated directly where it refers to. But in practice, no, if you have several graphs, then all deep links are scattered across different xml files and complicate their already complicated structure, and together with the inability to specify the host of deeplinks through the manifest placeholder, the fragments with several deeplinks have become look bulky:

<fragment
android:id="@+id/video_fragment"
android:name="com.company.VideoFragment">
<deepLink android:autoVerify="true" app:uri="company.com/videos/{videoId}" />
<deepLink android:autoVerify="true" app:uri="company.com/.*/videos/{videoId}" />
<deepLink android:autoVerify="true" app:uri="company.com/.*/collections/videos/{videoId}" />
<deepLink android:autoVerify="true" app:uri="company.com/user/videos/{videoId}" />
<deepLink android:autoVerify="true" app:uri="staging-company.com/videos/{videoId}" />
<deepLink android:autoVerify="true" app:uri="staging-company.com/.*/videos/{videoId}" />
<deepLink android:autoVerify="true" app:uri="staging-company.com/.*/collections/videos/{videoId}" />
<deepLink android:autoVerify="true" app:uri="staging-company.com/user/videos/{videoId}" />
...
</fragment>

Job Offers

Job Offers


    Mobile Engineer

    OLX Group
    Remote, Portugal, Spain, Romania, Poland
    • Full Time
    apply now

    Android Software Engineer (f/m/d)

    Paradox Cat GmbH
    Munich
    • Full Time
    apply now

    Senior Android Software Engineer (f/m/d)

    Paradox Cat GmbH
    Munich
    • Full Time
    apply now
Load more listings

OUR VIDEO RECOMMENDATION

,

Breaking the Rules: Dynamic Navigation in Modularized Apps

Properly handled navigation is critical for modularized apps, which often implement navigation logic at runtime. This presents certain challenges when working with the Navigation Components library:
Watch Video

Breaking the Rules: Dynamic Navigation in Modularized Apps

Sumayyah Ahmed
Senior Android Engineer

Breaking the Rules: Dynamic Navigation in Modularized Apps

Sumayyah Ahmed
Senior Android Engin ...

Breaking the Rules: Dynamic Navigation in Modularized Apps

Sumayyah Ahmed
Senior Android Engineer

Jobs

You need to add autoVerify to each deep link separately

It looks like in the previous example, you need to specify android:autoVerify="true" for each deepLink separately, if necessary for it to work as Android App Links. But before, it was possible to set up one intent-filter for all deeplinks of one host and specify autoVerify for them once.

Missing possibility to configure a priority for deep links with the same structure

I faced this problem when I needed to specify a deepLink with the same structure for fragments in the Bottom Navigation and in the main application graph.

For example, in the Bottom Navigation graph there was a user profile screen that could be opened with different params:

<fragment
android:id="@+id/profile_fragment"
android:name="com.company.ProfileFragment">
<deepLink app:uri="company.com/user/.*" />
...
</fragment>

and in the main graph there was a user’s subscriptions screen:

<fragment
android:id="@+id/subscriptions_fragment"
android:name="com.company.SubscriptionsFragment">
<deepLink app:uri="company.com/user/subscriptions" />
</fragment>

As a result, when opening the link https://company.com/user/subscriptions, both deepLinks were handled. I would like to be able to somehow indicate the priorities or a strategy for resolving conflicts in such cases.

Using only default launchMode is recommended

Google strongly recommends only using android:launchMode="standard" so that handleDeepLink() is called automatically when the graph is set up. Otherwise, you will need to do it manually by overriding the onNewIntent() method of the activity:

override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
navController.handleDeepLink(intent)
}

But when I tried to do this and use singleTop, I understood why Google strongly recommends the opposite. In this case, after opening the first deep link, opening subsequent ones does nothing, just opens the application with a screen for the previous deep link until the activity is recreated.

Clearing the backstack before opening a deep link

This problem has already been discussed in other articles and found out that this is afeature, but not a bug. The documentation also includes a description of the behavior.

But for a deep link that opens a screen in the Bottom Navigation graph, this looks like a bug, because when switching to another tab, we can see the same screen that the deep link opened before since by default the backstack for this tab does not save state. There is an issue in their tracker in the Won't fix (Intended behavior) status, that is, they consider this behavior intentional.

Сonclusions

In my experience, it’s much easier to implement your own DeepLinkHandler and have more freedom and flexibility than to constantly look for ways to work around the Navigation Component’s problems. The implementation of deep linking in the Navigation Component still leaves much to be desired, and it has a number of drawbacks and specific issues, and it is more suitable only for simple cases or small applications.

Unfortunately, there haven’t been any significant improvements over the past few years, and it looks like this feature wasn’t quite well designed from the start.

Since Compose is already on the heels and gaining popularity, I hope they will take into account past experience and finalize deep linking and navigation for it at least.

This is a translation of my article.

This article was originally published on proandroiddev.com on September 02, 2022

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
I recently found a bug that would cause a crash in all the apps…
READ MORE
blog
Typically apps go from the navigation bar to the status bar. With the release…
READ MORE
blog
It’s been about a year since Google announced Jetpack Compose’s 1.0 stable release, meaning…
READ MORE
blog

Edge-to-edge support for your Android app with Insetter

READ MORE

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

Menu