Utilise Android Navigation component to handle deep links with a splash screen activity
Asked Answered
W

1

7

I have an app with two activities, a splash screen activity and another that contains the main navgraph for the app.

I was wanting to utilise the new deep linking handling that comes with the Android Navigation Component. However following the Google tutorial, the Splash screen is skipped when clicking the link and dives straight into the navgraph for the app.

Is there any way to use these new features, whilst still forcing the splash screen to be shown first before navigating to the correct part of the app?

Weymouth answered 10/9, 2019 at 21:40 Comment(2)
Do you want to show the splash screen before correct part of the app or not (using nav component)?Veliavelick
Thanks for your reply @HemantSharma.The requirement was to show the splash screen first (without navigation component), then pass deep link onto main activity (which has navigation component). Came to a solution in the end (see below post).Weymouth
W
15

Posting the solution that I came to here in case anyone else has the same requirements.

It was actually pretty simple in the end! In the splash screen activity, catch the pendingDynamicLinkData as below:

private fun decideNextDestination() {
       FirebaseDynamicLinks.getInstance()
          .getDynamicLink(intent)
          .addOnSuccessListener(this) { pendingDynamicLinkData ->
              val deepLink = pendingDynamicLinkData?.link
              if (deepLink == null) navigateToMain() else deepLinkToDestination(deepLink)
          }
          .addOnFailureListener(this) { navigateToMain() }
}

Then in the deepLinkToDestination method, build an intent and add a bundle with the deeplink URI to pass along (Android Uri implements parcelable so can pass with no issues):

private fun deepLinkToDestination(deepLink: Uri) {
    val bundle = Bundle().apply { putParcelable(DEEP_LINK_PARAM_KEY, deepLink) }
    val intent = Intent(this, NavHostActivity::class.java).apply { putExtras(bundle) }
    startActivity(intent)
    finish()
}

Then in onCreate of the destination activity, grab the deep link, cast to Uri and navigate using implicit deep links (see docs https://developer.android.com/guide/navigation/navigation-deep-link#implicit) as below:

private fun handleDeepLink() {
    val deepLink = intent.extras?.getParcelable(DEEP_LINK_PARAM_KEY) as? Uri
    deepLink?.let { navController.safeNavigateToDeepLink(deepLink) }
}

I created an extension function for NavController, safeNavigateToDeepLink(deepLink), to check if the navGraph has reference to that deep link (as suggested in the navigation component source code), then if this can't be found, to navigate to a default destination:

fun NavController.safeNavigateToDeepLink(uri: Uri) {
    if (graph.hasDeepLink(uri)) navigate(uri)
    else safeNavigateTo(R.id.home)
}

If it helps anyone else, the other extension function in there is the below, which just checks that an action to navigate to that destination can be found before navigating:

fun NavController.safeNavigateTo(id: Int) {
    val action = currentDestination?.getAction(id)
    action?.let { navigate(id) }
}
Weymouth answered 19/9, 2019 at 7:56 Comment(3)
And what about explicit deep linking in same scenarios?Conceit
This way you need to manually declare an intent filter in the manifest of you launching activity, right? SInce <nav-graph android:value="@navigation/nav_graph" /> won't work.Visibility
pendingDynamicLinkData always is null any idea why?Lucho

© 2022 - 2024 — McMap. All rights reserved.