[PWA/NavCapture]: Create `NavigationCapturingSettings` interface
This CL aims to align CrOS and W/M/L link capturing architecture.
Currently, CrOS does not interact with the same link capturing
architecture as W/M/L since it does not set the link capturing
preferences for web_apps in the DB.
Creating a NavigationCapturingSettings interface that both W/M/L and
CrOS will have their own implementation. This is constructed as part of
the navigation_capturing_process.
The implementation for W/M/L and CrOS is taken from
GetWebAppControllingUrl which can then be removed.
More information found in design document:
https://docs.google.com/document/d/11KjFz_sUmXsPwzLRWGYEOVPV0oK1G7H2wz57EKLPmn8/edit?tab=t.0
Bug: 392712186
Change-Id: I5b1d369769a31bbaa87ca44408276212f3b5ac41
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6230494
Reviewed-by: Daniel Murphy <[email protected]>
Reviewed-by: Marijn Kruisselbrink <[email protected]>
Commit-Queue: May Siem <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1418878}
diff --git a/chrome/browser/apps/link_capturing/BUILD.gn b/chrome/browser/apps/link_capturing/BUILD.gn
index 755ba96..ea4caa0 100644
--- a/chrome/browser/apps/link_capturing/BUILD.gn
+++ b/chrome/browser/apps/link_capturing/BUILD.gn
@@ -53,6 +53,8 @@
"chromeos_reimpl_navigation_capturing_throttle.h",
"metrics/intent_handling_metrics.cc",
"metrics/intent_handling_metrics.h",
+ "navigation_capturing_settings_cros_impl.cc",
+ "navigation_capturing_settings_cros_impl.h",
]
deps += [
"//ash/webui/projector_app/public/cpp",
@@ -84,15 +86,9 @@
}
source_set("features") {
- sources = [
- "link_capturing_features.cc",
- "link_capturing_features.h",
- ]
+ sources = [ "link_capturing_features.h" ]
public_deps = [ "//base" ]
- deps = [
- "//chrome/common:chrome_features",
- "//content/public/common",
- ]
+ deps = [ "//chrome/browser/web_applications:web_applications" ]
}
source_set("test_support") {
diff --git a/chrome/browser/apps/link_capturing/link_capturing_features.h b/chrome/browser/apps/link_capturing/link_capturing_features.h
index 3df3f79c..6166a8a 100644
--- a/chrome/browser/apps/link_capturing/link_capturing_features.h
+++ b/chrome/browser/apps/link_capturing/link_capturing_features.h
@@ -5,26 +5,9 @@
#ifndef CHROME_BROWSER_APPS_LINK_CAPTURING_LINK_CAPTURING_FEATURES_H_
#define CHROME_BROWSER_APPS_LINK_CAPTURING_LINK_CAPTURING_FEATURES_H_
-#include "base/feature_list.h"
-#include "build/build_config.h"
-
-namespace apps::features {
-
-// Returns true if the updated UX for link capturing needs to be shown. Only set
-// to true on desktop platforms if kPwaNavigationCapturing is enabled, and
-// always on CrOS.
-bool ShouldShowLinkCapturingUX();
-
-// Returns true if the `kPwaNavigationCapturing` flag is enabled with the
-// reimplementation parameters set.
-//
-// NOTE: the reimplementation can also be enabled for particular applications
-// even if this flag is off. Hence only the `true` return value can be fully
-// trusted, but if `false` is returned extra considerations are required. See
-// `IsNavigationCapturingReimplExperimentEnabled()` at
-// //c/b/ui/web_applications/web_app_launch_utils.cc.
-bool IsNavigationCapturingReimplEnabled();
-
-} // namespace apps::features
+// TODO(msiem): Refactor references to reference
+// "chrome/browser/web_applications/link_capturing_features.h" and remove this
+// file.
+#include "chrome/browser/web_applications/link_capturing_features.h"
#endif // CHROME_BROWSER_APPS_LINK_CAPTURING_LINK_CAPTURING_FEATURES_H_
diff --git a/chrome/browser/apps/link_capturing/navigation_capturing_settings_cros_impl.cc b/chrome/browser/apps/link_capturing/navigation_capturing_settings_cros_impl.cc
new file mode 100644
index 0000000..3e164d9
--- /dev/null
+++ b/chrome/browser/apps/link_capturing/navigation_capturing_settings_cros_impl.cc
@@ -0,0 +1,54 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/apps/link_capturing/navigation_capturing_settings_cros_impl.h"
+
+#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
+#include "chrome/browser/apps/app_service/launch_utils.h"
+#include "chrome/browser/web_applications/chromeos_web_app_experiments.h"
+
+namespace web_app {
+
+std::unique_ptr<NavigationCapturingSettings>
+NavigationCapturingSettings::Create(Profile& profile) {
+ return std::make_unique<NavigationCapturingSettingsCrosImpl>(profile);
+}
+
+NavigationCapturingSettingsCrosImpl::NavigationCapturingSettingsCrosImpl(
+ Profile& profile)
+ : profile_(profile) {}
+
+NavigationCapturingSettingsCrosImpl::~NavigationCapturingSettingsCrosImpl() =
+ default;
+
+std::optional<webapps::AppId>
+NavigationCapturingSettingsCrosImpl::GetCapturingWebAppForUrl(const GURL& url) {
+ if (!apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(
+ &profile_.get())) {
+ return std::nullopt;
+ }
+
+ return apps::FindAppIdsToLaunchForUrl(
+ apps::AppServiceProxyFactory::GetForProfile(&profile_.get()), url)
+ .preferred;
+}
+
+// This is needed on ChromeOS to support the ChromeOsWebAppExperiments
+// code, see ChromeOsWebAppExperimentsNavigationBrowserTest for tests with
+// this on.
+bool NavigationCapturingSettingsCrosImpl::
+ ShouldAuxiliaryContextsKeepSameContainer(
+ const std::optional<webapps::AppId>& source_browser_app_id,
+ const GURL& url) {
+ if (source_browser_app_id.has_value() &&
+ ChromeOsWebAppExperiments::IsNavigationCapturingReimplEnabledForSourceApp(
+ *source_browser_app_id, url)) {
+ return true;
+ }
+
+ return NavigationCapturingSettings::ShouldAuxiliaryContextsKeepSameContainer(
+ source_browser_app_id, url);
+}
+
+} // namespace web_app
diff --git a/chrome/browser/apps/link_capturing/navigation_capturing_settings_cros_impl.h b/chrome/browser/apps/link_capturing/navigation_capturing_settings_cros_impl.h
new file mode 100644
index 0000000..7239a78
--- /dev/null
+++ b/chrome/browser/apps/link_capturing/navigation_capturing_settings_cros_impl.h
@@ -0,0 +1,48 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_APPS_LINK_CAPTURING_NAVIGATION_CAPTURING_SETTINGS_CROS_IMPL_H_
+#define CHROME_BROWSER_APPS_LINK_CAPTURING_NAVIGATION_CAPTURING_SETTINGS_CROS_IMPL_H_
+
+#include "base/memory/raw_ref.h"
+#include "chrome/browser/web_applications/navigation_capturing_settings.h"
+
+class Profile;
+
+namespace web_app {
+
+// This is created in the `NavigationCapturingSettings::Create` method, called
+// in `NavigationCapturingProcess`.
+//
+// ChromeOS uses a different source of truth for storing the preferred
+// application to capture navigations given a url, as it was implemented first
+// and it has to also deal with ARC++ apps. This specialization queries that
+// instead of the WebAppRegistrar.
+class NavigationCapturingSettingsCrosImpl : public NavigationCapturingSettings {
+ public:
+ explicit NavigationCapturingSettingsCrosImpl(Profile& profile);
+ ~NavigationCapturingSettingsCrosImpl() override;
+ NavigationCapturingSettingsCrosImpl(
+ const NavigationCapturingSettingsCrosImpl&) = delete;
+ NavigationCapturingSettingsCrosImpl& operator=(
+ const NavigationCapturingSettingsCrosImpl&) = delete;
+
+ std::optional<webapps::AppId> GetCapturingWebAppForUrl(
+ const GURL& url) override;
+
+ // Allows ChromeOS to sometimes disable auxiliary browser context handling in
+ // the NavigationCapturingProcess, as ChromeOsWebAppExperiments has some
+ // custom handling for auxiliary `about:blank` urls that then redirect.
+ // Otherwise falls back to default implementation.
+ bool ShouldAuxiliaryContextsKeepSameContainer(
+ const std::optional<webapps::AppId>& source_browser_app_id,
+ const GURL& url) override;
+
+ private:
+ raw_ref<Profile> profile_;
+};
+
+} // namespace web_app
+
+#endif // CHROME_BROWSER_APPS_LINK_CAPTURING_NAVIGATION_CAPTURING_SETTINGS_CROS_IMPL_H_
diff --git a/chrome/browser/ui/web_applications/navigation_capturing_process.cc b/chrome/browser/ui/web_applications/navigation_capturing_process.cc
index b81a0e0..dcf3156 100644
--- a/chrome/browser/ui/web_applications/navigation_capturing_process.cc
+++ b/chrome/browser/ui/web_applications/navigation_capturing_process.cc
@@ -18,6 +18,7 @@
#include "chrome/browser/ui/web_applications/web_app_launch_navigation_handle_user_data.h"
#include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
#include "chrome/browser/web_applications/navigation_capturing_log.h"
+#include "chrome/browser/web_applications/navigation_capturing_settings.h"
#include "chrome/browser/web_applications/web_app_helpers.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
@@ -26,8 +27,6 @@
#include "content/public/common/content_features.h"
#if BUILDFLAG(IS_CHROMEOS)
-#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
-#include "chrome/browser/apps/app_service/launch_utils.h"
#include "chrome/browser/web_applications/chromeos_web_app_experiments.h"
#endif
@@ -37,53 +36,6 @@
namespace {
-// Causes all new auxiliary browser contexts to share the same window container
-// type as where they were created from. For example, if an aux context was
-// created from standalone PWA, then the new context will be created in a new
-// window of the same PWA.
-// If this is off, then all auxiliary contexts will be created as browser tabs.
-const base::FeatureParam<bool> kEnableAuxContextKeepSameContainer{
- &features::kPwaNavigationCapturing, "aux_context_keep_same_container",
- /*default_value=*/false};
-
-// Keeping auxiliary contexts in an 'app' container was causing problems on
-// initial Canary testing, see https://crbug.com/379181271 for more information.
-// Either this will be rolled out separately or removed.
-bool ShouldDisableAuxiliaryBrowsingContextHandling(
- const std::optional<webapps::AppId>& source_browser_app_id,
- const GURL& url) {
- // This is however needed on ChromeOS to support the ChromeOsWebAppExperiments
- // code, see ChromeOsWebAppExperimentsNavigationBrowserTest for tests with
- // this on.
-#if BUILDFLAG(IS_CHROMEOS)
- if (source_browser_app_id.has_value() &&
- ::web_app::ChromeOsWebAppExperiments::
- IsNavigationCapturingReimplEnabledForSourceApp(*source_browser_app_id,
- url)) {
- return true;
- }
-#endif
- return apps::features::IsNavigationCapturingReimplEnabled() &&
- kEnableAuxContextKeepSameContainer.Get();
-}
-
-std::optional<webapps::AppId> GetWebAppControllingUrl(
- Profile& profile,
- const WebAppProvider* provider,
- const GURL& url) {
-#if BUILDFLAG(IS_CHROMEOS)
- if (!apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(
- &profile)) {
- return std::nullopt;
- }
- return apps::FindAppIdsToLaunchForUrl(
- apps::AppServiceProxyFactory::GetForProfile(&profile), url)
- .preferred;
-#else
- return provider->registrar_unsafe().FindAppThatCapturesLinksInScope(url);
-#endif
-}
-
bool IsDispositionValidForNavigationCapturing(
WindowOpenDisposition disposition) {
switch (disposition) {
@@ -275,6 +227,8 @@
WebAppProvider* provider = WebAppProvider::GetForWebApps(&*profile_);
CHECK(provider);
web_app::WebAppRegistrar& registrar = provider->registrar_unsafe();
+ navigation_capturing_settings_ =
+ NavigationCapturingSettings::Create(*profile_);
debug_data_.Set("referrer.url", params.referrer.url.possibly_invalid_spec());
debug_data_.Set("source_contents.url",
@@ -302,7 +256,8 @@
debug_data_.Set("is_user_modified_click", is_user_modified_click());
first_navigation_app_id_ =
- GetWebAppControllingUrl(profile_.get(), provider, params.url);
+ navigation_capturing_settings_->GetCapturingWebAppForUrl(params.url);
+
debug_data_.Set("controlling_app_id",
first_navigation_app_id_.value_or("<none>"));
if (first_navigation_app_id_) {
@@ -511,8 +466,9 @@
// app browser.
if (IsAuxiliaryBrowsingContext(params)) {
debug_data_.Set("is_auxiliary_browsing_context", true);
- if (!ShouldDisableAuxiliaryBrowsingContextHandling(source_browser_app_id_,
- params.url)) {
+ if (!navigation_capturing_settings_
+ ->ShouldAuxiliaryContextsKeepSameContainer(source_browser_app_id_,
+ params.url)) {
return CapturingDisabled();
}
if (source_browser_app_id_.has_value()) {
@@ -737,7 +693,7 @@
WebAppProvider::GetForWebContents(web_contents_for_navigation);
WebAppRegistrar& registrar = provider->registrar_unsafe();
std::optional<webapps::AppId> target_app_id =
- GetWebAppControllingUrl(profile_.get(), provider, final_url);
+ navigation_capturing_settings_->GetCapturingWebAppForUrl(final_url);
// "Same first navigation state" case:
// First, we can exit early if the first navigation app id matches the target
diff --git a/chrome/browser/ui/web_applications/navigation_capturing_process.h b/chrome/browser/ui/web_applications/navigation_capturing_process.h
index c4d218f..9d20a82 100644
--- a/chrome/browser/ui/web_applications/navigation_capturing_process.h
+++ b/chrome/browser/ui/web_applications/navigation_capturing_process.h
@@ -22,6 +22,8 @@
namespace web_app {
+class NavigationCapturingSettings;
+
// This class encompasses all of the logic for navigations in the browser to be
// captured into installed web app launches.
//
@@ -211,6 +213,8 @@
PipelineState state_ = PipelineState::kCreated;
+ std::unique_ptr<NavigationCapturingSettings> navigation_capturing_settings_;
+
// These fields are copied or derived from the NavigateParams of the original
// navigation.
const raw_ref<Profile> profile_;
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index b63b165..bafa171e 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -205,6 +205,8 @@
"jobs/uninstall/uninstall_job.cc",
"jobs/uninstall/uninstall_job.h",
"jobs/uninstall/web_app_uninstall_and_replace_job.h",
+ "link_capturing_features.cc",
+ "link_capturing_features.h",
"locks/all_apps_lock.cc",
"locks/all_apps_lock.h",
"locks/app_lock.cc",
@@ -235,6 +237,8 @@
"manifest_update_utils.h",
"navigation_capturing_log.cc",
"navigation_capturing_log.h",
+ "navigation_capturing_settings.cc",
+ "navigation_capturing_settings.h",
"os_integration/file_handling_sub_manager.cc",
"os_integration/file_handling_sub_manager.h",
"os_integration/os_integration_manager.cc",
@@ -468,6 +472,13 @@
]
}
+ if (!is_chromeos) {
+ sources += [
+ "navigation_capturing_settings_impl.cc",
+ "navigation_capturing_settings_impl.h",
+ ]
+ }
+
# Enable the "exit_time_destructors" warning here to avoid accidentally
# adding exit time destructors and because the flag is not enabled by default.
# TODO(http://crbug.com/101600): Remove once exit_time_destructors is enabled
diff --git a/chrome/browser/apps/link_capturing/link_capturing_features.cc b/chrome/browser/web_applications/link_capturing_features.cc
similarity index 89%
rename from chrome/browser/apps/link_capturing/link_capturing_features.cc
rename to chrome/browser/web_applications/link_capturing_features.cc
index b16bc6e..c9bdfdd 100644
--- a/chrome/browser/apps/link_capturing/link_capturing_features.cc
+++ b/chrome/browser/web_applications/link_capturing_features.cc
@@ -1,8 +1,8 @@
-// Copyright 2022 The Chromium Authors
+// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/apps/link_capturing/link_capturing_features.h"
+#include "chrome/browser/web_applications/link_capturing_features.h"
#include "base/feature_list.h"
#include "build/build_config.h"
diff --git a/chrome/browser/web_applications/link_capturing_features.h b/chrome/browser/web_applications/link_capturing_features.h
new file mode 100644
index 0000000..e96fb6e
--- /dev/null
+++ b/chrome/browser/web_applications/link_capturing_features.h
@@ -0,0 +1,30 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_LINK_CAPTURING_FEATURES_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_LINK_CAPTURING_FEATURES_H_
+
+#include "base/feature_list.h"
+#include "build/build_config.h"
+
+namespace apps::features {
+
+// Returns true if the updated UX for link capturing needs to be shown. Only set
+// to true on desktop platforms if kPwaNavigationCapturing is enabled, and
+// always on CrOS.
+bool ShouldShowLinkCapturingUX();
+
+// Returns true if the `kPwaNavigationCapturing` flag is enabled with the
+// reimplementation parameters set.
+//
+// NOTE: the reimplementation can also be enabled for particular applications
+// even if this flag is off. Hence only the `true` return value can be fully
+// trusted, but if `false` is returned extra considerations are required. See
+// `IsNavigationCapturingReimplExperimentEnabled()` at
+// //c/b/ui/web_applications/web_app_launch_utils.cc.
+bool IsNavigationCapturingReimplEnabled();
+
+} // namespace apps::features
+
+#endif // CHROME_BROWSER_WEB_APPLICATIONS_LINK_CAPTURING_FEATURES_H_
diff --git a/chrome/browser/web_applications/navigation_capturing_settings.cc b/chrome/browser/web_applications/navigation_capturing_settings.cc
new file mode 100644
index 0000000..77873f6
--- /dev/null
+++ b/chrome/browser/web_applications/navigation_capturing_settings.cc
@@ -0,0 +1,36 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/navigation_capturing_settings.h"
+
+#include "chrome/browser/web_applications/link_capturing_features.h"
+#include "content/public/common/content_features.h"
+#include "ui/base/ui_base_features.h"
+
+namespace web_app {
+
+namespace {
+
+// Causes all new auxiliary browser contexts to share the same window container
+// type as where they were created from. For example, if an aux context was
+// created from standalone PWA, then the new context will be created in a new
+// window of the same PWA.
+// If this is off, then all auxiliary contexts will be created as browser tabs.
+const base::FeatureParam<bool> kEnableAuxContextKeepSameContainer{
+ &features::kPwaNavigationCapturing, "aux_context_keep_same_container",
+ /*default_value=*/false};
+
+} // namespace
+
+// Keeping auxiliary contexts in an 'app' container was causing problems on
+// initial Canary testing, see https://crbug.com/379181271 for more information.
+// Either this will be rolled out separately or removed.
+bool NavigationCapturingSettings::ShouldAuxiliaryContextsKeepSameContainer(
+ const std::optional<webapps::AppId>& source_browser_app_id,
+ const GURL& url) {
+ return apps::features::IsNavigationCapturingReimplEnabled() &&
+ kEnableAuxContextKeepSameContainer.Get();
+}
+
+} // namespace web_app
diff --git a/chrome/browser/web_applications/navigation_capturing_settings.h b/chrome/browser/web_applications/navigation_capturing_settings.h
new file mode 100644
index 0000000..ccf046d
--- /dev/null
+++ b/chrome/browser/web_applications/navigation_capturing_settings.h
@@ -0,0 +1,49 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_NAVIGATION_CAPTURING_SETTINGS_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_NAVIGATION_CAPTURING_SETTINGS_H_
+
+#include <memory>
+#include <optional>
+
+#include "components/webapps/common/web_app_id.h"
+
+class Profile;
+
+namespace web_app {
+
+// This class is used by the `NavigationCapturingProcess` to get an installed
+// PWA's `apps::AppId` that captures a given url. This is abstracted behind an
+// interface because ChromeOS uses a separate storage / source of truth for this
+// information than other platforms, and has some extra constraints &
+// requirements due to needing to support ARC++ / Android apps.
+//
+// This class is used exclusively on the UI thread.
+class NavigationCapturingSettings {
+ public:
+ static std::unique_ptr<NavigationCapturingSettings> Create(Profile&);
+ virtual ~NavigationCapturingSettings() = default;
+
+ // Returns the app_id for the web app that a url should be captured in.
+ // Otherwise, return nullopt.
+ virtual std::optional<webapps::AppId> GetCapturingWebAppForUrl(
+ const GURL& url) = 0;
+
+ // Return if auxiliary contexts should be created in the same container (app
+ // or browser) that the navigation happened in. Due to breakage, this is
+ // disabled by default via feature flag, but is planned to be changed to
+ // always 'true'.
+ //
+ // In the meantime, on ChromeOS for <experiment class>, this is selectively
+ // enabled for certain cases to support that project, until we can ship the
+ // above change.
+ virtual bool ShouldAuxiliaryContextsKeepSameContainer(
+ const std::optional<webapps::AppId>& source_browser_app_id,
+ const GURL& url);
+};
+
+} // namespace web_app
+
+#endif // CHROME_BROWSER_WEB_APPLICATIONS_NAVIGATION_CAPTURING_SETTINGS_H_
diff --git a/chrome/browser/web_applications/navigation_capturing_settings_impl.cc b/chrome/browser/web_applications/navigation_capturing_settings_impl.cc
new file mode 100644
index 0000000..967d907
--- /dev/null
+++ b/chrome/browser/web_applications/navigation_capturing_settings_impl.cc
@@ -0,0 +1,30 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/navigation_capturing_settings_impl.h"
+
+#include "chrome/browser/web_applications/navigation_capturing_settings.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
+#include "chrome/browser/web_applications/web_app_registrar.h"
+
+namespace web_app {
+
+std::unique_ptr<NavigationCapturingSettings>
+NavigationCapturingSettings::Create(Profile& profile) {
+ return std::make_unique<NavigationCapturingSettingsImpl>(profile);
+}
+
+NavigationCapturingSettingsImpl::NavigationCapturingSettingsImpl(
+ Profile& profile)
+ : profile_(profile) {}
+
+NavigationCapturingSettingsImpl::~NavigationCapturingSettingsImpl() = default;
+
+std::optional<webapps::AppId>
+NavigationCapturingSettingsImpl::GetCapturingWebAppForUrl(const GURL& url) {
+ auto* provider = web_app::WebAppProvider::GetForWebApps(&profile_.get());
+ return provider->registrar_unsafe().FindAppThatCapturesLinksInScope(url);
+}
+
+} // namespace web_app
diff --git a/chrome/browser/web_applications/navigation_capturing_settings_impl.h b/chrome/browser/web_applications/navigation_capturing_settings_impl.h
new file mode 100644
index 0000000..e44baaf
--- /dev/null
+++ b/chrome/browser/web_applications/navigation_capturing_settings_impl.h
@@ -0,0 +1,38 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_NAVIGATION_CAPTURING_SETTINGS_IMPL_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_NAVIGATION_CAPTURING_SETTINGS_IMPL_H_
+
+#include "base/memory/raw_ref.h"
+#include "chrome/browser/web_applications/navigation_capturing_settings.h"
+
+class Profile;
+
+namespace web_app {
+
+// This is created in the `NavigationCapturingSettings::Create` method, called
+// in `NavigationCapturingProcess`.
+//
+// Windows, Mac, and Linux queries through the WebAppRegistrar to store the
+// preferred application to capturing navigations given a url.
+class NavigationCapturingSettingsImpl : public NavigationCapturingSettings {
+ public:
+ explicit NavigationCapturingSettingsImpl(Profile& profile);
+ ~NavigationCapturingSettingsImpl() override;
+ NavigationCapturingSettingsImpl(const NavigationCapturingSettingsImpl&) =
+ delete;
+ NavigationCapturingSettingsImpl& operator=(
+ const NavigationCapturingSettingsImpl&) = delete;
+
+ std::optional<webapps::AppId> GetCapturingWebAppForUrl(
+ const GURL& url) override;
+
+ private:
+ raw_ref<Profile> profile_;
+};
+
+} // namespace web_app
+
+#endif // CHROME_BROWSER_WEB_APPLICATIONS_NAVIGATION_CAPTURING_SETTINGS_IMPL_H_