Merge pull request #6035 from electron/content-scripts-in-web-views
Load content scripts in webview devtools
This commit is contained in:
commit
efa667fa0a
6 changed files with 73 additions and 41 deletions
|
@ -4,9 +4,8 @@
|
||||||
|
|
||||||
#include "atom/browser/api/atom_api_render_process_preferences.h"
|
#include "atom/browser/api/atom_api_render_process_preferences.h"
|
||||||
|
|
||||||
|
#include "atom/browser/api/atom_api_web_contents.h"
|
||||||
#include "atom/browser/atom_browser_client.h"
|
#include "atom/browser/atom_browser_client.h"
|
||||||
#include "atom/browser/native_window.h"
|
|
||||||
#include "atom/browser/window_list.h"
|
|
||||||
#include "atom/common/native_mate_converters/value_converter.h"
|
#include "atom/common/native_mate_converters/value_converter.h"
|
||||||
#include "atom/common/node_includes.h"
|
#include "atom/common/node_includes.h"
|
||||||
#include "content/public/browser/render_process_host.h"
|
#include "content/public/browser/render_process_host.h"
|
||||||
|
@ -19,18 +18,17 @@ namespace api {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool IsBrowserWindow(content::RenderProcessHost* process) {
|
bool IsWebContents(v8::Isolate* isolate, content::RenderProcessHost* process) {
|
||||||
content::WebContents* web_contents =
|
content::WebContents* web_contents =
|
||||||
static_cast<AtomBrowserClient*>(AtomBrowserClient::Get())->
|
static_cast<AtomBrowserClient*>(AtomBrowserClient::Get())->
|
||||||
GetWebContentsFromProcessID(process->GetID());
|
GetWebContentsFromProcessID(process->GetID());
|
||||||
if (!web_contents)
|
if (!web_contents)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
NativeWindow* window = NativeWindow::FromWebContents(web_contents);
|
auto api_web_contents = WebContents::CreateFrom(isolate, web_contents);
|
||||||
if (!window)
|
auto type = api_web_contents->GetType();
|
||||||
return false;
|
return type == WebContents::Type::BROWSER_WINDOW ||
|
||||||
|
type == WebContents::Type::WEB_VIEW;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -63,10 +61,11 @@ void RenderProcessPreferences::BuildPrototype(
|
||||||
|
|
||||||
// static
|
// static
|
||||||
mate::Handle<RenderProcessPreferences>
|
mate::Handle<RenderProcessPreferences>
|
||||||
RenderProcessPreferences::ForAllBrowserWindow(v8::Isolate* isolate) {
|
RenderProcessPreferences::ForAllWebContents(v8::Isolate* isolate) {
|
||||||
return mate::CreateHandle(
|
return mate::CreateHandle(
|
||||||
isolate,
|
isolate,
|
||||||
new RenderProcessPreferences(isolate, base::Bind(&IsBrowserWindow)));
|
new RenderProcessPreferences(isolate,
|
||||||
|
base::Bind(&IsWebContents, isolate)));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace api
|
} // namespace api
|
||||||
|
@ -78,8 +77,8 @@ namespace {
|
||||||
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
||||||
v8::Local<v8::Context> context, void* priv) {
|
v8::Local<v8::Context> context, void* priv) {
|
||||||
mate::Dictionary dict(context->GetIsolate(), exports);
|
mate::Dictionary dict(context->GetIsolate(), exports);
|
||||||
dict.SetMethod("forAllBrowserWindow",
|
dict.SetMethod("forAllWebContents",
|
||||||
&atom::api::RenderProcessPreferences::ForAllBrowserWindow);
|
&atom::api::RenderProcessPreferences::ForAllWebContents);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -17,7 +17,7 @@ class RenderProcessPreferences
|
||||||
: public mate::Wrappable<RenderProcessPreferences> {
|
: public mate::Wrappable<RenderProcessPreferences> {
|
||||||
public:
|
public:
|
||||||
static mate::Handle<RenderProcessPreferences>
|
static mate::Handle<RenderProcessPreferences>
|
||||||
ForAllBrowserWindow(v8::Isolate* isolate);
|
ForAllWebContents(v8::Isolate* isolate);
|
||||||
|
|
||||||
static void BuildPrototype(v8::Isolate* isolate,
|
static void BuildPrototype(v8::Isolate* isolate,
|
||||||
v8::Local<v8::ObjectTemplate> prototype);
|
v8::Local<v8::ObjectTemplate> prototype);
|
||||||
|
|
|
@ -187,6 +187,39 @@ struct Converter<content::SavePageType> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Converter<atom::api::WebContents::Type> {
|
||||||
|
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||||
|
atom::api::WebContents::Type val) {
|
||||||
|
using Type = atom::api::WebContents::Type;
|
||||||
|
std::string type = "";
|
||||||
|
switch (val) {
|
||||||
|
case Type::BACKGROUND_PAGE: type = "backgroundPage"; break;
|
||||||
|
case Type::BROWSER_WINDOW: type = "window"; break;
|
||||||
|
case Type::REMOTE: type = "remote"; break;
|
||||||
|
case Type::WEB_VIEW: type = "webview"; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return mate::ConvertToV8(isolate, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
|
||||||
|
atom::api::WebContents::Type* out) {
|
||||||
|
using Type = atom::api::WebContents::Type;
|
||||||
|
std::string type;
|
||||||
|
if (!ConvertFromV8(isolate, val, &type))
|
||||||
|
return false;
|
||||||
|
if (type == "webview") {
|
||||||
|
*out = Type::WEB_VIEW;
|
||||||
|
} else if (type == "backgroundPage") {
|
||||||
|
*out = Type::BACKGROUND_PAGE;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace mate
|
} // namespace mate
|
||||||
|
|
||||||
|
|
||||||
|
@ -238,10 +271,8 @@ WebContents::WebContents(v8::Isolate* isolate,
|
||||||
// Read options.
|
// Read options.
|
||||||
options.Get("backgroundThrottling", &background_throttling_);
|
options.Get("backgroundThrottling", &background_throttling_);
|
||||||
|
|
||||||
// Whether it is a guest WebContents.
|
type_ = BROWSER_WINDOW;
|
||||||
bool is_guest = false;
|
options.Get("type", &type_);
|
||||||
options.Get("isGuest", &is_guest);
|
|
||||||
type_ = is_guest ? WEB_VIEW : BROWSER_WINDOW;
|
|
||||||
|
|
||||||
// Obtain the session.
|
// Obtain the session.
|
||||||
std::string partition;
|
std::string partition;
|
||||||
|
@ -261,7 +292,7 @@ WebContents::WebContents(v8::Isolate* isolate,
|
||||||
session_.Reset(isolate, session.ToV8());
|
session_.Reset(isolate, session.ToV8());
|
||||||
|
|
||||||
content::WebContents* web_contents;
|
content::WebContents* web_contents;
|
||||||
if (is_guest) {
|
if (IsGuest()) {
|
||||||
scoped_refptr<content::SiteInstance> site_instance =
|
scoped_refptr<content::SiteInstance> site_instance =
|
||||||
content::SiteInstance::CreateForURL(
|
content::SiteInstance::CreateForURL(
|
||||||
session->browser_context(), GURL("chrome-guest://fake-host"));
|
session->browser_context(), GURL("chrome-guest://fake-host"));
|
||||||
|
@ -290,7 +321,7 @@ WebContents::WebContents(v8::Isolate* isolate,
|
||||||
|
|
||||||
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
|
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
|
||||||
|
|
||||||
if (is_guest) {
|
if (IsGuest()) {
|
||||||
guest_delegate_->Initialize(this);
|
guest_delegate_->Initialize(this);
|
||||||
|
|
||||||
NativeWindow* owner_window = nullptr;
|
NativeWindow* owner_window = nullptr;
|
||||||
|
@ -744,13 +775,8 @@ int WebContents::GetID() const {
|
||||||
return web_contents()->GetRenderProcessHost()->GetID();
|
return web_contents()->GetRenderProcessHost()->GetID();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string WebContents::GetType() const {
|
WebContents::Type WebContents::GetType() const {
|
||||||
switch (type_) {
|
return type_;
|
||||||
case BROWSER_WINDOW: return "window";
|
|
||||||
case WEB_VIEW: return "webview";
|
|
||||||
case REMOTE: return "remote";
|
|
||||||
default: return "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebContents::Equal(const WebContents* web_contents) const {
|
bool WebContents::Equal(const WebContents* web_contents) const {
|
||||||
|
|
|
@ -43,6 +43,13 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||||
public CommonWebContentsDelegate,
|
public CommonWebContentsDelegate,
|
||||||
public content::WebContentsObserver {
|
public content::WebContentsObserver {
|
||||||
public:
|
public:
|
||||||
|
enum Type {
|
||||||
|
BACKGROUND_PAGE, // A DevTools extension background page.
|
||||||
|
BROWSER_WINDOW, // Used by BrowserWindow.
|
||||||
|
REMOTE, // Thin wrap around an existing WebContents.
|
||||||
|
WEB_VIEW, // Used by <webview>.
|
||||||
|
};
|
||||||
|
|
||||||
// For node.js callback function type: function(error, buffer)
|
// For node.js callback function type: function(error, buffer)
|
||||||
using PrintToPDFCallback =
|
using PrintToPDFCallback =
|
||||||
base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>;
|
base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>;
|
||||||
|
@ -59,7 +66,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||||
v8::Local<v8::ObjectTemplate> prototype);
|
v8::Local<v8::ObjectTemplate> prototype);
|
||||||
|
|
||||||
int GetID() const;
|
int GetID() const;
|
||||||
std::string GetType() const;
|
Type GetType() const;
|
||||||
bool Equal(const WebContents* web_contents) const;
|
bool Equal(const WebContents* web_contents) const;
|
||||||
void LoadURL(const GURL& url, const mate::Dictionary& options);
|
void LoadURL(const GURL& url, const mate::Dictionary& options);
|
||||||
void DownloadURL(const GURL& url);
|
void DownloadURL(const GURL& url);
|
||||||
|
@ -268,12 +275,6 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||||
void DevToolsClosed() override;
|
void DevToolsClosed() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum Type {
|
|
||||||
BROWSER_WINDOW, // Used by BrowserWindow.
|
|
||||||
WEB_VIEW, // Used by <webview>.
|
|
||||||
REMOTE, // Thin wrap around an existing WebContents.
|
|
||||||
};
|
|
||||||
|
|
||||||
AtomBrowserContext* GetBrowserContext() const;
|
AtomBrowserContext* GetBrowserContext() const;
|
||||||
|
|
||||||
uint32_t GetNextRequestId() {
|
uint32_t GetNextRequestId() {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
const {app, ipcMain, session, webContents, BrowserWindow} = require('electron')
|
const {app, ipcMain, session, webContents, BrowserWindow} = require('electron')
|
||||||
const {getAllWebContents} = process.atomBinding('web_contents')
|
const {getAllWebContents} = process.atomBinding('web_contents')
|
||||||
const renderProcessPreferences = process.atomBinding('render_process_preferences').forAllBrowserWindow()
|
const renderProcessPreferences = process.atomBinding('render_process_preferences').forAllWebContents()
|
||||||
|
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
@ -19,6 +19,11 @@ const generateExtensionIdFromName = function (name) {
|
||||||
return name.replace(/[\W_]+/g, '-').toLowerCase()
|
return name.replace(/[\W_]+/g, '-').toLowerCase()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isWindowOrWebView = function (webContents) {
|
||||||
|
const type = webContents.getType()
|
||||||
|
return type === 'window' || type === 'webview'
|
||||||
|
}
|
||||||
|
|
||||||
// Create or get manifest object from |srcDirectory|.
|
// Create or get manifest object from |srcDirectory|.
|
||||||
const getManifestFromPath = function (srcDirectory) {
|
const getManifestFromPath = function (srcDirectory) {
|
||||||
let manifest
|
let manifest
|
||||||
|
@ -73,6 +78,7 @@ const startBackgroundPages = function (manifest) {
|
||||||
const html = new Buffer(`<html><body>${scripts}</body></html>`)
|
const html = new Buffer(`<html><body>${scripts}</body></html>`)
|
||||||
|
|
||||||
const contents = webContents.create({
|
const contents = webContents.create({
|
||||||
|
type: 'backgroundPage',
|
||||||
commandLineSwitches: ['--background-page']
|
commandLineSwitches: ['--background-page']
|
||||||
})
|
})
|
||||||
backgroundPages[manifest.extensionId] = { html: html, webContents: contents }
|
backgroundPages[manifest.extensionId] = { html: html, webContents: contents }
|
||||||
|
@ -111,7 +117,7 @@ let nextId = 0
|
||||||
ipcMain.on('CHROME_RUNTIME_CONNECT', function (event, extensionId, connectInfo) {
|
ipcMain.on('CHROME_RUNTIME_CONNECT', function (event, extensionId, connectInfo) {
|
||||||
const page = backgroundPages[extensionId]
|
const page = backgroundPages[extensionId]
|
||||||
if (!page) {
|
if (!page) {
|
||||||
console.error(`Connect to unkown extension ${extensionId}`)
|
console.error(`Connect to unknown extension ${extensionId}`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +138,7 @@ ipcMain.on('CHROME_I18N_MANIFEST', function (event, extensionId) {
|
||||||
ipcMain.on('CHROME_RUNTIME_SENDMESSAGE', function (event, extensionId, message) {
|
ipcMain.on('CHROME_RUNTIME_SENDMESSAGE', function (event, extensionId, message) {
|
||||||
const page = backgroundPages[extensionId]
|
const page = backgroundPages[extensionId]
|
||||||
if (!page) {
|
if (!page) {
|
||||||
console.error(`Connect to unkown extension ${extensionId}`)
|
console.error(`Connect to unknown extension ${extensionId}`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +148,7 @@ ipcMain.on('CHROME_RUNTIME_SENDMESSAGE', function (event, extensionId, message)
|
||||||
ipcMain.on('CHROME_TABS_SEND_MESSAGE', function (event, tabId, extensionId, isBackgroundPage, message) {
|
ipcMain.on('CHROME_TABS_SEND_MESSAGE', function (event, tabId, extensionId, isBackgroundPage, message) {
|
||||||
const contents = webContents.fromId(tabId)
|
const contents = webContents.fromId(tabId)
|
||||||
if (!contents) {
|
if (!contents) {
|
||||||
console.error(`Sending message to unkown tab ${tabId}`)
|
console.error(`Sending message to unknown tab ${tabId}`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +160,7 @@ ipcMain.on('CHROME_TABS_SEND_MESSAGE', function (event, tabId, extensionId, isBa
|
||||||
ipcMain.on('CHROME_TABS_EXECUTESCRIPT', function (event, requestId, tabId, extensionId, details) {
|
ipcMain.on('CHROME_TABS_EXECUTESCRIPT', function (event, requestId, tabId, extensionId, details) {
|
||||||
const contents = webContents.fromId(tabId)
|
const contents = webContents.fromId(tabId)
|
||||||
if (!contents) {
|
if (!contents) {
|
||||||
console.error(`Sending message to unkown tab ${tabId}`)
|
console.error(`Sending message to unknown tab ${tabId}`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,7 +243,7 @@ const loadDevToolsExtensions = function (win, manifests) {
|
||||||
}
|
}
|
||||||
|
|
||||||
app.on('web-contents-created', function (event, webContents) {
|
app.on('web-contents-created', function (event, webContents) {
|
||||||
if (webContents.getType() === 'remote') return
|
if (!isWindowOrWebView(webContents)) return
|
||||||
|
|
||||||
hookWebContentsForTabEvents(webContents)
|
hookWebContentsForTabEvents(webContents)
|
||||||
webContents.on('devtools-opened', function () {
|
webContents.on('devtools-opened', function () {
|
||||||
|
@ -322,7 +328,7 @@ app.once('ready', function () {
|
||||||
const manifest = getManifestFromPath(srcDirectory)
|
const manifest = getManifestFromPath(srcDirectory)
|
||||||
if (manifest) {
|
if (manifest) {
|
||||||
for (const webContents of getAllWebContents()) {
|
for (const webContents of getAllWebContents()) {
|
||||||
if (webContents.getType() !== 'remote') {
|
if (isWindowOrWebView(webContents)) {
|
||||||
loadDevToolsExtensions(webContents, [manifest])
|
loadDevToolsExtensions(webContents, [manifest])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ const createGuest = function (embedder, params) {
|
||||||
|
|
||||||
const id = getNextInstanceId(embedder)
|
const id = getNextInstanceId(embedder)
|
||||||
const guest = webContents.create({
|
const guest = webContents.create({
|
||||||
isGuest: true,
|
type: 'webview',
|
||||||
partition: params.partition,
|
partition: params.partition,
|
||||||
embedder: embedder
|
embedder: embedder
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Reference in a new issue