Home  >  Q&A  >  body text

Reinject content scripts: a necessary step after a Chrome extension upgrade or installation

<p>After installing or upgrading a Chrome extension I'm developing, the content script (specified in the manifest) is not re-injected, so a page refresh is required for the extension to work properly. Is there a way to force the script to be re-injected? </p> <p>I believe I could inject them again by programmatically removing them from the manifest and then processing the page to be injected in a background page, but that's not a good solution. </p> <p>I don't want to automatically refresh the user's tabs as this might result in some data loss. Safari automatically refreshes all pages when an extension is installed or upgraded. </p>
P粉066224086P粉066224086423 days ago522

reply all(2)I'll reply

  • P粉807239416

    P粉8072394162023-08-25 11:24:31

    The only way to force the injection of a content script without refreshing the page is through programmatic injection.

    You can use Chrome's Tag API to get all tags and inject code into them. For example, you could store a version number in local storage and every time you check if the version number in the background page is out of date (if it is), you could get all active tags and inject your code programmatically, or whatever Other solutions to ensure the extension is updated.

    Use the following code to get all tags:
    chrome.tabs.query

    and inject your code into all pages
    chrome.tabs.executeScript(tabId, {file: "content_script.js"});

    reply
    0
  • P粉158473780

    P粉1584737802023-08-25 00:54:45

    There is a way to make content script-heavy extensions continue to work properly after upgrading and have them take effect immediately after installation.

    Installation/Upgrade

    The way to install it is to simply loop through all tabs in all windows and programmatically inject some script in the tab with matching URL.

    ManifestV3

    manifest.json:

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

    These host_permissions should be the same as the matches of the content script.

    background.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,
          });
        }
      }
    });
    

    This is a simplified example that does not deal with frames. You can use the getAllFrames API and match URLs yourself, see the matching patterns documentation.

    ManifestV2

    Obviously you have to do this in a background page or event page script declared in manifest.json:

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

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

    Historical Fun Facts

    In ancient Chrome 26 and earlier, content scripts could restore connections to background scripts. This was fixed in 2013http://crbug.com/168263. You can see an example of this technique in an earlier version of this answer.

    reply
    0
  • Cancelreply