Search code examples
androidnavigationcomponentssplash-screendeep-linking

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


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?


Solution

  • 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) }
    }