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

时间:2012-06-12 10:00:05

标签: google-chrome-extension browser-extension content-script

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

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

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

6 个答案:

答案 0 :(得分:28)

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

安装

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

显然,您必须在manifest.json中声明的background pageevent page脚本中执行此操作:

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

background.js:

// Add a `manifest` property to the `chrome` object.
chrome.manifest = chrome.app.getDetails();

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);
            }
        }
    }
});

升级

升级方法依赖于在禁用,卸载或升级扩展后注入内容脚本的事实。

进行端口连接时,会添加onDisconnect处理程序。这在断开连接事件后等待一秒钟,然后尝试重新连接。如果失败,则会触发另一个onDisconnect,以便再次进行该过程,直到建立连接。它并不完美,但它确实有效。

内容脚本:

var port;

// Attempt to reconnect
var reconnectToExtension = function () {
    // Reset port
    port = null;
    // Attempt to reconnect after 1 second
    setTimeout(connectToExtension, 1000 * 1);
};

// Attempt to connect
var connectToExtension = function () {

    // Make the connection
    port = chrome.runtime.connect({name: "my-port"});

    // When extension is upgraded or disabled and renabled, the content scripts
    // will still be injected, so we have to reconnect them.
    // We listen for an onDisconnect event, and then wait for a second before
    // trying to connect again. Becuase chrome.runtime.connect fires an onDisconnect
    // event if it does not connect, an unsuccessful connection should trigger
    // another attempt, 1 second later.
    port.onDisconnect.addListener(reconnectToExtension);

};

// Connect for the first time
connectToExtension();

答案 1 :(得分:20)

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

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

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

并将您的代码注入所有页面中 chrome.tabs.executeScript(tabId, {file: "content_script.js"});

答案 2 :(得分:2)

在后台脚本中尝试。现在已淘汰了许多旧方法,因此我重构了代码。对于我来说,我只安装单个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));
                }
            })
        }
    });    
}

答案 3 :(得分:0)

Chrome已添加一种方法来侦听扩展程序的安装或升级事件。发生此类事件时,可以重新注入内容脚本。 https://developers.chrome.com/extensions/runtime#event-onInstalled

答案 4 :(得分:0)

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

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

答案 5 :(得分:-7)

你不能在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"
   } ],