Commit 6ce64ec3 authored by Mike Dougherty's avatar Mike Dougherty Committed by Chromium LUCI CQ

[iOS] Move shared JavaScript to JavaScriptFeature classes

The shared JavaScript files (base.js, common.js, and
message.js) need to be moved to JavaScriptFeature instances in order
to correctly establish dependencies within WKContentWorlds. This CL
uses these new classes to inject the shared JavaScript.

This CL has no change in behavior.

Bug: 1042335, 1152112
Change-Id: Ie26fc65c1ddb3ee3ff6f4f626111159c243abc03
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2612516
Commit-Queue: Mike Dougherty <michaeldo@chromium.org>
Reviewed-by: default avatarAli Juma <ajuma@chromium.org>
Reviewed-by: default avatarEugene But <eugenebut@chromium.org>
Cr-Commit-Position: refs/heads/master@{#843265}
parent 1fdc55a2
......@@ -28,7 +28,7 @@ namespace chrome_test_util {
// error resulting from the execution, if one occurs. The return value is the
// result of the JavaScript execution. If the request is timed out, then nil is
// returned.
id ExecuteJavaScript(NSString* javascript, NSError* __autoreleasing* out_error);
id ExecuteJavaScript(NSString* javascript, NSError** out_error);
} // namespace chrome_test_util
......
......@@ -460,6 +460,7 @@ source_set("ios_web_web_state_ui_unittests") {
"//ios/web/public",
"//ios/web/public/deprecated",
"//ios/web/public/deprecated:test_doubles",
"//ios/web/public/js_messaging",
"//ios/web/public/session",
"//ios/web/public/test",
"//ios/web/security",
......
......@@ -66,7 +66,7 @@ TEST_F(BrowserStateTest, SetCookieBlockingMode) {
web::WKWebViewConfigurationProvider::FromBrowserState(&browser_state);
NSArray* wkscripts = config_provider.GetWebViewConfiguration()
.userContentController.userScripts;
EXPECT_EQ(wkscripts.count, 4U);
ASSERT_GT(wkscripts.count, 0U);
NSArray<WKUserScript*>* original_scripts =
[[NSArray alloc] initWithArray:wkscripts copyItems:NO];
......
......@@ -56,11 +56,23 @@ source_set("java_script_feature") {
]
}
source_set("java_script_feature_util") {
configs += [ "//build/config/compiler:enable_arc" ]
deps = [ "//ios/web/public/js_messaging" ]
sources = [
"java_script_feature_util_impl.h",
"java_script_feature_util_impl.mm",
]
}
source_set("unittests") {
configs += [ "//build/config/compiler:enable_arc" ]
testonly = true
deps = [
":java_script_feature",
":java_script_feature_util",
":js_messaging",
"//base",
"//base/test:test_support",
......@@ -69,6 +81,7 @@ source_set("unittests") {
"//ios/web/public/js_messaging",
"//ios/web/public/test",
"//ios/web/public/test/fakes",
"//ios/web/web_state/ui:wk_web_view_configuration_provider",
"//testing/gtest",
"//third_party/ocmock",
]
......@@ -77,6 +90,7 @@ source_set("unittests") {
"crw_js_window_id_manager_unittest.mm",
"crw_wk_script_message_router_unittest.mm",
"java_script_content_world_unittest.mm",
"java_script_feature_manager_unittest.mm",
"java_script_feature_unittest.mm",
"page_script_util_unittest.mm",
"web_frame_impl_unittest.mm",
......
......@@ -11,7 +11,7 @@
#include "base/supports_user_data.h"
#import "ios/web/js_messaging/java_script_content_world.h"
@class WKUserContentController;
//@class WKUserContentController;
namespace web {
......@@ -41,9 +41,9 @@ class JavaScriptFeatureManager : public base::SupportsUserData::Data {
JavaScriptFeatureManager& operator=(const JavaScriptFeatureManager&) = delete;
private:
JavaScriptFeatureManager(WKUserContentController* user_content_controller);
JavaScriptFeatureManager(BrowserState* browser_state);
WKUserContentController* user_content_controller_ = nullptr;
BrowserState* browser_state_;
// The content world shared with the page content JavaScript.
std::unique_ptr<JavaScriptContentWorld> page_content_world_;
......
......@@ -9,6 +9,7 @@
#include "base/ios/ios_util.h"
#import "ios/web/public/browser_state.h"
#import "ios/web/public/js_messaging/java_script_feature.h"
#include "ios/web/public/js_messaging/java_script_feature_util.h"
#import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
......@@ -22,13 +23,25 @@ namespace {
const char kWebJavaScriptFeatureManagerKeyName[] =
"web_java_script_feature_manager";
// Adds common features to |world|.
void AddSharedCommonFeatures(web::JavaScriptContentWorld* world) {
// The scripts defined by these features were previously hardcoded into
// js_compile.gni and are assumed to always exist by other feature javascript
// (regardless of content world).
// TODO(crbug.com/1152112): Remove unconditional injection of these features
// once dependent features are migrated to JavaScriptFeatures and correctly
// define their dependencies.
world->AddFeature(web::java_script_features::GetBaseJavaScriptFeature());
world->AddFeature(web::java_script_features::GetCommonJavaScriptFeature());
world->AddFeature(web::java_script_features::GetMessageJavaScriptFeature());
}
} // namespace
namespace web {
JavaScriptFeatureManager::JavaScriptFeatureManager(
WKUserContentController* user_content_controller)
: user_content_controller_(user_content_controller) {}
JavaScriptFeatureManager::JavaScriptFeatureManager(BrowserState* browser_state)
: browser_state_(browser_state) {}
JavaScriptFeatureManager::~JavaScriptFeatureManager() {}
JavaScriptFeatureManager* JavaScriptFeatureManager::FromBrowserState(
......@@ -39,11 +52,7 @@ JavaScriptFeatureManager* JavaScriptFeatureManager::FromBrowserState(
static_cast<JavaScriptFeatureManager*>(
browser_state->GetUserData(kWebJavaScriptFeatureManagerKeyName));
if (!feature_manager) {
WKWebViewConfigurationProvider& configuration_provider =
WKWebViewConfigurationProvider::FromBrowserState(browser_state);
WKUserContentController* user_content_controller =
configuration_provider.GetWebViewConfiguration().userContentController;
feature_manager = new JavaScriptFeatureManager(user_content_controller);
feature_manager = new JavaScriptFeatureManager(browser_state);
browser_state->SetUserData(kWebJavaScriptFeatureManagerKeyName,
base::WrapUnique(feature_manager));
}
......@@ -52,13 +61,23 @@ JavaScriptFeatureManager* JavaScriptFeatureManager::FromBrowserState(
void JavaScriptFeatureManager::ConfigureFeatures(
std::vector<JavaScriptFeature*> features) {
WKWebViewConfigurationProvider& configuration_provider =
WKWebViewConfigurationProvider::FromBrowserState(browser_state_);
// Fetch the WKUserContentController each time features are configured as it
// is not guarentted to remain constant. (For example, clearing Browsing Data
// changes the user content controller instance.)
WKUserContentController* user_content_controller =
configuration_provider.GetWebViewConfiguration().userContentController;
page_content_world_ =
std::make_unique<JavaScriptContentWorld>(user_content_controller_);
std::make_unique<JavaScriptContentWorld>(user_content_controller);
AddSharedCommonFeatures(page_content_world_.get());
#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
if (@available(iOS 14, *)) {
isolated_world_ = std::make_unique<JavaScriptContentWorld>(
user_content_controller_, WKContentWorld.defaultClientWorld);
user_content_controller, WKContentWorld.defaultClientWorld);
AddSharedCommonFeatures(isolated_world_.get());
}
#endif // defined(__IPHONE14_0)
......
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/web/js_messaging/java_script_feature_manager.h"
#import <WebKit/WebKit.h>
#include "base/ios/ios_util.h"
#import "ios/web/public/js_messaging/java_script_feature.h"
#import "ios/web/public/test/fakes/fake_web_client.h"
#include "ios/web/public/test/web_test.h"
#import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
#import "testing/gtest_mac.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// A test fixture for testing JavaScriptFeatureManager.
class JavaScriptFeatureManagerTest : public web::WebTest {
protected:
JavaScriptFeatureManagerTest()
: web::WebTest(std::make_unique<web::FakeWebClient>()) {}
web::JavaScriptFeatureManager* GetJavaScriptFeatureManager() {
web::JavaScriptFeatureManager* java_script_feature_manager =
web::JavaScriptFeatureManager::FromBrowserState(GetBrowserState());
return java_script_feature_manager;
}
WKUserContentController* GetUserContentController() {
return web::WKWebViewConfigurationProvider::FromBrowserState(
GetBrowserState())
.GetWebViewConfiguration()
.userContentController;
}
void SetUp() override {
web::WebTest::SetUp();
[GetUserContentController() removeAllUserScripts];
}
};
// Tests that JavaScriptFeatureManager adds base shared user scripts.
TEST_F(JavaScriptFeatureManagerTest, Configure) {
ASSERT_TRUE(GetJavaScriptFeatureManager());
ASSERT_EQ(0ul, [GetUserContentController().userScripts count]);
GetJavaScriptFeatureManager()->ConfigureFeatures({});
if (base::ios::IsRunningOnIOS14OrLater()) {
EXPECT_EQ(6ul, [GetUserContentController().userScripts count]);
} else {
EXPECT_EQ(3ul, [GetUserContentController().userScripts count]);
}
}
// Tests that JavaScriptFeatureManager adds a JavaScriptFeature for all frames
// at document start time for the page content world.
TEST_F(JavaScriptFeatureManagerTest, AllFramesStartFeature) {
ASSERT_TRUE(GetJavaScriptFeatureManager());
std::vector<const web::JavaScriptFeature::FeatureScript> feature_scripts = {
web::JavaScriptFeature::FeatureScript::CreateWithFilename(
"all_frames_web_bundle",
web::JavaScriptFeature::FeatureScript::InjectionTime::kDocumentStart,
web::JavaScriptFeature::FeatureScript::TargetFrames::kAllFrames)};
std::unique_ptr<web::JavaScriptFeature> feature =
std::make_unique<web::JavaScriptFeature>(
web::JavaScriptFeature::ContentWorld::kPageContentWorld,
feature_scripts);
GetJavaScriptFeatureManager()->ConfigureFeatures({feature.get()});
if (base::ios::IsRunningOnIOS14OrLater()) {
EXPECT_EQ(7ul, [GetUserContentController().userScripts count]);
} else {
EXPECT_EQ(4ul, [GetUserContentController().userScripts count]);
}
WKUserScript* user_script =
[GetUserContentController().userScripts lastObject];
EXPECT_TRUE([user_script.source
containsString:@"findElementAtPointInPageCoordinates"]);
EXPECT_EQ(WKUserScriptInjectionTimeAtDocumentStart,
user_script.injectionTime);
EXPECT_EQ(NO, user_script.forMainFrameOnly);
}
// Tests that JavaScriptFeatureManager adds a JavaScriptFeature for all frames
// at document start time for any content world.
TEST_F(JavaScriptFeatureManagerTest, MainFrameEndFeature) {
ASSERT_TRUE(GetJavaScriptFeatureManager());
std::vector<const web::JavaScriptFeature::FeatureScript> feature_scripts = {
web::JavaScriptFeature::FeatureScript::CreateWithFilename(
"main_frame_web_bundle",
web::JavaScriptFeature::FeatureScript::InjectionTime::kDocumentEnd,
web::JavaScriptFeature::FeatureScript::TargetFrames::kMainFrame)};
std::unique_ptr<web::JavaScriptFeature> feature =
std::make_unique<web::JavaScriptFeature>(
web::JavaScriptFeature::ContentWorld::kAnyContentWorld,
feature_scripts);
GetJavaScriptFeatureManager()->ConfigureFeatures({feature.get()});
if (base::ios::IsRunningOnIOS14OrLater()) {
EXPECT_EQ(7ul, [GetUserContentController().userScripts count]);
} else {
EXPECT_EQ(4ul, [GetUserContentController().userScripts count]);
}
WKUserScript* user_script =
[GetUserContentController().userScripts lastObject];
EXPECT_TRUE([user_script.source containsString:@"findElementAtPoint"]);
EXPECT_EQ(WKUserScriptInjectionTimeAtDocumentEnd, user_script.injectionTime);
EXPECT_EQ(YES, user_script.forMainFrameOnly);
}
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_WEB_JS_MESSAGING_JAVA_SCRIPT_FEATURE_UTIL_IMPL_H_
#define IOS_WEB_JS_MESSAGING_JAVA_SCRIPT_FEATURE_UTIL_IMPL_H_
#include <vector>
#include "ios/web/public/js_messaging/java_script_feature_util.h"
namespace web {
class JavaScriptFeature;
namespace java_script_features {
// Returns the JavaScriptFeatures built in to //ios/web.
std::vector<JavaScriptFeature*> GetBuiltInJavaScriptFeatures();
} // namespace java_script_features
} // namespace web
#endif // IOS_WEB_JS_MESSAGING_JAVA_SCRIPT_FEATURE_UTIL_IMPL_H_
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/web/js_messaging/java_script_feature_util_impl.h"
#import <Foundation/Foundation.h>
#include "ios/web/public/js_messaging/java_script_feature.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
const char kBaseScriptName[] = "base_js";
const char kCommonScriptName[] = "common_js";
const char kMessageScriptName[] = "message_js";
} // namespace
namespace web {
namespace java_script_features {
std::vector<JavaScriptFeature*> GetBuiltInJavaScriptFeatures() {
return {};
}
JavaScriptFeature* GetBaseJavaScriptFeature() {
// Static storage is ok for |base_feature| as it holds no state.
static std::unique_ptr<JavaScriptFeature> base_feature = nullptr;
static dispatch_once_t once;
dispatch_once(&once, ^{
std::vector<const JavaScriptFeature::FeatureScript> feature_scripts = {
JavaScriptFeature::FeatureScript::CreateWithFilename(
kBaseScriptName,
JavaScriptFeature::FeatureScript::InjectionTime::kDocumentStart,
JavaScriptFeature::FeatureScript::TargetFrames::kAllFrames)};
base_feature = std::make_unique<JavaScriptFeature>(
JavaScriptFeature::ContentWorld::kAnyContentWorld, feature_scripts);
});
return base_feature.get();
}
JavaScriptFeature* GetCommonJavaScriptFeature() {
// Static storage is ok for |common_feature| as it holds no state.
static std::unique_ptr<JavaScriptFeature> common_feature = nullptr;
static dispatch_once_t once;
dispatch_once(&once, ^{
std::vector<const JavaScriptFeature::FeatureScript> feature_scripts = {
JavaScriptFeature::FeatureScript::CreateWithFilename(
kCommonScriptName,
JavaScriptFeature::FeatureScript::InjectionTime::kDocumentStart,
JavaScriptFeature::FeatureScript::TargetFrames::kAllFrames)};
std::vector<const JavaScriptFeature*> dependencies = {
GetBaseJavaScriptFeature()};
common_feature = std::make_unique<JavaScriptFeature>(
JavaScriptFeature::ContentWorld::kAnyContentWorld, feature_scripts,
dependencies);
});
return common_feature.get();
}
JavaScriptFeature* GetMessageJavaScriptFeature() {
// Static storage is ok for |message_feature| as it holds no state.
static std::unique_ptr<JavaScriptFeature> message_feature = nullptr;
static dispatch_once_t once;
dispatch_once(&once, ^{
std::vector<const JavaScriptFeature::FeatureScript> feature_scripts = {
JavaScriptFeature::FeatureScript::CreateWithFilename(
kMessageScriptName,
JavaScriptFeature::FeatureScript::InjectionTime::kDocumentStart,
JavaScriptFeature::FeatureScript::TargetFrames::kAllFrames)};
std::vector<const JavaScriptFeature*> dependencies = {
GetCommonJavaScriptFeature()};
message_feature = std::make_unique<JavaScriptFeature>(
JavaScriptFeature::ContentWorld::kAnyContentWorld, feature_scripts,
dependencies);
});
return message_feature.get();
}
} // namespace java_script_features
} // namespace web
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/web/js_messaging/java_script_feature_util_impl.h"
#import <Foundation/Foundation.h>
#import "ios/web/public/js_messaging/java_script_feature.h"
#import "ios/web/public/js_messaging/java_script_feature_util.h"
#include "testing/platform_test.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
typedef PlatformTest JavaScriptFeatureUtilImplTest;
TEST_F(JavaScriptFeatureUtilImplTest, BaseFeature) {
web::JavaScriptFeature* feature =
web::java_script_features::GetBaseJavaScriptFeature();
std::vector<const web::JavaScriptFeature::FeatureScript*> scripts =
feature->GetScripts();
EXPECT_EQ(1ul, scripts.size());
const web::JavaScriptFeature::FeatureScript* script = scripts.front();
EXPECT_TRUE([script->GetScriptString() containsString:@"__gCrWeb"]);
EXPECT_FALSE([script->GetScriptString() containsString:@"__gCrWeb.common"]);
EXPECT_EQ(
web::JavaScriptFeature::FeatureScript::InjectionTime::kDocumentStart,
script->GetInjectionTime());
EXPECT_EQ(web::JavaScriptFeature::FeatureScript::TargetFrames::kAllFrames,
script->GetTargetFrames());
}
TEST_F(JavaScriptFeatureUtilImplTest, CommonFeature) {
web::JavaScriptFeature* feature =
web::java_script_features::GetCommonJavaScriptFeature();
std::vector<const web::JavaScriptFeature::FeatureScript*> scripts =
feature->GetScripts();
EXPECT_EQ(1ul, scripts.size());
const web::JavaScriptFeature::FeatureScript* script = scripts.front();
EXPECT_TRUE([script->GetScriptString() containsString:@"__gCrWeb.common"]);
EXPECT_FALSE([script->GetScriptString() containsString:@"__gCrWeb.message"]);
EXPECT_EQ(
web::JavaScriptFeature::FeatureScript::InjectionTime::kDocumentStart,
script->GetInjectionTime());
EXPECT_EQ(web::JavaScriptFeature::FeatureScript::TargetFrames::kAllFrames,
script->GetTargetFrames());
}
TEST_F(JavaScriptFeatureUtilImplTest, MessageFeature) {
web::JavaScriptFeature* feature =
web::java_script_features::GetMessageJavaScriptFeature();
std::vector<const web::JavaScriptFeature::FeatureScript*> scripts =
feature->GetScripts();
EXPECT_EQ(1ul, scripts.size());
const web::JavaScriptFeature::FeatureScript* script = scripts.front();
EXPECT_TRUE([script->GetScriptString() containsString:@"__gCrWeb.message"]);
EXPECT_EQ(
web::JavaScriptFeature::FeatureScript::InjectionTime::kDocumentStart,
script->GetInjectionTime());
EXPECT_EQ(web::JavaScriptFeature::FeatureScript::TargetFrames::kAllFrames,
script->GetTargetFrames());
}
......@@ -101,11 +101,8 @@ NSString* GetDocumentStartScriptForAllFrames(BrowserState* browser_state) {
web_bundle =
[web_bundle stringByReplacingOccurrencesOfString:@"$(COOKIE_STATE)"
withString:injectedCookieState];
NSString* script = [NSString
stringWithFormat:@"%@; %@; %@; %@; %@", GetPageScript(@"base_js"),
GetPageScript(@"common_js"),
GetPageScript(@"message_js"), web_bundle,
embedder_page_script];
NSString* script =
[NSString stringWithFormat:@"%@; %@", web_bundle, embedder_page_script];
return MakeScriptInjectableOnce(@"start_all_frames", script);
}
......
......@@ -11,6 +11,7 @@ source_set("js_messaging") {
sources = [
"java_script_feature.h",
"java_script_feature_util.h",
"web_frame.h",
"web_frame_user_data.h",
"web_frame_util.h",
......
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_WEB_PUBLIC_JS_MESSAGING_JAVA_SCRIPT_FEATURE_UTIL_H_
#define IOS_WEB_PUBLIC_JS_MESSAGING_JAVA_SCRIPT_FEATURE_UTIL_H_
namespace web {
class JavaScriptFeature;
namespace java_script_features {
// Returns the shared base javascript used across many features which defines
// the __gCrWeb object.
JavaScriptFeature* GetBaseJavaScriptFeature();
// Returns the shared common javascript used across many features which defines
// __gCrWeb.common APIs.
JavaScriptFeature* GetCommonJavaScriptFeature();
// Returns the shared message javascript used across many features which defines
// __gCrWeb.message APIs.
JavaScriptFeature* GetMessageJavaScriptFeature();
} // namespace java_script_features
} // namespace web
#endif // IOS_WEB_PUBLIC_JS_MESSAGING_JAVA_SCRIPT_FEATURE_UTIL_H_
......@@ -42,6 +42,9 @@ class FakeWebClient : public web::WebClient {
base::RefCountedMemory* GetDataResourceBytes(int id) const override;
std::vector<JavaScriptFeature*> GetJavaScriptFeatures(
BrowserState* browser_state) const override;
NSString* GetDocumentStartScriptForMainFrame(
BrowserState* browser_state) const override;
NSString* GetDocumentStartScriptForAllFrames(
......@@ -71,6 +74,9 @@ class FakeWebClient : public web::WebClient {
// Changes Early Page Script for testing purposes.
void SetEarlyPageScript(NSString* page_script);
// Changes Java Script Features for testing.
void SetJavaScriptFeatures(std::vector<JavaScriptFeature*> features);
// Overrides AllowCertificateError response.
void SetAllowCertificateErrors(bool flag);
......@@ -88,6 +94,7 @@ class FakeWebClient : public web::WebClient {
private:
base::string16 plugin_not_supported_text_;
std::vector<JavaScriptFeature*> java_script_features_;
NSString* early_page_script_ = nil;
// Last arguments passed to AllowCertificateError.
int last_cert_error_code_ = 0;
......
......@@ -62,6 +62,11 @@ base::RefCountedMemory* FakeWebClient::GetDataResourceBytes(
resource_id);
}
std::vector<JavaScriptFeature*> FakeWebClient::GetJavaScriptFeatures(
BrowserState* browser_state) const {
return java_script_features_;
}
NSString* FakeWebClient::GetDocumentStartScriptForMainFrame(
BrowserState* browser_state) const {
return early_page_script_ ? early_page_script_ : @"";
......@@ -76,6 +81,11 @@ void FakeWebClient::SetPluginNotSupportedText(const base::string16& text) {
plugin_not_supported_text_ = text;
}
void FakeWebClient::SetJavaScriptFeatures(
std::vector<JavaScriptFeature*> features) {
java_script_features_ = features;
}
void FakeWebClient::SetEarlyPageScript(NSString* page_script) {
early_page_script_ = [page_script copy];
}
......
......@@ -37,6 +37,7 @@ namespace web {
class BrowserState;
class BrowserURLRewriter;
class JavaScriptFeature;
class SerializableUserDataManager;
class WebClient;
class WebMainParts;
......@@ -122,6 +123,10 @@ class WebClient {
// singleton.
virtual void PostBrowserURLRewriterCreation(BrowserURLRewriter* rewriter) {}
// Gives the embedder a chance to provide custom JavaScriptFeatures.
virtual std::vector<JavaScriptFeature*> GetJavaScriptFeatures(
BrowserState* browser_state) const;
// Gives the embedder a chance to provide the JavaScript to be injected into
// the web view as early as possible. Result must not be nil.
// The script returned will be injected in all frames (main and subframes).
......
......@@ -75,6 +75,11 @@ base::RefCountedMemory* WebClient::GetDataResourceBytes(int resource_id) const {
return nullptr;
}
std::vector<JavaScriptFeature*> WebClient::GetJavaScriptFeatures(
BrowserState* browser_state) const {
return std::vector<JavaScriptFeature*>();
}
NSString* WebClient::GetDocumentStartScriptForAllFrames(
BrowserState* browser_state) const {
return @"";
......
......@@ -131,6 +131,8 @@ source_set("wk_web_view_configuration_provider") {
"//ios/third_party/webkit",
"//ios/web/common",
"//ios/web/js_messaging",
"//ios/web/js_messaging:java_script_feature",
"//ios/web/js_messaging:java_script_feature_util",
"//ios/web/public",
"//ios/web/web_state/js",
"//ios/web/webui",
......
......@@ -6,6 +6,7 @@
#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>
#include <vector>
#include "base/check.h"
#include "base/ios/ios_util.h"
......@@ -15,6 +16,8 @@
#include "components/safe_browsing/core/features.h"
#include "ios/web/common/features.h"
#import "ios/web/js_messaging/crw_wk_script_message_router.h"
#import "ios/web/js_messaging/java_script_feature_manager.h"
#include "ios/web/js_messaging/java_script_feature_util_impl.h"
#import "ios/web/js_messaging/page_script_util.h"
#include "ios/web/public/browser_state.h"
#include "ios/web/public/web_client.h"
......@@ -208,6 +211,21 @@ WKWebViewConfigurationProvider::GetContentRuleListProvider() {
void WKWebViewConfigurationProvider::UpdateScripts() {
[configuration_.userContentController removeAllUserScripts];
JavaScriptFeatureManager* java_script_feature_manager =
JavaScriptFeatureManager::FromBrowserState(browser_state_);
std::vector<JavaScriptFeature*> features;
for (JavaScriptFeature* feature :
java_script_features::GetBuiltInJavaScriptFeatures()) {
features.push_back(feature);
}
for (JavaScriptFeature* feature :
GetWebClient()->GetJavaScriptFeatures(browser_state_)) {
features.push_back(feature);
}
java_script_feature_manager->ConfigureFeatures(features);
// Main frame script depends upon scripts injected into all frames, so the
// "AllFrames" scripts must be injected first.
[configuration_.userContentController
......
......@@ -9,6 +9,7 @@
#include "base/memory/ptr_util.h"
#import "ios/web/js_messaging/crw_wk_script_message_router.h"
#import "ios/web/js_messaging/page_script_util.h"
#import "ios/web/public/js_messaging/java_script_feature.h"
#include "ios/web/public/test/fakes/fake_browser_state.h"
#import "ios/web/public/test/fakes/fake_web_client.h"
#include "ios/web/public/test/scoped_testing_web_client.h"
......@@ -223,6 +224,33 @@ TEST_F(WKWebViewConfigurationProviderTest, UpdateScripts) {
[initial_script.source rangeOfString:updated_main_frame_script].length);
}
// Tests that configuration's userContentController has additional scripts
// injected for JavaScriptFeatures configured through the WebClient.
TEST_F(WKWebViewConfigurationProviderTest, JavaScriptFeatureInjection) {
FakeWebClient* client = GetWebClient();
WKUserContentController* user_content_controller =
GetProvider().GetWebViewConfiguration().userContentController;
unsigned long original_script_count =
[user_content_controller.userScripts count];
std::vector<const web::JavaScriptFeature::FeatureScript> feature_scripts = {
web::JavaScriptFeature::FeatureScript::CreateWithFilename(
"all_frames_web_bundle",
web::JavaScriptFeature::FeatureScript::InjectionTime::kDocumentStart,
web::JavaScriptFeature::FeatureScript::TargetFrames::kAllFrames)};
std::unique_ptr<web::JavaScriptFeature> feature =
std::make_unique<web::JavaScriptFeature>(
web::JavaScriptFeature::ContentWorld::kPageContentWorld,
feature_scripts);
client->SetJavaScriptFeatures({feature.get()});
GetProvider().UpdateScripts();
EXPECT_GT([user_content_controller.userScripts count], original_script_count);
}
// Tests that observers methods are correctly triggered when observing the
// WKWebViewConfigurationProvider
TEST_F(WKWebViewConfigurationProviderTest, Observers) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment