[iOS] Add Brave Talk JavaScriptFeature (#34799)

This introduces a Chromium JavaScriptFeature based on `BraveTalkScript.js`

The script itself deviates from its original in that it is now sandboxed to the isolated content world
This commit is contained in:
Kyle Hickinson
2026-03-23 16:44:39 -04:00
committed by GitHub
parent a39486edab
commit aecf5b0e21
19 changed files with 437 additions and 61 deletions
+1
View File
@@ -126,6 +126,7 @@ brave_core_public_headers = [
"//ui/base/l10n/l10n_util_mac_bridge.h",
"$root_gen_dir/components/grit/brave_components_swift_strings.h",
"//brave/ios/browser/web/logins/logins_tab_helper_bridge.h",
"//brave/ios/browser/brave_talk/brave_talk_tab_helper_bridge.h",
]
brave_core_public_headers += ads_public_headers
+1 -1
View File
@@ -646,7 +646,7 @@ var package = Package(
.target(
name: "BraveTalk",
dependencies: [
"Shared", "Preferences", "JitsiMeet", "BraveCore",
"Shared", "Preferences", "JitsiMeet", "BraveCore", "Web",
.product(name: "Collections", package: "swift-collections"),
],
plugins: ["LoggerPlugin"]
@@ -1,37 +0,0 @@
// Copyright 2022 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
import Foundation
import Shared
import UIKit
import Web
extension BrowserViewController {
func launchNativeBraveTalk(tab: (any TabState)?, room: String, token: String) {
guard let host = tab?.lastCommittedURL?.host else { return }
braveTalkJitsiCoordinator.launchNativeBraveTalk(
for: room,
token: token,
host: host,
onEnterCall: { [weak tab] in
tab?.stopLoading()
},
onExitCall: { [weak self] in
guard let self = self else { return }
// When we close the call, redirect to Brave Talk home page if the selected tab is still the original
// talk URL
if let url = self.tabManager.selectedTab?.visibleURL,
let currentHost = url.host,
DomainUserScript.braveTalkHelper.associatedDomains.contains(currentHost)
{
var components = URLComponents()
components.host = currentHost
components.scheme = url.scheme
self.select(url: components.url!, isUserDefinedURLNavigation: false)
}
}
)
}
}
@@ -83,6 +83,22 @@ extension BrowserViewController: TabManagerDelegate {
if FeatureList.kUseProfileWebViewConfiguration.enabled {
tab.readerMode = .init(tab: tab)
}
tab.braveTalk = .init(tab: tab, coordinator: braveTalkJitsiCoordinator)
tab.braveTalk?.onExitCall = { [weak self] in
guard let self = self else { return }
// When we close the call, redirect to Brave Talk home page if the selected tab is still the
// original talk URL
if let url = self.tabManager.selectedTab?.visibleURL,
let currentHost = url.host,
DomainUserScript.braveTalkHelper.associatedDomains.contains(currentHost)
{
var components = URLComponents()
components.host = currentHost
components.scheme = url.scheme
self.select(url: components.url!, isUserDefinedURLNavigation: false)
}
}
}
func tabManager(
@@ -431,14 +431,7 @@ extension BrowserViewController {
}
if tab.profile.prefs.isBraveTalkAvailable {
injectedScripts.append(
BraveTalkScriptHandler(
rewards: rewards,
launchNativeBraveTalk: { [weak self] tab, room, token in
self?.launchNativeBraveTalk(tab: tab, room: room, token: token)
}
)
)
injectedScripts.append(BraveTalkScriptHandler())
}
if profileController.braveWalletAPI.isAllowed {
@@ -13,18 +13,7 @@ import WebKit
import os.log
class BraveTalkScriptHandler: TabContentScript {
private weak var rewards: BraveRewards?
private let launchNativeBraveTalk:
(_ tab: (any TabState)?, _ room: String, _ token: String) -> Void
required init(
rewards: BraveRewards,
launchNativeBraveTalk: @escaping (_ tab: (any TabState)?, _ room: String, _ token: String) ->
Void
) {
self.rewards = rewards
self.launchNativeBraveTalk = launchNativeBraveTalk
}
init() {}
static let scriptName = "BraveTalkScript"
static let scriptId = UUID().uuidString
@@ -109,7 +98,7 @@ class BraveTalkScriptHandler: TabContentScript {
else {
return
}
launchNativeBraveTalk(tab, room, jwt)
tab.braveTalk?.launchBraveTalk(withRoom: room, jwtKey: jwt)
replyHandler(nil, nil)
}
}
@@ -0,0 +1,60 @@
// Copyright (c) 2026 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
import BraveCore
@_spi(ChromiumWebViewAccess) import Web
extension TabDataValues {
private struct BraveTalkTabHelperKey: TabDataKey {
static var defaultValue: BraveTalkTabHelper?
}
public var braveTalk: BraveTalkTabHelper? {
get { self[BraveTalkTabHelperKey.self] }
set { self[BraveTalkTabHelperKey.self] = newValue }
}
}
@MainActor
public class BraveTalkTabHelper: TabObserver, @preconcurrency BraveTalkTabHelperBridge {
private weak var tab: (any TabState)?
private let coordinator: BraveTalkJitsiCoordinator
public var onExitCall: (() -> Void)?
public init(tab: some TabState, coordinator: BraveTalkJitsiCoordinator) {
self.tab = tab
self.coordinator = coordinator
tab.addObserver(self)
}
deinit {
tab?.removeObserver(self)
}
public func tabDidCreateWebView(_ tab: some TabState) {
if FeatureList.kUseProfileWebViewConfiguration.enabled {
BraveWebView.from(tab: tab)?.setBraveTalkHelper(self)
}
}
public func tabWillBeDestroyed(_ tab: some TabState) {
tab.removeObserver(self)
}
public func launchBraveTalk(withRoom room: String, jwtKey: String) {
guard let tab, let host = tab.lastCommittedURL?.host else { return }
coordinator.launchNativeBraveTalk(
for: room,
token: jwtKey,
host: host,
onEnterCall: { [weak tab] in
tab?.stopLoading()
},
onExitCall: { [weak self] in
self?.onExitCall?()
}
)
}
}
+6
View File
@@ -3,6 +3,8 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.
import("//brave/components/brave_talk/buildflags/buildflags.gni")
config("config") {
# For our own public headers to be able to import the official public headers
include_dirs = [
@@ -27,6 +29,7 @@ source_set("web_view") {
"//base",
"//brave/components/ai_chat/core/common",
"//brave/components/ai_chat/ios/browser",
"//brave/components/brave_talk/buildflags",
"//brave/ios/browser/ai_chat",
"//brave/ios/browser/api/profile",
"//brave/ios/browser/api/web_view/autofill",
@@ -53,6 +56,9 @@ source_set("web_view") {
"//ios/web_view/framework:web_view_sources",
"//net",
]
if (enable_brave_talk) {
deps += [ "//brave/ios/browser/brave_talk" ]
}
frameworks = [
"Foundation.framework",
"UIKit.framework",
@@ -24,6 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
@protocol AIChatAssociatedContentPageFetcher;
@protocol ProfileBridge;
@protocol LoginsTabHelperBridge;
@protocol BraveTalkTabHelperBridge;
typedef void (^ResetConfigurationCallback)(id<ProfileBridge>,
WKWebViewConfiguration*);
@@ -196,6 +197,12 @@ CWV_EXPORT
fontSize:(NSInteger)fontSize;
@end
CWV_EXPORT
@interface BraveWebView (BraveTalk)
/// A bridge for handling Brave Talk tab features
- (void)setBraveTalkHelper:(id<BraveTalkTabHelperBridge>)braveTalkHelper;
@end
NS_ASSUME_NONNULL_END
#endif // BRAVE_IOS_BROWSER_API_WEB_VIEW_BRAVE_WEB_VIEW_H_
@@ -15,6 +15,7 @@
#include "brave/components/ai_chat/core/common/features.h"
#include "brave/components/ai_chat/ios/browser/ai_chat_associated_content_page_fetcher.h"
#include "brave/components/ai_chat/ios/browser/ai_chat_tab_helper.h"
#include "brave/components/brave_talk/buildflags/buildflags.h"
#include "brave/ios/browser/ai_chat/ai_chat_distiller_javascript_feature.h"
#include "brave/ios/browser/ai_chat/ai_chat_ui_handler_bridge_holder.h"
#include "brave/ios/browser/ai_chat/tab_data_web_state_observer.h"
@@ -22,6 +23,7 @@
#include "brave/ios/browser/api/web_view/autofill/brave_web_view_autofill_client.h"
#include "brave/ios/browser/api/web_view/passwords/brave_web_view_password_manager_client.h"
#include "brave/ios/browser/brave_ads/ads_tab_helper.h"
#include "brave/ios/browser/brave_talk/brave_talk_tab_helper_bridge.h"
#include "brave/ios/browser/ui/web_view/features.h"
#include "brave/ios/browser/ui/webui/brave_wallet/wallet_page_handler_bridge_holder.h"
#include "brave/ios/browser/web/document_fetch/document_fetch_javascript_feature.h"
@@ -65,6 +67,10 @@
#include "net/base/apple/url_conversions.h"
#include "net/http/http_status_code.h"
#if BUILDFLAG(ENABLE_BRAVE_TALK)
#include "brave/ios/browser/brave_talk/brave_talk_tab_helper.h"
#endif
@interface BraveNavigationAction ()
- (instancetype)initWithRequest:(NSURLRequest*)request
requestInfo:
@@ -203,6 +209,9 @@ class BraveWebViewHolder : public web::WebStateUserData<BraveWebViewHolder> {
aiChatUIHandler;
@property(nonatomic, weak) id<WalletPageHandlerBridge> walletPageHandler;
@property(nonatomic, weak) id<LoginsTabHelperBridge> loginsHelper;
#if BUILDFLAG(ENABLE_BRAVE_TALK)
@property(nonatomic, weak) id<BraveTalkTabHelperBridge> braveTalkHelper;
#endif
@end
@implementation BraveWebView {
@@ -281,6 +290,11 @@ class BraveWebViewHolder : public web::WebStateUserData<BraveWebViewHolder> {
}
brave_ads::AdsTabHelper::MaybeCreateForWebState(self.webState);
#if BUILDFLAG(ENABLE_BRAVE_TALK)
BraveTalkTabHelper::CreateForWebState(self.webState);
BraveTalkTabHelper::FromWebState(self.webState)
->SetBridge(self.braveTalkHelper);
#endif
LoginsTabHelper::MaybeCreateForWebState(self.webState, _loginsHelper);
}
@@ -544,3 +558,19 @@ class BraveWebViewHolder : public web::WebStateUserData<BraveWebViewHolder> {
}
@end
@implementation BraveWebView (BraveTalk)
/// A bridge for handling Brave Talk tab features
- (void)setBraveTalkHelper:(id<BraveTalkTabHelperBridge>)braveTalkHelper {
#if BUILDFLAG(ENABLE_BRAVE_TALK)
_braveTalkHelper = braveTalkHelper;
BraveTalkTabHelper* tab_helper =
BraveTalkTabHelper::FromWebState(self.webState);
if (tab_helper) {
tab_helper->SetBridge(braveTalkHelper);
}
#endif // BUILDFLAG(ENABLE_BRAVE_TALK)
}
@end
+24 -1
View File
@@ -4,16 +4,39 @@
# You can obtain one at https://mozilla.org/MPL/2.0/.
import("//brave/components/brave_talk/buildflags/buildflags.gni")
import("//ios/web/public/js_messaging/optimize_ts.gni")
assert(enable_brave_talk)
source_set("brave_talk") {
sources = [
"brave_talk_launcher_javascript_feature.h",
"brave_talk_launcher_javascript_feature.mm",
"brave_talk_pref_names_bridge.h",
"brave_talk_pref_names_bridge.mm",
"brave_talk_tab_helper.h",
"brave_talk_tab_helper.mm",
"brave_talk_tab_helper_bridge.h",
]
deps = [
"//base",
":brave_talk_launcher_js",
"//brave/components/brave_talk",
"//components/prefs",
"//ios/chrome/browser/shared/model/profile",
"//net",
"//url",
]
public_deps = [
"//base",
"//ios/web/public",
"//ios/web/public/js_messaging",
]
}
optimize_ts("brave_talk_launcher_js") {
visibility = [ ":brave_talk" ]
sources = [ "resources/brave_talk_launcher.ts" ]
deps = [ "//ios/web/public/js_messaging:util_scripts" ]
}
@@ -0,0 +1,45 @@
// Copyright (c) 2026 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
#ifndef BRAVE_IOS_BROWSER_BRAVE_TALK_BRAVE_TALK_LAUNCHER_JAVASCRIPT_FEATURE_H_
#define BRAVE_IOS_BROWSER_BRAVE_TALK_BRAVE_TALK_LAUNCHER_JAVASCRIPT_FEATURE_H_
#include <optional>
#include <string>
#include "base/no_destructor.h"
#include "ios/web/public/js_messaging/java_script_feature.h"
namespace web {
class WebState;
} // namespace web
// A JavaScriptFeature that observes iframe additions on Brave Talk pages and
// notifies the BraveTalkTabHelper attached to the WebState to launch the
// native Brave Talk experience.
class BraveTalkLauncherJavaScriptFeature : public web::JavaScriptFeature {
public:
// This feature holds no state, so only a single static instance is ever
// needed.
static BraveTalkLauncherJavaScriptFeature* GetInstance();
// JavaScriptFeature:
std::optional<std::string> GetScriptMessageHandlerName() const override;
void ScriptMessageReceived(web::WebState* web_state,
const web::ScriptMessage& message) override;
private:
friend class base::NoDestructor<BraveTalkLauncherJavaScriptFeature>;
BraveTalkLauncherJavaScriptFeature();
~BraveTalkLauncherJavaScriptFeature() override;
BraveTalkLauncherJavaScriptFeature(
const BraveTalkLauncherJavaScriptFeature&) = delete;
BraveTalkLauncherJavaScriptFeature& operator=(
const BraveTalkLauncherJavaScriptFeature&) = delete;
};
#endif // BRAVE_IOS_BROWSER_BRAVE_TALK_BRAVE_TALK_LAUNCHER_JAVASCRIPT_FEATURE_H_
@@ -0,0 +1,100 @@
// Copyright (c) 2026 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
#include "brave/ios/browser/brave_talk/brave_talk_launcher_javascript_feature.h"
#include <optional>
#include <string>
#include "base/containers/fixed_flat_set.h"
#include "base/values.h"
#include "brave/ios/browser/brave_talk/brave_talk_tab_helper.h"
#include "ios/web/public/js_messaging/script_message.h"
#include "ios/web/public/web_state.h"
#include "net/base/url_util.h"
#include "url/gurl.h"
namespace {
constexpr char kScriptName[] = "brave_talk_launcher";
constexpr char kScriptHandlerName[] = "BraveTalkLauncherMessageHandler";
constexpr char kMessageURLKey[] = "url";
constexpr auto kAllowedUrlHosts = base::MakeFixedFlatSet<std::string_view>({
"talk.brave.com",
"talk.bravesoftware.com",
"talk.brave.software",
});
} // namespace
BraveTalkLauncherJavaScriptFeature::BraveTalkLauncherJavaScriptFeature()
: JavaScriptFeature(web::ContentWorld::kIsolatedWorld,
{FeatureScript::CreateWithFilename(
kScriptName,
FeatureScript::InjectionTime::kDocumentStart,
FeatureScript::TargetFrames::kMainFrame,
FeatureScript::ReinjectionBehavior::
kReinjectOnDocumentRecreation)}) {}
BraveTalkLauncherJavaScriptFeature::~BraveTalkLauncherJavaScriptFeature() =
default;
// static
BraveTalkLauncherJavaScriptFeature*
BraveTalkLauncherJavaScriptFeature::GetInstance() {
static base::NoDestructor<BraveTalkLauncherJavaScriptFeature> instance;
return instance.get();
}
std::optional<std::string>
BraveTalkLauncherJavaScriptFeature::GetScriptMessageHandlerName() const {
return kScriptHandlerName;
}
void BraveTalkLauncherJavaScriptFeature::ScriptMessageReceived(
web::WebState* web_state,
const web::ScriptMessage& message) {
GURL request_url = message.request_url().value_or(GURL());
if (!message.is_main_frame() || !request_url.is_valid() ||
!kAllowedUrlHosts.contains(request_url.host())) {
return;
}
const base::DictValue* body =
message.body() ? message.body()->GetIfDict() : nullptr;
if (!body) {
return;
}
const std::string* url_string = body->FindString(kMessageURLKey);
if (!url_string) {
return;
}
const GURL jitsi_url(*url_string);
if (!jitsi_url.is_valid()) {
return;
}
// The room name is the first path component of jitsi frame url (stripping the
// the leading '/').
const std::string_view room =
jitsi_url.path().empty() ? "" : jitsi_url.path().substr(1);
if (room.empty()) {
return;
}
std::string jwt;
if (!net::GetValueForKeyInQuery(jitsi_url, "jwt", &jwt) || jwt.empty()) {
return;
}
BraveTalkTabHelper* tab_helper = BraveTalkTabHelper::FromWebState(web_state);
if (!tab_helper) {
return;
}
tab_helper->LaunchBraveTalk(room, jwt);
}
@@ -0,0 +1,38 @@
// Copyright (c) 2026 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
#ifndef BRAVE_IOS_BROWSER_BRAVE_TALK_BRAVE_TALK_TAB_HELPER_H_
#define BRAVE_IOS_BROWSER_BRAVE_TALK_BRAVE_TALK_TAB_HELPER_H_
#include <string>
#include "base/memory/raw_ptr.h"
#include "ios/web/public/web_state_user_data.h"
@protocol BraveTalkTabHelperBridge;
namespace web {
class WebState;
} // namespace web
class BraveTalkTabHelper : public web::WebStateUserData<BraveTalkTabHelper> {
public:
~BraveTalkTabHelper() override;
void SetBridge(id<BraveTalkTabHelperBridge> bridge);
// Forwards a launch request to the registered delegate, if any.
void LaunchBraveTalk(const std::string_view room, const std::string_view jwt);
private:
friend class web::WebStateUserData<BraveTalkTabHelper>;
explicit BraveTalkTabHelper(web::WebState* web_state);
raw_ptr<web::WebState> web_state_ = nullptr; // not owned
__weak id<BraveTalkTabHelperBridge> bridge_;
};
#endif // BRAVE_IOS_BROWSER_BRAVE_TALK_BRAVE_TALK_TAB_HELPER_H_
@@ -0,0 +1,41 @@
// Copyright (c) 2026 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
#include "brave/ios/browser/brave_talk/brave_talk_tab_helper.h"
#include "base/strings/sys_string_conversions.h"
#include "brave/components/brave_talk/pref_names.h"
#include "brave/ios/browser/brave_talk/brave_talk_tab_helper_bridge.h"
#include "components/prefs/pref_service.h"
#include "ios/chrome/browser/shared/model/profile/profile_ios.h"
namespace {
bool IsBraveTalkDisabledByPolicy(PrefService* prefs) {
return prefs->IsManagedPreference(brave_talk::prefs::kDisabledByPolicy) &&
prefs->GetBoolean(brave_talk::prefs::kDisabledByPolicy);
}
} // namespace
BraveTalkTabHelper::BraveTalkTabHelper(web::WebState* web_state)
: web_state_(web_state) {}
BraveTalkTabHelper::~BraveTalkTabHelper() = default;
void BraveTalkTabHelper::SetBridge(id<BraveTalkTabHelperBridge> bridge) {
bridge_ = bridge;
}
void BraveTalkTabHelper::LaunchBraveTalk(const std::string_view room,
const std::string_view jwt) {
PrefService* prefs =
ProfileIOS::FromBrowserState(web_state_->GetBrowserState())->GetPrefs();
if (IsBraveTalkDisabledByPolicy(prefs) || !bridge_) {
return;
}
[bridge_ launchBraveTalkWithRoom:base::SysUTF8ToNSString(room)
jwtKey:base::SysUTF8ToNSString(jwt)];
}
@@ -0,0 +1,22 @@
// Copyright (c) 2026 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
#ifndef BRAVE_IOS_BROWSER_BRAVE_TALK_BRAVE_TALK_TAB_HELPER_BRIDGE_H_
#define BRAVE_IOS_BROWSER_BRAVE_TALK_BRAVE_TALK_TAB_HELPER_BRIDGE_H_
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol BraveTalkTabHelperBridge
@required
- (void)launchBraveTalkWithRoom:(NSString*)room jwtKey:(NSString*)jwtKey;
@end
NS_ASSUME_NONNULL_END
#endif // BRAVE_IOS_BROWSER_BRAVE_TALK_BRAVE_TALK_TAB_HELPER_BRIDGE_H_
@@ -0,0 +1,30 @@
// Copyright (c) 2026 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
import {sendWebKitMessage} from
'//ios/web/public/js_messaging/resources/utils.js';
const allowedOrigins = [
'https://talk.brave.com',
'https://talk.bravesoftware.com',
'https://talk.brave.software',
];
if (allowedOrigins.includes(window.location.origin)) {
const observer = new MutationObserver((mutations: MutationRecord[]) => {
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
if (node instanceof HTMLIFrameElement) {
sendWebKitMessage(
'BraveTalkLauncherMessageHandler', {url: node.src});
observer.disconnect();
return;
}
}
}
});
observer.observe(document, {childList: true, subtree: true});
}
+5
View File
@@ -3,6 +3,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.
import("//brave/components/brave_talk/buildflags/buildflags.gni")
import("//brave/components/brave_wallet/common/buildflags/buildflags.gni")
source_set("web") {
@@ -16,6 +17,7 @@ source_set("web") {
"//base",
"//brave/components/ai_chat/core/browser",
"//brave/components/brave_component_updater/browser:public",
"//brave/components/brave_talk/buildflags",
"//brave/components/brave_user_agent/browser",
"//brave/components/constants",
"//brave/ios/browser/ai_chat",
@@ -47,6 +49,9 @@ source_set("web") {
"//ios/public/provider/chrome/browser/url_rewriters:url_rewriters_api",
"//ios/web_view/framework:web_view_sources",
]
if (enable_brave_talk) {
deps += [ "//brave/ios/browser/brave_talk" ]
}
if (enable_brave_wallet) {
deps += [ "//brave/components/brave_wallet/browser" ]
}
+8 -1
View File
@@ -12,6 +12,7 @@
#include "base/ios/ns_error_util.h"
#include "base/notimplemented.h"
#include "base/strings/sys_string_conversions.h"
#include "brave/components/brave_talk/buildflags/buildflags.h"
#include "brave/components/constants/url_constants.h"
#include "brave/ios/browser/ai_chat/ai_chat_distiller_javascript_feature.h"
#include "brave/ios/browser/api/profile/profile_bridge_impl.h"
@@ -47,6 +48,10 @@
#import "net/base/apple/url_conversions.h"
#include "url/gurl.h"
#if BUILDFLAG(ENABLE_BRAVE_TALK)
#include "brave/ios/browser/brave_talk/brave_talk_launcher_javascript_feature.h"
#endif
BraveWebClient::BraveWebClient() {}
BraveWebClient::~BraveWebClient() {}
@@ -113,12 +118,14 @@ std::vector<web::JavaScriptFeature*> BraveWebClient::GetJavaScriptFeatures(
features.push_back(
brave_ads::AdsMediaReportingJavaScriptFeature::GetInstance());
features.push_back(AIChatDistillerJavaScriptFeature::GetInstance());
#if BUILDFLAG(ENABLE_BRAVE_TALK)
features.push_back(BraveTalkLauncherJavaScriptFeature::GetInstance());
#endif
features.push_back(DeAmpJavaScriptFeature::GetInstance());
features.push_back(DocumentFetchJavaScriptFeature::GetInstance());
features.push_back(ForcePasteJavaScriptFeature::GetInstance());
features.push_back(PageMetadataJavaScriptFeature::GetInstance());
features.push_back(brave::ReaderModeJavaScriptFeature::GetInstance());
if (!base::FeatureList::IsEnabled(
brave::features::kUseChromiumWebViewsAutofill)) {
features.push_back(LoginsJavaScriptFeature::GetInstance());