摘要:我需要找到一种方法来完成程序化注入与使用content_scripts
>完全相同的行为。清单上matches
"all_frames": true
iframe
。为什么?因为这是我发现在扩展页面中注入optional_permissions
内容而没有跨源错误的唯一方法。
我正在使用Chrome扩展程序转到optional_permissions
,而我却走到了尽头。
将此行为移至content_scripts
,以便将来能够添加更多主机。使用当前代码,在matches
>上添加一个新主机content_scripts
Chrome已禁用该扩展程序。
对于移动,我删除了清单中的"optional_permissions": ["*://*/"],
,并添加了chrome.permissions.request
。然后,我成功实现了一个对话框,询问用户iframe
的新权限。
正如我之前所说,问题是如何在扩展页面中注入allFrames: true
的内容。
chrome.declarativeContent.RequestContentScript
(提及here)与iframe
。如果我直接输入网址,我只能看到脚本正在运行,当url
中设置该网址时没有任何反应。chrome.tabs.onUpdated
:undefined
是iframe
的扩展程序页面。此外,未检测到allFrames: true
网址。iframe
后,立即使用Cannot access contents of the page. Extension manifest must request permission to access the respective host.
致电chrome.tabs.executeScript
。通过这样做,我得到一个例外chrome-extension://
,“相应的主机”是content_scripts
,如果你想将它添加到权限中,它就不是有效的主机。我迷路了。我找不到一种方法来模拟与matches
>相同的行为。 webNavigation
与programmatic injection。
注意:使用frameId
API不是一个选项,因为扩展程序是实时的,并且它有数千个用户。因此,我无法将executeScript
属性用于executeScript
。因此,chrome-extension
的唯一选择是注入所有帧,但PhoneAuthProvider.getInstance().verifyPhoneNumber(
phoneNum,
60,
TimeUnit.SECONDS,
this,
mCallbacks
主机问题不允许我继续。
更新:我能够完成我想要的但只能在HTTP主机上完成。我使用chrome.tabs.executeScript
(选项3)。
问题仍然是如何在扩展页面上进行此项工作。
答案 0 :(得分:2)
您无法在任何扩展程序页面中运行内容脚本,包括您自己的。
如果您想在扩展程序页面的子框架中运行代码,则必须使用frameId
。无论有没有webNavigation
,有两种方法可以做到这一点。
我已将所有代码片段放在此答案中(使用一些按钮调用各个代码段)并在https://robwu.nl/s/optional_permissions-script-subframe.zip分享它 要试用它,请下载并解压缩zip文件,在chrome:// extensions处加载扩展程序,然后单击扩展按钮以打开测试页。
由于目标是以optional permissions编程运行脚本,因此您需要请求权限。我的例子将使用example.com。 如果您也想使用webNavigation API,也请在权限请求中包含其权限。
chrome.permissions.request({
// permissions: ['webNavigation'], // uncomment if you want this.
origins: ['*://*.example.com/*'],
}, function(granted) {
alert('Permission was ' + (granted ? '' : 'not ') + 'granted!');
});
一旦有了标签ID和frameId,就可以轻松地在特定框架中注入脚本。由于tabId要求,此方法只适用于选项卡中的帧,而不适用于browserAction / pageAction弹出窗口或后台页面中的帧!
为了证明代码执行成功,下面的示例将在tabId和frameId已知后调用下一个injectInFrame
函数。
function injectInFrame(tabId, frameId) {
chrome.tabs.executeScript(tabId, {
frameId,
code: 'document.body.textContent = "The document content replaced with content at " + new Date().toLocaleString();',
});
}
如果您不仅要在特定框架中运行代码,而是要在该框架的所有子框架中运行代码,只需将allFrames: true
添加到chrome.tabs.executeScript
来电。
如果您想知道其他脚本中的当前tabId(例如后台脚本),请使用chrome.tabs.getCurrent
查找脚本运行的选项卡的ID(或chrome.tabs.query
和{active:true,currentWindow:true}
。
之后,使用chrome.webNavigation.getAllFrames
查询选项卡中的所有帧。识别框架的主要方法是通过页面的URL,因此如果框架页面重定向到其他位置,或者如果有多个框架具有相同的URL,则会出现问题。这是一个例子:
// Assuming that you already have a frame in your document,
// i.e. <iframe src="https://example.com"></iframe>
chrome.tabs.getCurrent(function(tab) {
chrome.webNavigation.getAllFrames({
tabId: tab.id,
}, function(frames) {
for (var frame of frames) {
if (frame.url === 'https://example.com/') {
injectInFrame(tab.id, frame.frameId);
break;
}
}
});
});
webNavigation
选项看起来很简单但有两个主要缺点:
另一种方法是首先打开一个发送扩展消息的扩展页面,然后在chrome.runtime.onMessage
监听器的第二个参数中找到的元数据中找到frameId
(和选项卡ID) 。此代码比其他选项更复杂,但它更可靠,不需要任何其他权限。
framehelper.html
<script src="framehelper.js"></script>
framehelper.js
var parentOrigin = location.ancestorOrigins[location.ancestorOrigins.length - 1];
if (parentOrigin === location.origin) {
// Only send a message if the frame was opened by ourselves.
chrome.runtime.sendMessage(location.hash.slice(1));
}
要在您的扩展程序页面中运行的代码:
chrome.runtime.onMessage.addListener(frameMessageListener);
var randomMessage = 'Random message: ' + Math.random();
var f = document.createElement('iframe');
f.src = chrome.runtime.getURL('framehelper.html') + '#' + randomMessage;
document.body.appendChild(f);
function frameMessageListener(msg, sender) {
if (msg !== randomMessage) return;
var tabId = sender.tab.id;
var frameId = sender.frameId;
chrome.runtime.onMessage.removeListener(frameMessageListener);
// Note: This will cause the script to be run on the first load.
// If the frame redirects elsewhere, then the injection can seemingly fail.
f.addEventListener('load', function onload() {
f.removeEventListener('load', onload);
injectInFrame(tabId, frameId);
});
f.src = 'https://example.com';
}