检测Chrome扩展程序内容脚本是否已注入/内容脚本包含保护

8
当选项卡更新时,我希望执行内容脚本函数。问题在于,有时选项卡更新是ajax(无需重新加载页面),但仍更改页面的URL。因此,旧的内容脚本注入仍存在于页面上。结果是多个实例的内容脚本被注入并在同一页面上运行。
因此,我正在寻找一种机制,只有在之前没有注入相同的内容脚本时才注入内容脚本。有什么想法吗?

那么,我很想知道除了尝试发送消息并等待内容脚本响应之外,您是否能找到有效的解决方案? - c00000fd
@c00000fd:重新审视这个问题,我认为Rob W的解决方案更简单,因为它不依赖于Chrome消息传递。 - Keven Wang
2个回答

14
你可以尝试向内容脚本发送消息(消息传递)。如果内容脚本成功返回响应,则意味着内容脚本已经存在,否则将返回一个空响应,您可以检查空响应并注入内容脚本。 背景:
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
    chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
        if (response) {
            console.log("Already there");
        }
        else {
            console.log("Not there, inject contentscript");
        }
    });
});

内容脚本:

chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse) {
        if (request.greeting == "hello")
            sendResponse({message: "hi"});
 });

4
尝试过了。但你只知道sendMessage回调函数中的错误,而无法捕获在回调函数中抛出的错误。 - Keven Wang
1
这个答案可能适用于早期的Chrome版本,但今天不行了... - Philip Enc

8

实现包含保护非常容易:

(function() {
    // Comparing to a literal value to prevent matching a DOM element with id="hasRun"
    // https://dev59.com/-3A75IYBdhLWcg3wK1wp/do-dom-tree-elements-with-ids-become-global
    if (window.hasRun === true) return;
    window.hasRun = true;
    // Rest of code
})();

如果您想以编程方式注入内容脚本,考虑使用webNavigation事件之一(例如onCommitted),而不是chrome.tabs.onUpdated。与tabs事件不同,webNavigation事件也会触发框架内导航,并提供了一种预先声明URL过滤器的方法。

了解WebNavigation很好!有了这个包含保护,代码本身仍然会被注入。经过多次导航后,可能会有许多内容脚本注入到此页面中。这会导致任何性能问题吗?是否有一种方法可以通过检查不存在任何内容脚本来进行注入? - Keven Wang
1
同一扩展程序的所有内容脚本在相同的上下文中运行。不必担心性能。 - Rob W
1
同一扩展程序的所有内容脚本在相同的上下文中运行... 直到重新加载扩展程序。如果您重新加载扩展程序,请小心 - 这将导致两个扩展程序同时运行。 - vaughan
@RobW:抱歉打扰这个旧帖子,但我并没有真正理解所提出的实现方式。window.hasRun是什么?这段代码应该从哪里运行? - c00000fd
@c00000fd hasRun 是一个任意选择的全局变量名称,应该包装内容脚本,以便只执行一次。 - Rob W

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接