Skip to content

android: extend support for protocol navigation to Android#815

Open
willh-ts wants to merge 1 commit into
mainfrom
will/navigate
Open

android: extend support for protocol navigation to Android#815
willh-ts wants to merge 1 commit into
mainfrom
will/navigate

Conversation

@willh-ts

@willh-ts willh-ts commented Jun 29, 2026

Copy link
Copy Markdown

Extends support for the navigate path of the tailscale: protocol to Android,
mirroring the existing macOS routes & pending iOS routes.

All settings tabs without existing routes simply open the main settings view
for now.

tailscale://navigate/main/devices
tailscale://navigate/main/devices/<computedName or stableID>
tailscale://navigate/main/exit-nodes
tailscale://navigate/main/exit-nodes/<stableID>
tailscale://navigate/main/exit-nodes/location/<country>
tailscale://navigate/settings[/<anyTab>]

The scripts/deeplink-probe.go script can be used to trigger the application to
navigate to a given route by passing that to it.
e.g., ./tool/go run ./scripts/deeplink-probe.go main/devices

updates tailscale/corp#41056

@willh-ts willh-ts requested review from barnstar and kari-ts June 29, 2026 18:50
@willh-ts willh-ts force-pushed the will/navigate branch 2 times, most recently from 2334b8a to 88f4d5d Compare June 30, 2026 14:10

@barnstar barnstar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mainly, I think we need to be really conservative on performing actions with deeplinks (and perhaps audit iOS/macOS if we allow that there). Navigation is perfectly fine, but the idea that clicking a link can change what exit node I'm using has some implications we need to consider before rolling it out.

Comment thread android/src/main/java/com/tailscale/ipn/ui/util/DeepLinkNavigator.kt Outdated
Comment thread android/src/main/java/com/tailscale/ipn/ui/util/DeepLinkNavigator.kt Outdated
Comment thread scripts/deeplink-probe.sh Outdated
@willh-ts willh-ts requested a review from barnstar July 2, 2026 15:08

@kari-ts kari-ts left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for doing this!

}

private fun presentSettings() {
popToMain()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this won't work if main isn't in the backstack, eg if a settings deep link is handled on cold start

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe something liek this?

private fun presentSettings() {
  navController.navigate("settings") {
    popUpTo("main") { inclusive = false }
    launchSingleTop = true
  }
}

https://developer.android.com/guide/navigation/backstack#pop

}

private fun popToMain() {
navController.popBackStack(route = "main", inclusive = false)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe check the return value and log if this fails?

}
1 -> {
pushDeviceDetail(rest[0])
true

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this returns true even if the node is missing, is this intended?

?: all.firstOrNull { it.StableID == identifier }
}

private fun presentExitNodePicker() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this sounds a little Apple-y. I think Android tends to use "show"

}
}

private fun navigateUri(intent: Intent?): Uri? {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe rename, since this doesn't actually navigate? this just extracts a uri from the intent, so maybe something liek deepLinkUri for clarity?

Comment thread android/src/main/java/com/tailscale/ipn/MainActivity.kt Outdated
onNavigateHome = backTo("main"), backTo("userSwitcher"))
}
}
if (isIntroScreenViewedSet()) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how does/should this interact with deep linking? eg, if deep linking happens without having viewed the intro screen?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good call out and I suspect we have the same issue on both iOS and mac. It could make sense in all three cases to gate the DeepLink router on our intro/onboarding properties, ignoring the navigation request if the intro screens haven't yet been marked as seen. I updated MainActivity's pendingDeepLink handler to do that here.

Extends support for the `navigate` path of the `tailscale:` protocol to Android,
mirroring the existing macOS routes & pending iOS routes.

All settings tabs without existing routes simply open the main settings view
for now.

```
tailscale://navigate/main/devices
tailscale://navigate/main/devices/<computedName or stableID>
tailscale://navigate/main/exit-nodes
tailscale://navigate/main/exit-nodes/<stableID>
tailscale://navigate/main/exit-nodes/location/<country>
tailscale://navigate/settings[/<anyTab>]
```

The `scripts/deeplink-probe.sh` script can be used to trigger the application to
navigate to a given route by passing that to it.
e.g., `./tool/go run ./scripts/deeplink-probe.go main/devices`

updates tailscale/corp#41056

Signed-off-by: Will Hannah <willh@tailscale.com>
@willh-ts willh-ts requested a review from kari-ts July 2, 2026 20:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants