升级或安装后重新注入 Chrome 扩展内容脚本

问题描述 投票:0回答:6

安装或升级我正在使用的 Chrome 扩展后,内容脚本(在清单中指定)不会重新注入,因此需要刷新页面才能使扩展正常工作。有没有办法强制再次注入脚本?

我相信我可以通过从清单中删除它们然后处理要在后台页面中注入的页面来以编程方式再次注入它们,但这不是一个好的解决方案。

我不想自动刷新用户的选项卡,因为这可能会丢失他们的一些数据。当您安装或升级扩展程序时,Safari 会自动刷新所有页面。

google-chrome-extension browser-extension content-script
6个回答
56
投票

有一种方法可以让内容脚本繁重的扩展在升级后继续运行,并使其在安装后立即运行。

安装/升级

安装方法是简单地遍历所有窗口中的所有选项卡,并以编程方式将一些脚本注入到具有匹配 URL 的选项卡中。

清单V3

清单.json:

"background": {"service_worker": "background.js"},
"permissions": ["scripting"],
"host_permissions": ["<all_urls>"],

这些 host_permissions 应该与内容脚本的

matches
相同。

背景.js:

chrome.runtime.onInstalled.addListener(async () => {
  for (const cs of chrome.runtime.getManifest().content_scripts) {
    for (const tab of await chrome.tabs.query({url: cs.matches})) {
      chrome.scripting.executeScript({
        target: {tabId: tab.id},
        files: cs.js,
      });
    }
  }
});

这是一个不处理帧的简化示例。您可以使用 getAllFrames API 并自己匹配 URL,请参阅 matching patterns 的文档。

清单V2

显然,您必须在 background pageevent page 脚本中声明 manifest.json:

"background": {
    "scripts": ["background.js"]
},

背景.js:

// Add a `manifest` property to the `chrome` object.
chrome.manifest = chrome.runtime.getManifest();

var injectIntoTab = function (tab) {
    // You could iterate through the content scripts here
    var scripts = chrome.manifest.content_scripts[0].js;
    var i = 0, s = scripts.length;
    for( ; i < s; i++ ) {
        chrome.tabs.executeScript(tab.id, {
            file: scripts[i]
        });
    }
}

// Get all windows
chrome.windows.getAll({
    populate: true
}, function (windows) {
    var i = 0, w = windows.length, currentWindow;
    for( ; i < w; i++ ) {
        currentWindow = windows[i];
        var j = 0, t = currentWindow.tabs.length, currentTab;
        for( ; j < t; j++ ) {
            currentTab = currentWindow.tabs[j];
            // Skip chrome:// and https:// pages
            if( ! currentTab.url.match(/(chrome|https):\/\//gi) ) {
                injectIntoTab(currentTab);
            }
        }
    }
});

历史琐事

在古老的 Chrome 26 和更早版本中,内容脚本可以恢复与后台脚本的连接。它已于 2013 年修复http://crbug.com/168263。您可以在此答案的早期版本中看到此技巧的示例。


29
投票

强制注入内容脚本而不刷新页面的唯一方法是通过编程注入。

您可以获取所有选项卡并使用 chrome 选项卡 API 将代码注入其中。 例如,您可以将清单版本存储在本地存储中,并且每次检查清单版本是否为旧版本(在后台页面中),如果是这样,您可以获得所有活动选项卡并以编程方式注入代码,或者任何其他可以让您确保扩展已更新。

使用以下方法获取所有标签:
chrome.tabs.query

并将您的代码注入所有页面

chrome.tabs.executeScript(tabId, {file: "content_script.js"});


9
投票

在你的后台脚本中试试这个。许多旧方法现在已被弃用,因此我重构了代码。对于我的使用,我只安装单个 content_script 文件。如果需要你可以迭代

chrome.runtime.getManifest().content_scripts
数组获取所有 .js 文件。

chrome.runtime.onInstalled.addListener(installScript);

function installScript(details){
    // console.log('Installing content script in all tabs.');
    let params = {
        currentWindow: true
    };
    chrome.tabs.query(params, function gotTabs(tabs){
        let contentjsFile = chrome.runtime.getManifest().content_scripts[0].js[0];
        for (let index = 0; index < tabs.length; index++) {
            chrome.tabs.executeScript(tabs[index].id, {
                file: contentjsFile
            },
            result => {
                const lastErr = chrome.runtime.lastError;
                if (lastErr) {
                    console.error('tab: ' + tabs[index].id + ' lastError: ' + JSON.stringify(lastErr));
                }
            })
        }
    });    
}

2
投票

Chrome 添加了一个方法来监听扩展的安装或升级事件。当这样的事件发生时,可以重新注入内容脚本。 https://developers.chrome.com/extensions/runtime#event-onInstalled


0
投票

由于https://bugs.chromium.org/p/chromium/issues/detail?id=168263,您的内容脚本和后台脚本之间的连接被切断。正如其他人所提到的,解决此问题的一种方法是重新注入内容脚本。 这个 StackOverflow 答案中有一个粗略的概述。

主要的棘手部分是在注入新的内容脚本之前有必要“破坏”您当前的内容脚本。销毁可能非常棘手,因此减少必须销毁的状态量的一种方法是制作一个小的可重新注入脚本,它通过 DOM 与您的主要内容脚本对话。


-14
投票

你不能在你升级的css或js末尾加上

?ver=2.10
吗?

"content_scripts": [ {
      "css": [ "css/cs.css?ver=2.10" ],
      "js": [ "js/contentScript.js?ver=2.10" ],
      "matches": [ "http://*/*", "https://*/*" ],
      "run_at": "document_end"
   } ],
© www.soinside.com 2019 - 2024. All rights reserved.