From f2ff5dfecaa3cb95f4a7809f0fb6a13e8b9bc90d Mon Sep 17 00:00:00 2001 From: Jamil Date: Wed, 17 Sep 2025 23:37:03 -0400 Subject: [PATCH] fix(android): launch auth in CustomTab (#10371) Unfortunately, Firefox on Android seems to have a bug where it only allows one tab to intercept the custom URI scheme handler for our auth redirect. This causes an issue where the first sign in works, but subsequent ones do not because that first tab is still open. Luckily the fix here is quite simple. By using Android's CustomTabs to launch the activity, only one, sandboxed instance is ever open and the URI intercept works reliably. Both Firefox and Chrome (and likely other browsers) support CustomTabs, which means the user's default browser is used, allowing cookies, password managers, etc to be used. Related to this, this PR also fixes a bug where dismissing the launched auth flow would result in it immediately relaunching, making it impossible to get back to the app unless you force quit or complete the sign in process. Fixes #10318 --- .../android/features/auth/ui/AuthActivity.kt | 32 +++++++++++++++---- website/src/components/Changelog/Android.tsx | 4 +++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/kotlin/android/app/src/main/java/dev/firezone/android/features/auth/ui/AuthActivity.kt b/kotlin/android/app/src/main/java/dev/firezone/android/features/auth/ui/AuthActivity.kt index 86a94403a..248091249 100644 --- a/kotlin/android/app/src/main/java/dev/firezone/android/features/auth/ui/AuthActivity.kt +++ b/kotlin/android/app/src/main/java/dev/firezone/android/features/auth/ui/AuthActivity.kt @@ -1,12 +1,14 @@ /* Licensed under Apache 2.0 (C) 2024 Firezone, Inc. */ package dev.firezone.android.features.auth.ui +import android.content.ActivityNotFoundException import android.content.Intent import android.net.Uri import android.os.Bundle import androidx.activity.viewModels import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity +import androidx.browser.customtabs.CustomTabsIntent import dagger.hilt.android.AndroidEntryPoint import dev.firezone.android.R import dev.firezone.android.core.presentation.MainActivity @@ -16,6 +18,7 @@ import dev.firezone.android.databinding.ActivityAuthBinding class AuthActivity : AppCompatActivity(R.layout.activity_auth) { private lateinit var binding: ActivityAuthBinding private val viewModel: AuthViewModel by viewModels() + private var hasLaunchedCustomTab = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -27,7 +30,12 @@ class AuthActivity : AppCompatActivity(R.layout.activity_auth) { override fun onResume() { super.onResume() - viewModel.onActivityResume() + if (hasLaunchedCustomTab) { + // User returned from Custom Tab without completing auth, navigate back to main app + navigateToSignIn() + } else { + viewModel.onActivityResume() + } } private fun setupActionObservers() { @@ -43,12 +51,24 @@ class AuthActivity : AppCompatActivity(R.layout.activity_auth) { } } - // We can't close this webview because it's opened with ACTION_VIEW. - // If we want more control over it we need to embed our own WebView which - // has its own set of tradeoffs. private fun setupWebView(url: String) { - val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) - startActivity(intent) + hasLaunchedCustomTab = true + val customTabsIntent = + CustomTabsIntent + .Builder() + .setShowTitle(true) + .build() + val url = Uri.parse(url) + + // Try to use Custom Tabs with the default browser first + try { + customTabsIntent.launchUrl(this, url) + } catch (e: ActivityNotFoundException) { + // Fallback to default browser if Custom Tabs unavailable + val intent = Intent(Intent.ACTION_VIEW, url) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + startActivity(intent) + } } private fun navigateToSignIn() { diff --git a/website/src/components/Changelog/Android.tsx b/website/src/components/Changelog/Android.tsx index 5a453eb79..b21bffbf1 100644 --- a/website/src/components/Changelog/Android.tsx +++ b/website/src/components/Changelog/Android.tsx @@ -21,6 +21,10 @@ export default function Android() { {/* When you cut a release, remove any solved issues from the "known issues" lists over in `client-apps`. This must not be done when the issue's PR merges. */} + + Fixes a bug that could prevent sign-ins from completing successfully + if Firefox is set as the default browser. + Fixes an issue where DNS resources would resolve to a different IP after signing out and back into Firezone. This would break