Sparround

Navigation Component & deep links

The Navigation Component replaces manual fragment transactions:

  • The nav graph — screens (destinations) and transitions (actions) in one XML/Kotlin graph
  • NavControllernavigate(action), popBackStack() — it owns the back stack
  • Safe Args — generated type-safe Directions classes for arguments: string Bundle-key mistakes become compile errors

Deep links — jumping straight to a screen from a URL:

  • Explicit deep links — via PendingIntent (from notifications)
  • Implicit deep links<deepLink app:uri="bank://transfer/{id}"/> in the graph + a nav-graph element in the manifest; the system maps the URI to a destination and builds a synthetic back stack
  • App Links — verified ownership of https URLs (assetlinks.json): the link opens in-app with no chooser

In banking, deep links are risky entry points: if the target requires auth, the link must pass through auth, never jump straight to content.

kotlin
// nav_graph.xml-də:
// <fragment android:id="@+id/transactionDetail" ...>
//     <argument android:name="txId" app:argType="string"/>
//     <deepLink app:uri="bank://tx/{txId}"/>
// </fragment>

// Göndərən tərəf — string açar yox, generasiya olunmuş Directions:
findNavController().navigate(
    FeedFragmentDirections.actionFeedToTransactionDetail(txId = tx.id)
)

// Qəbul edən tərəf:
private val args: TransactionDetailFragmentArgs by navArgs()
// args.txId — tipli, null-safe

Type-safe navigation with Safe Args

The auth-gated deep link pattern: when a link arrives and the user is not logged in, store the target route → redirect to login → continue to the stored route after successful auth. Same principle in Compose Navigation. One more rule: never trust deep link parameters — if a transaction id arrives, the server must verify it belongs to this user (the mobile face of IDOR).

🛠 Practice task

Build a 3-screen graph with the Navigation Component and pass arguments via Safe Args.

  • Add a deep link to one destination (app://demo/tx/{id}) and open it with adb shell am start -a android.intent.action.VIEW -d "app://demo/tx/42".
  • Press back — observe how the synthetic back stack behaves.
  • Then add a "login required" gate: store the target route and resume after login.

Done when: the deep link cannot bypass auth and the back button behaves sensibly.

📚 Sources and documentation