草庐IT

javascript - Chrome 扩展 : Checking if content script has been injected or not

coder 2024-05-18 原文

我正在开发 Chrome 扩展程序。我没有使用 manifest.json 来匹配所有 URL 的内容脚本,而是在用户单击扩展图标时通过调用 chrome.tabs.executeScript 懒惰地注入(inject)内容脚本。

我正在尝试避免多次执行脚本。所以我的内容脚本中有以下代码:

if (!window.ALREADY_INJECTED_FLAG) {
    window.ALREADY_INJECTED_FLAG = true
    init() // <- All side effects go here
}

问题 #1,每次点击扩展图标时,这是否足够安全以天真地调用 chrome.tabs.executeScript?换句话说,这是幂等的吗?

问题 #2chrome.tabs.insertCSS 是否有类似的方法?

似乎无法在背景脚本中检查内容脚本注入(inject)状态,因为它无法访问网页的 DOM。我尝试了一种 ping/pong 方法来检查任何内容脚本实例是否存在。但这引入了设计 ping 超时的开销和复杂性。

问题 #3,后台脚本检查内容脚本注入(inject)状态的任何更好的方法,这样我就可以防止每次调用 chrome.tabs.executeScript用户点击了图标?

提前致谢!

最佳答案

is this safe enough to naively call chrome.tabs.executeScript every time the extension icon got clicked? In other words, is this idempotent?

  1. 是的,除非您的内容脚本修改了页面的 DOM 并且重新加载了扩展程序(通过设置页面、更新等方式重新加载)。在这种情况下,您的旧内容脚本将不再在扩展的上下文中运行,因此它不能使用扩展 API,也不能直接与您的扩展通信。

is there a similar method for chrome.tabs.insertCSS?

  1. 不,chrome.tabs.insertCSS 没有包含保护。但是再次插入相同的样式表不会改变页面的外观,因为所有规则都具有相同的 CSS 特性,并且在这种情况下最后一个样式表优先。但是,如果样式表与您的扩展紧密耦合,那么您可以简单地使用 executeScript 注入(inject)脚本,检查它是否是第一次注入(inject),如果是,则插入样式表(参见下面的示例)。

any better method for background script to check the inject status of content script, so I can just prevent calling chrome.tabs.executeScript every time when user clicked the icon?

  1. 您可以向选项卡 (chrome.tabs.sendMessage) 发送消息,如果您没有收到回复,则假设选项卡中没有内容脚本并插入内容脚本。

2 的代码示例

在你的弹出/背景脚本中:

chrome.tabs.executeScript(tabId, {
    file: 'contentscript.js',
}, function(results) {
    if (chrome.runtime.lastError || !results || !results.length) {
        return;  // Permission error, tab closed, etc.
    }
    if (results[0] !== true) {
        // Not already inserted before, do your thing, e.g. add your CSS:
        chrome.tabs.insertCSS(tabId, { file: 'yourstylesheet.css' });
    }
});

使用 contentScript.js 您有两个解决方案:

  1. 直接使用 Windows:不推荐,因为每个人都可以更改变量和 Is there a spec that the id of elements should be made global variable?
  2. 使用 chrome.storage API:您可以与其他窗口共享 contentScript 的状态(您可以看到缺点,这根本不是缺点,是您需要请求对 Manifest.json 的权限。但这没关系,因为这是正确的方法。

选项 1:contentscript.js:

// Wrapping in a function to not leak/modify variables if the script
// was already inserted before.
(function() {
    if (window.hasRun === true)
        return true;  // Will ultimately be passed back to executeScript
    window.hasRun = true;
    // rest of code ... 
    // No return value here, so the return value is "undefined" (without quotes).
})(); // <-- Invoke function. The return value is passed back to executeScript

请注意,明确检查 window.hasRun 的值很重要(上面示例中的 true),否则它可能是一个自动创建的全局变量具有 id="hasRun" 属性的 DOM 元素,参见 Is there a spec that the id of elements should be made global variable?

选项 2:contentscript.js(使用 chrome.storage.sync,您也可以使用 chrome.storage.local)

    // Wrapping in a function to not leak/modify variables if the script
    // was already inserted before.
    (chrome.storage.sync.get(['hasRun'], (hasRun)=>{
      const updatedHasRun = checkHasRun(hasRun); // returns boolean
      chrome.storage.sync.set({'hasRun': updatedHasRun});
    ))()

function checkHasRun(hasRun) {
        if (hasRun === true)
            return true;  // Will ultimately be passed back to executeScript
        hasRun = true;
        // rest of code ... 
        // No return value here, so the return value is "undefined" (without quotes).
    }; // <-- Invoke function. The return value is passed back to executeScript

关于javascript - Chrome 扩展 : Checking if content script has been injected or not,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34528785/

有关javascript - Chrome 扩展 : Checking if content script has been injected or not的更多相关文章

  1. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  2. c - mkmf 在编译 C 扩展时忽略子文件夹中的文件 - 2

    我想这样组织C源代码:+/||___+ext||||___+native_extension||||___+lib||||||___(Sourcefilesarekeptinhere-maycontainsub-folders)||||___native_extension.c||___native_extension.h||___extconf.rb||___+lib||||___(Rubysourcecode)||___Rakefile我无法使此设置与mkmf一起正常工作。native_extension/lib中的文件(包含在native_extension.c中)将被完全忽略。

  3. ruby-on-rails - 向 Rails 3 添加 Ruby 扩展方法的最佳实践? - 2

    我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion

  4. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

  5. ruby - 下载位置 Selenium-webdriver Cucumber Chrome - 2

    我将Cucumber与Ruby结合使用。通过Selenium-Webdriver在Chrome中运行测试时,我想将下载位置更改为测试文件夹而不是用户下载文件夹。我当前的chrome驱动程序是这样设置的:Capybara.default_driver=:seleniumCapybara.register_driver:seleniumdo|app|Capybara::Selenium::Driver.new(app,:browser=>:chrome,desired_capabilities:{'chromeOptions'=>{'args'=>%w{window-size=1920,1

  6. ruby - 如何在 ruby​​ 中复制目录结构,不包括某些文件扩展名 - 2

    我想编写一个ruby​​脚本来递归复制目录结构,但排除某些文件类型。因此,给定以下目录结构:folder1folder2file1.txtfile2.txtfile3.csfile4.htmlfolder2folder3file4.dll我想复制这个结构,但不包含.txt和.cs文件。因此,生成的目录结构应如下所示:folder1folder2file4.htmlfolder2folder3file4.dll 最佳答案 您可以使用查找模块。这是一个代码片段:require"find"ignored_extensions=[".cs"

  7. ruby - 扩展类和实例 - 2

    这个问题有两个部分。在RubyProgrammingLanguage一书中,有一个使用模块扩展字符串对象和类的示例(第8.1.1节)。第一个问题。为什么如果您使用新方法扩展类,然后创建该类的对象/实例,则无法访问该方法?irb(main):001:0>moduleGreeter;defciao;"Ciao!";end;end=>nilirb(main):002:0>String.extend(Greeter)=>Stringirb(main):003:0>String.ciao=>"Ciao!"irb(main):004:0>x="foobar"=>"foobar"irb(main):

  8. ruby - 动态扩展现有方法或覆盖 ruby​​ 中的发送方法 - 2

    假设我们有A、B、C类。Adefself.inherited(sub)#metaprogramminggoeshere#takeclassthathasjustinheritedclassA#andforfooclassesinjectprepare_foo()as#firstlineofmethodthenrunrestofthecodeenddefprepare_foo#=>prepare_foo()neededhere#somecodeendendBprepare_foo()neededhere#somecodeendend如您所见,我正在尝试将foo_prepare()调用注入

  9. ruby - 在 Mechanize 中使用 JavaScript 单击链接 - 2

    我有这个:AccountSummary我想单击该链接,但在使用link_to时出现错误。我试过:bot.click(page.link_with(:href=>/menu_home/))bot.click(page.link_with(:class=>'top_level_active'))bot.click(page.link_with(:href=>/AccountSummary/))我得到的错误是:NoMethodError:nil:NilClass的未定义方法“[]” 最佳答案 那是一个javascript链接。Mechan

  10. ruby-on-rails - 如何扩展 Ruby Test::Unit 断言以包含 assert_false? - 2

    显然在Test::Unit中没有assert_false。您将如何通过扩展断言并添加文件config/initializers/assertions_helper.rb来添加它?这是最好的方法吗?我不想修改test/unit/assertions.rb。顺便说一句,我不认为这是多余的。我使用的是assert_equalfalse,something_to_evaluate。这种方法的问题是很容易意外使用assertfalse,something_to_evaluate。这将始终失败,不会引发错误或警告,并且会在测试中引入错误。 最佳答案

随机推荐