preface

This article is aimed at getting started with Chrome development. If you need further development, you can go to the Chrome official website to learn. The official website provides a demo to modify the background color of the web page, you can click download, if you have problems with the download, you can go to Github

This article will list some common concepts, including five JS type comparisons, six cores, message communication and some dynamic injection, packaged publishing, etc.

This article concludes with a Chrome demo that turns pages into dark mode

The demo effect is as follows:

The plugin will be highlighted on the JD.com TAB page and the color will be gray on other TAB pages. How to do this is explained in the demo

What is the Chrome plugin?

The real name of chrome plug-in mentioned in this article should be Chrome Extension (Chrome Extension), the real plug-in refers to the lower level of browser function Extension, may need to have a certain understanding of Chrome source code to develop.

The Chrome add-ons in this article refer to some of the Chrome extensions we use everyday.

Extensions are small software programs that customize the browsing experience. They enableusers to tailor Chrome functionality and behavior to individual needs or preferences. They are built on web technologies  such as HTML, JavaScript, and CSS.Copy the code

Chrome Extension is a small software program that allows you to customize your browsing experience. They allow users to customize Chrome features and behavior based on their personal needs or preferences. It is built on Web technologies such as HTML, JavaScript, and CSS.

Why learn Chrome Extension development?

With Chrome Extension development, we can easily customize our own browser, enhance some browser functions, strengthen our learning ability, and also have some other aspects of our business thinking.

More skills, more skills, maybe when you go to the next company, you will have more skills.

Six core

The six core concepts include Manifest Format, Manage Events, Design User Interface, Content Scripts, Declare Permissions and Warn Users, and Give Users Options

Manifest Format – The official documentation

Each Chrome Extension comes with a MANIFEST file in JSON format called manifest.json that provides important information. Used to configure all plugin-related configurations, must be placed under the project root directory. The simple configuration is as follows

{
  "name": "TimeStone"."manifest_version": 2."version": "1.0"."description": "TimeStone Extension"."page_action": {
    "default_icon": "images/icon.png"."default_title": "TimeStone plug-in"."default_popup": "html/home.html"
  },
  "background": {
    "scripts": ["js/background.js"]},"options_page": "html/options.html"."homepage_url": "https://juejin.cn/user/4230576473387773"."permissions": [
    "tabs"."storage"."activeTab"]}Copy the code

The configuration is described as follows: [Note] It must be marked in bold and highlighted is recommended

  • Manifest_version – You have to have it, and it has to be 2
  • Name – Plug-in name
  • Version – Indicates the version number
  • Description – description
  • The ICONS – icon
  • Homepage_url – Plugin homepage, ha ha, I usually set to my own gold digging homepage
  • background- The background JS or background page that will always be resident, can be specified in two ways
    "background"If you specify JS, a background page will be generated automatically"page": "background.html"
     	//"scripts": ["js/background.js"]}Copy the code
  • Browser_action, page_Action, app- Displayed in the upper right corner of the browser
    "browser_action": 
     {
     	"default_icon": "img/icon.png"// The title of the hovering icon, optional"default_title": "This is a sample Chrome plugin"."default_popup": "popup.html"
     }
     "page_action":
     {
     	"default_icon": "img/icon.png"."default_title": "I am pageAction"."default_popup": "popup.html"
     }
    Copy the code
  • permissions- Set plug-in permission application
    "permissions":
     [
     	"contextMenus"// Right-click the menu"tabs", / / label"notifications"/ / notice"webRequest", // Web request"webRequestBlocking"."storage", // Plug-in local storage]Copy the code
  • Web_accessible_resources – A list of plug-in resources that can be accessed directly by a normal page
  • Chrome_url_overrides – overrides the browser default page
  • Options_ui – Plugin configuration page writing
  • omnibox- Register a keyword to the address bar to provide search suggestions. Only one keyword can be set
    "omnibox": { "keyword" : "rick" }
    Copy the code
  • Default_locale – The default language
  • Devtools_page – DevTools page entry. Note that it can only point to an HTML file, not a JS file

Manage Events with Background Scripts -The official documentation

Chrome Ex is an event-based program used to modify or enhance the Chrome browser experience. Events are browser triggers, for example, to navigate to a new page, delete a bookmark or close a TAB. The extender monitors these events in its background scripts and then responds with specified instructions.

Background pages are loaded when needed and unloaded when idle. Some examples of events include:

  • The extension is first installed or updated to a new version.
  • The background page is listening for an event and has scheduled the event.
  • Content scripts or other extensions send messages.
  • Another view in the program (for example, the pop-up window) to invoke the runtime. GetBackgroundPage.

Valid background scripts remain dormant until events listen for fire, react to specified instructions, and then unload.

Register Background Scripts

Configure it in manifest.json as follows

{
  "name": "Awesome Test Extension"."background": {
    "scripts": ["js/background.js"]."persistent": false},... }Copy the code

Initialize the extension

Listen for runtime.onInstalled events, which can be used to set state or perform an initialization. Take the context menu.

 chrome.runtime.onInstalled.addListener(function() {
    chrome.contextMenus.create({
      "id": "sampleContextMenu"."title": "Sample Context Menu"."contexts": ["selection"]}); });Copy the code

Setting up listeners

Build background scripts around extended-dependent events. Defining functionally-relevant events puts background scripts to sleep until they are fired and prevents extensions from missing important triggers.

Listeners must be synchronously registered from the page.

 chrome.runtime.onInstalled.addListener(function() {
    chrome.contextMenus.create({
      "id": "sampleContextMenu"."title": "Sample Context Menu"."contexts": ["selection"]}); }); // This will run when a bookmark is created. chrome.bookmarks.onCreated.addListener(function() {
    // do something
  });
Copy the code

Do not register listeners asynchronously, because they will not be triggered correctly.

 chrome.runtime.onInstalled.addListener(function() {
    // ERROR! Events must be registered synchronously from the start of
    // the page.
    chrome.bookmarks.onCreated.addListener(function() {
      // do something
    });
  });
Copy the code

An extender can remove removeListener listeners from its background scripts with a call. If all listeners for an event are removed, Chrome will no longer load the extension’s background script for the event.

  chrome.runtime.onMessage.addListener(function(message, sender, reply) {
      chrome.runtime.onMessage.removeListener(event);
  });
Copy the code

Screening event

Use an API that supports event filters to limit listeners to cases where the extension is concerned. If the add-in is listening tabs. OnUpdated event, please try to use webNavigation. OnCompleted events with a filter, because tabs API does not support filters.

chrome.webNavigation.onCompleted.addListener(function() {
      alert("This is my favorite website!");
  }, {url: [{urlMatches : 'https://www.google.com/'}]});
Copy the code

Respond to events

After the event is triggered, there are listeners that can trigger functionality. To react to an event, construct the desired response inside the listener event.

  chrome.runtime.onMessage.addListener(function(message, callback) {
    if(the message data = ="setAlarm ") {chrome.alarms. Create ({delayInMinutes: 5})}else if(the message data = = "runLogic") {chrome. Tabs. ExecuteScript ({file:'logic.js'});
    } else if(the message data = = "changeColor") {chrome. Tabs. ExecuteScript ({code:'document.body.style.backgroundColor="orange"'});
    };
  });
Copy the code

Uninstalling background Scripts

Data should be saved periodically in case important information is lost and the extension crashes to receive onSuspend. Using the Storage API can help with this task.

 chrome.storage.local.set({variable: variableInformation});

Copy the code

If the extension uses messaging, make sure all ports are turned off. Background scripts are not unloaded until all message ports are closed. Listen for the runtime. Port. OnDisconnect events will provide insights about open Port when closed. Turn them off manually using Runtime.port.disconnect.

 chrome.runtime.onMessage.addListener(function(message, callback) {
    if (message == 'hello') {
      sendResponse({greeting: 'welcome! '})}else if (message == 'goodbye') { chrome.runtime.Port.disconnect(); }});Copy the code

You can observe the life of background scripts by monitoring when an extension’s entry appears and disappears from Chrome’s task manager.

After a few seconds of inactivity, the background script unloads itself. If you need a last-minute cleanup, listen to the Runtime.onsuspend event.

  chrome.runtime.onSuspend.addListener(function() {
    console.log("Unloading.");
    chrome.browserAction.setBadgeText({text: ""});
  });
Copy the code

In contrast, however, persistent data runtime.onsuspend should be preferred. It doesn’t allow for as much cleanup as possible, and it doesn’t help when it crashes.

Design User Interface – The official documentation

Extending the user interface should be purposeful and minimal. Like the extension itself, the UI should customize or enhance the browsing experience without becoming a distraction.

Enable the extension on all pages

Use browser_action when the extender’s functionality is available in most cases.

  • Register browser_action in manifest.json

      {
      "name": "My Awesome browser_action Extension"."browser_action": {... }... }Copy the code

    Declare “browser_action” and keep the icon in color to indicate that the extension is available to the user.

  • Add a badge

    A badge displays some text on an icon and a colored banner containing up to four characters above the browser icon. They can only be used by extensions declared by “browser_action” in its manifest.

    Call to set the text of the badge, and call to set the color of the banner. chrome.browserAction.setBadgeText chrome.browserAction.setBadgeBackgroundColor

Activate the extension on the selected page

Use page_action when the extender’s functionality is only available under defined conditions.

  • inmanifest.jsonregisteredpage_action
      {
      "name": "My Awesome page_action Extension"."page_action": {... }... }Copy the code

    The “page_action” declaration will color the icon only if the extension is available to the user, otherwise it will appear in grayscale.

  • Define the activation extension rule Through the script in the background of chrome. DeclarativeContent runtime. OnInstalled cut with the listener, and define when extended the rules may be used. Example page manipulation through A URL Extension sets a condition that the URL must contain “g”. If the conditions are met, the extension call is made. DeclarativeContent. ShowPageAction () [note] : here is the answer at jd.com TAB page, plug-in highlights show, in other color will be grey TAB page

      chrome.runtime.onInstalled.addListener(function() {
      // Replace all rules ...
      chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
        // With a new rule ...
        chrome.declarativeContent.onPageChanged.addRules([
          {
            // That fires when a page's URL contains a 'g'... conditions: [ new chrome.declarativeContent.PageStateMatcher({ pageUrl: { urlContains: 'jd.com' }, }) ], // And shows the extension's page action.
            actions: [ new chrome.declarativeContent.ShowPageAction() ]
          }
        ]);
      });
    });
    Copy the code
  • Using “page_Action”, an extender can dynamically activate and disable PageAction.hide by calling pageAction.show and.

    The MAPPY sample extension scans web pages for addresses and displays pop-up locations on static maps. Because the extension depends on the content of the page, there is no way to declare rules to predict which pages will be relevant. Instead, if the address is found on the page, it calls pageAction.show to color the icon and signal that the extension is available on the TAB.

    chrome.runtime.onMessage.addListener(function(req, sender) {
      chrome.storage.local.set({'address': req.address})
      chrome.pageAction.show(sender.tab.id);
      chrome.pageAction.setTitle({tabId: sender.tab.id, title: req.address});
    });
    Copy the code

Provide extension ICONS

The extension requires at least one icon to represent it. Although you can accept any WebKit supported format, including BMP, GIF, ICO, and JPEG, ICONS provided in PNG format provide the best visual effects.

  • Specifies the toolbar icon

    The toolbar-specific ICONS are registered in fields in the Manifest browser_action or page_action under manifest.json “default_icon”. Encourage inclusion of multiple dimensions to accommodate 16 inclination space. At least 16×16 and 32×32 sizes are recommended.

     {
      "name": "My Awesome page_action Extension"."page_action": {
        "default_icon": {
          "16": "extension_toolbar_icon16.png"."32": "extension_toolbar_icon32.png"}}... }Copy the code

    All ICONS should be square, otherwise they may be distorted. If no icon is provided, Chrome adds a generic icon to the toolbar.

  • Create and register additional ICONS – Use additional ICONS of the following sizes outside the toolbar.

    Size of the icon The icon to use
    16×16 The site icon on the extension page
    32×32 Windows computers typically need this size. Providing this option will prevent size distortion from decreasing by 48×48 option.
    48×48 Displayed on the extension Management page
    128×128 Displayed in the installation and Chrome Webstore
    {
        "name": "My Awesome Extension"."icons": {
          "16": "extension_icon16.png"."32": "extension_icon32.png"."48": "extension_icon48.png"."128": "extension_icon128.png"}... }Copy the code

Other UI functions

  • Popup

    A pop-up window is an HTML file that appears in a special window when the user clicks on a toolbar icon. Pop-ups work much like web pages; It can contain links to stylesheet and script tags, but does not allow inline JavaScript.

    The Drink Water Event sample pop-up window shows the timer options available. The user sets up the alert by clicking one of the buttons provided.

<html>
    <head>
      <title>Water Popup</title>
    </head>
    <body>
        <img src='./stay_hydrated.png' id='hydrateImage'>
        <button id='sampleSecond' value='0.1'>Sample Second</button>
        <button id='15min' value='15'>15 Minutes</button>
        <button id='30min' value='30'>30 Minutes</button>
        <button id='cancelAlarm'>Cancel Alarm</button>
     <script src="popup.js"></script>
    </body>
  </html>
Copy the code

The Settings above can live in browser_action or page_action

{
    "name": "Drink Water Event"."browser_action": {
      "default_popup": "popup.html"}... }Copy the code

Pop-ups can also be set dynamically by calling or. BrowserAction. SetPopup, pageAction. SetPopup

chrome.storage.local.get('signed_in'.function(data) {
    if (data.signed_in) {
      chrome.browserAction.setPopup({popup: 'popup.html'});
    } else {
      chrome.browserAction.setPopup({popup: 'popup_sign_in.html'}); }});Copy the code
  • Tooltip – Use Tooptip to provide short instructions or instructions to the user when hovering over a browser icon.

browser_action
page_action

  {
  "name": "Tab Flipper"."browser_action": {
      "default_title": "Press Ctrl(Win)/Command(Mac)+Shift+Right/Left to flip tabs"}... }Copy the code

The contents of Tooltips can also be updated with methods browserAction.setTitle and PageAction.setTitle.

 chrome.browserAction.onClicked.addListener(function(tab) {
    chrome.browserAction.setTitle({tabId: tab.id, title: "You are on tab:" + tab.id});
  });
Copy the code
  • Omnibox users can invoke extension functionality through the Omnibox. Include the “Omnibox” field in the listing and specify the keyword. New TAB in url column search sample extension using “NT” as the keyword.
 {
    "name": "Omnibox New Tab Search". \..."omnibox": { "keyword" : "nt" },
    "default_icon": {
      "16": "newtab_search16.png"."32": "newtab_search32.png"}... }Copy the code

When the user enters “nt” in the utility box, it activates the extension. To signal the user, it grays the 16×16 icon provided and includes it in the multifunction box next to the extension.

This extension listens for events. When triggered, the extension opens a new TAB containing a Google search for the user’s entry. omnibox.onInputEntered

chrome.omnibox.onInputEntered.addListener(function(text) {
  // Encode user input for special characters , / ? : @ & = + $ #
  var newURL = 'https://www.google.com/search?q=' + encodeURIComponent(text);
  chrome.tabs.create({ url: newURL });
});

Copy the code
  • Context Menu – Right-click Menu

    Apply permission on contextMenus,

      {
      "name": "Global Google Search"."permissions": ["contextMenus"."storage"]."icons": {
        "16": "globalGoogle16.png"."48": "globalGoogle48.png"."128": "globalGoogle128.png"}... }Copy the code

    The 16×16 icon appears next to the new menu item.

contextMenus.create
background script
runtime.onInstalled

const kLocales = {
    'com.au': 'Australia'.'com.br': 'Brazil'.'ca': 'Canada'.'cn': 'China'.'fr': 'France'.'it': 'Italy'.'co.in': 'India'.'co.jp': 'Japan'.'com.ms': 'Mexico'.'ru': 'Russia'.'co.za': 'South Africa'.'co.uk': 'United Kingdom'
  };
 chrome.runtime.onInstalled.addListener(function() {
    for (let key of Object.keys(kLocales)) {
      chrome.contextMenus.create({
        id: key,
        title: kLocales[key],
        type: 'normal',
        contexts: ['selection']}); }});Copy the code
  • Commands extensions can define specific Commands and bind them to composite keys. Register the required commands with the commands
{
    "name": "Tab Flipper"."commands": {
      "flip-tabs-forward": {
        "suggested_key": {
          "default": "Ctrl+Shift+Right"."mac": "Command+Shift+Right"
        },
        "description": "Flip tabs forward"
      },
      "flip-tabs-backwards": {
        "suggested_key": {
          "default": "Ctrl+Shift+Left"."mac": "Command+Shift+Left"
        },
        "description": "Flip tabs backwards"}}... }Copy the code

Commands can be used to provide new or alternative browser shortcuts. The Tab Flipper sample extension listens to Commands. OnCommand event background script for each registered combination and defines functionality.

  chrome.commands.onCommand.addListener(function(command) {
    chrome.tabs.query({currentWindow: true}, function(tabs) {
      // Sort tabs according to their index in the window.
      tabs.sort((a, b) => { return a.index < b.index; });
      let activeIndex = tabs.findIndex((tab) => { return tab.active; });
      let lastTab = tabs.length - 1;
      let newIndex = -1;
      if (command= = ='flip-tabs-forward')
        newIndex = activeIndex === 0 ? lastTab : activeIndex - 1;
      else  // 'flip-tabs-backwards'
        newIndex = activeIndex === lastTab ? 0 : activeIndex + 1;
      chrome.tabs.update(tabs[newIndex].id, {active: true, highlighted: true});
    });
  });
Copy the code
  • The Override Pages extension can Override the browser’s HTML with its ownNew TABbookmarksPage. It can contain specialized logic and styles, but does not allow inline JavaScript. A single extension is limited to covering one of three possible pages.

The registration method is as follows

 {
   "name": "Awesome Override Extension"."chrome_url_overrides" : {
     "newtab": "override_page.html"."bookmarks": "book.html"},... }Copy the code
<html>
  <head>
   <title>New Tab</title>
  </head>
  <body>
     <h1>Hello World</h1>
   <script src="logic.js"></script>
  </body>
 </html>
Copy the code

Content Scripts – The official documentation

Content scripts are files that run in the context of a web page. Using the standard Document Object Model (DOM), they can read the details of a web page visited by the browser, make changes to it and pass the information to its parent extension.

Content scripting capabilities

Content scripts can access the Chrome API used by their parent extension by exchanging messages with the extension. They can also use the URL to access the extension file, Chrome.runtime.geturl () and use the same results as any other URL.

  //Code for displaying <extensionDir>/images/myimage.png:
  var imgURL = chrome.runtime.getURL("images/myimage.png");
  document.getElementById("someImage").src = imgURL;
Copy the code

Content scripts also have access to the following apis

  • i18n
  • storage
  • runtime:
    • connect
    • getManifest
    • getURL
    • id
    • onConnect
    • onMessage
    • sendMessage

Way to work

Content scripts run in an isolated world, allowing content scripts to align with JavaScript’s environment for changes without colliding with pages or other content scripts.

The extension can run in a Web page with code similar to the following example.

  <html>
    <button id="mybutton">click me</button>
    <script>
      var greeting = "hello, ";
      var button = document.getElementById("mybutton");
      button.person_name = "Bob";
      button.addEventListener("click".function() {
        alert(greeting + button.person_name + ".");
      }, false);
    </script>
  </html>
Copy the code

This extension can inject the following content scripts.

 var greeting = "hola, ";
  var button = document.getElementById("mybutton");
  button.person_name = "Roberto";
  button.addEventListener("click".function() {
    alert(greeting + button.person_name + ".");
  }, false);
Copy the code

If this button is pressed, two alarms will appear simultaneously.

The isolated world does not allow content scripts, extensions and web pages to access any variables or functions created by other variables or functions. This also enables content scripts to enable functionality that web pages should not access.

Video learning link

Inject Scripts – Inject Scripts

Content scripts can be injected programmatically or declaratively.

  • Programmatically injected

    Use program injection for content scripts that need to be run under specific circumstances. To inject programmatic content scripts, provide activeTab permissions in the manifest. This grants secure access to the active site host and temporary access to TAB permissions, allowing content scripts to run on the current active TAB without specifying cross-domain permissions.

     {
      "name": "My extension"."permissions": [
        "activeTab"],... }Copy the code

    Content scripts can be injected as code.

      chrome.runtime.onMessage.addListener(
      function(message, callback) {
        if"ChangeColor (message = =") {chrome. Tabs. ExecuteScript ({code:'document.body.style.backgroundColor="orange"'}); }});Copy the code

You can also specify files

 chrome.runtime.onMessage.addListener(
   function(message, callback) {
     if(message = = "runContentScript") {chrome. Tabs. ExecuteScript ({file:'contentScript.js'}); }});Copy the code
  • Declarative injection is used for content scripts that run automatically on a specified page. The declarative injection script is in the"content_scripts"Register in the listing under the field. They can include JavaScript files and/or CSS files. All automatically run content scripts must be specifiedMatch the pattern
{
 "name": "My extension"."content_scripts": [{"matches": ["http://*.nytimes.com/*"]."css": ["myStyles.css"]."js": ["contentScript.js"]}],... }Copy the code
The name of the type describe
matches array of strings Needs. Specifies which pages this content script will be injected into. For more details on the syntax of these strings, see”Match the patternFor information on how to exclude urls, seeMatch patterns and globals”.
css array of strings Optional. A list of CSS files to insert that match the page. Before any DOM is constructed or displayed for the page, they are injected in the order in which they appear in this array.
js array of strings Optional. A list of JavaScript files to insert that match the page. These are injected in the order in which they appear in the array.
match_about_blank boolean Optional. Whether the script should inject matches into the About :blank parent frame or open frames that match one of the declared patterns in. The default is false.
exclude_matches array of strings Optional. Exclude pages where this content script will be injected. For more details on the syntax of these strings, seeMatch the pattern.
include_globs array of strings Optional. Then apply matches to include only those urls that also match the glob. Designed to simulate the Greasemonkey keyword.@include
exclude_globs array of strings Optional. Matches is later applied to exclude urls that match the global. Designed to simulate the Greasemonkey keyword.@exclude
{
  "name": "My extension"."content_scripts": [{"matches": ["http://*.nytimes.com/*"]."exclude_matches": ["*://*/*business*"]."js": ["contentScript.js"]}],... }Copy the code

You can also specify the run time, communicate with the embedded page, specify the framework, more configuration please read the official link developer.chrome.com/extensions/…

Declare Permissions and Warn Users

The extension’s ability to access websites and most Chrome apis depends on its declared permissions. Permissions should be limited to those required for its function. Limiting permissions establishes the functionality of an extension and reduces the data intrusion that can result if an attacker breaches the extension. Protect extensions and their users by implementing explicit, minimum, and optional permissions.

Finishing permissions

Permissions are known strings that reference Chrome APIS or match patterns to grant access to one or more hosts. They are listed in the listing and specified as required or optional permissions.

 {
    "name": "Permissions Extension". // Mandatory permissions"permissions": [
      "activeTab"."contextMenus"."storage"], // Optional permission"optional_permissions": [
      "topSites"."http://www.developer.chrome.com/*"],..."manifest_version"2} :Copy the code

Determine the required permissions -The official address

A simple extension may require multiple permissions to be requested, and many permissions display warnings at installation time. Users are more likely to trust a limited warning or extension when the limits are explained to them.

Use events to trigger optional permissions

The core function of the optional permission sample extension is to overpower the new TAB page. One is to display the user’s goals for the day. This feature only requires a storage license and contains no warnings.

This extension has additional capabilities. Displays the user’s popular websites. This feature requires topSites permission and comes with a warning.

Give Users Options – The official documentation

There are two entrances, one is the right icon has a “options” menu, and another in the plug-in management page:

Simple configuration

  • A full page options
{
 "name": "My extension"."options_page": "options.html". }Copy the code
  • Embedded options
{
  "name": "My extension"."options_ui": {
    "page": "options.html"."open_in_tab": false},... }Copy the code

Comparison of 5 JS types -Refer to the link

The JS of Chrome extensions can be classified into five categories: injected Script, Content-Script, Popup JS, Background JS and DevTools JS

Permission to contrast

JS type Accessible APIS DOM access JS access Direct cross domain
injected script No different from normal JS, no access to any extension API You can visit You can visit Can not be
content script You can only access some apis like Extension and Runtime You can visit Can not be Can not be
popup js Access to most apis except the DevTools family Not directly accessible Can not be can
background js Access to most apis except the DevTools family Not directly accessible Can not be can
devtools js Only some apis such as DevTools, Extension, and Runtime can be accessed can can Can not be

Message communication -The official documentation

The demo address

Because Content scripts run in the context of a Web page rather than an extender, they often need some way to communicate with the rest of the extender.

Communication between extensions and their content scripts is done using messaging. Either side can listen for messages sent from the other end and respond on the same channel. Messages can contain any valid JSON object (empty, Boolean, number, string, array, or object)

  • There is a simple API to handle one-time requests
  • A more sophisticated API allows you to have long-term connections to exchange multiple messages with a shared context.
  • If you know another extension name, you can also pass messages across extensions. This article will not cover this. If you are interested, go to the official website

Simple one-time pass

If you only need to send a message to another part of the extension (and optionally return a response), use the simplified Runtime. sendMessage or tabs. SendMessage. This allows you to send a JSON-serializable message to the extension once from the content script and vice versa. Optional callback parameters allow you to process the response, if any, from the other side.

chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
  console.log(response.farewell);
});
Copy the code

Sending a request to a content script from an extension looks very similar, except that you need to specify which TAB to send the request to. This example demonstrates a content script that sends a message to a selected TAB.

chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
  chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
    console.log(response.farewell);
  });
});
Copy the code

On the receiving side, you need to set up the Runtime. onMessage event listener to process the message. This looks the same from a content script or extension page.

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
    if (request.greeting == "hello")
      sendResponse({farewell: "goodbye"});
  });
Copy the code

Open the Background default background page to see the message

There will also be responses in content-script.js

A long connection

Sometimes conversations last longer than a single request and response, which is useful. In this case, you can use Runtime.connect or tabs. Connect, respectively, to open long-life channels from content scripts to extended pages, and vice versa. Channels can have a name so that you can distinguish between different types of connections.

When a connection is established, both ends are provided with a Runtime. Port object that is used to send and receive messages over the connection.

The way to send and receive channels from content-script is as follows: Sending a request from an extension to a content script looks very similar, except that you need to specify which TAB to connect to. Simply replace the connect connection in the above example with tabs.connect.

The way to connect a page to content-script is as follows

var port = chrome.runtime.connect({name: "knockknock"});
port.postMessage({joke: "Knock knock"});
port.onMessage.addListener(function(msg) {
  if (msg.question == "Who's there?")
    port.postMessage({answer: "Madame"});
  else if (msg.question == "Madame who?")
    port.postMessage({answer: "Madame... Bovary"});
});
Copy the code

To process incoming connections, you need to set up the Runtime. onConnect event listener. This looks the same from a content script or extension page. This event is triggered when another part of the extension calls “connect()”, along with the Runtime.port object that can be used to send and receive messages over the connection. This is what the response incoming connection looks like: Content-script.js

/ / listen long connection chrome. Runtime. OnConnect. AddListener (function(port) {
  console.assert(port.name == "knockknock");
  port.onMessage.addListener(function(msg) {
    if (msg.joke == "Knock knock")
      port.postMessage({question: "Who's there?"});
    else if (msg.answer == "Madame")
      port.postMessage({question: "Madame who?"});
    else if (msg.answer == "Madame... Bovary")
      port.postMessage({question: "I don't get it."});
  });
});
Copy the code

The effect is shown below:

Port life

The port is designed as a method of two-way communication between different parts of the extension, where the (top-level) frame is treated as the smallest part.

A Port is created when tabs. Connect, Runtime. connect, or Runtime. connectNative is called. This port is immediately available to send messages to the other end via postMessage.

If you have more than one frame in the TAB, calling Tabs. Connect results in multiple calls to the Runtime.onConnect event (one for each frame in the TAB). Similarly, if runtime.connect is used, the onConnect event may fire multiple times (once per frame during the extension).

You might want to find out when the connection is closed, for example, if you maintain a separate state for each open port. To do this, you can listen to the runtime. Port. OnDisconnect events. This event is emitted when there is no valid port on the other side of the channel. This happens when:

  • There is no listener for Runtime.onConnect on the other end.
  • The TAB containing the port is unloaded (for example, if it is navigated).
  • connectThe framework for the calling location is unloaded.
  • All frames for the receive port (via Runtime.onConnect) have been unloaded.
  • The other end callsruntime.Port.disconnect. Notice if aconnectThe call results in multiple ports at the receiver’s end, anddisconnect()Is called on any of these ports, then theonDisconnectEvents are emitted only on the sender’s port and not on any other port.

Common method identification

Dynamically inject CSS code

// Execute CSS code dynamically, TODO, chrome.tabs. InsertCSS (tabId, {code:'xxx'}); InsertCSS (tabId, {file:'some-style.css'});
Copy the code

[Note] Because content_scripts has a very high priority for CSS, almost second only to the browser default, it may affect the presentation of some sites if you are not careful, so try not to write styles that affect the whole world. So make sure you test it when you inject it.

Dynamic execution

The official documentation

/ / dynamic execution of JS code chrome. Tabs. ExecuteScript (tabId, {code:'document.body.style.filter = "grayscale(1)"'}); / / dynamic execution of JS file chrome. Tabs. ExecuteScript (tabId, {file:'script.js'});
Copy the code

【 note 】 background and page_action page cannot directly access the dom, but can be by chrome. Tabs. ExecuteScript ({code: script,}) to perform the js

Gets the current window ID -The document

chrome.windows.getCurrent(function(currentWindow)
{
	console.log('Window ID:' + currentWindow.id);
});
Copy the code

Debug extensions

For debugging, see the debug extension website for more details, as well as links to videos

Packaging and publishing

We can click on the package extension and generate the.rtx file, which you need to log into your Google account to publish to the Google App Store.

Add dark mode to jingdong page

Directory as follows

Add - dark - to - page ├ ├ ─ README. Md ├ ─ the manifest. Json ├ ─ js | ├ ─ background. Js | └ home. Js ├ ─ images | └ icon. The PNG ├ ─ HTML | | ├ ─ home. HTML └ options. HTML ├ ─ CSS | └ index. The CSSCopy the code

First createmainfest.json

{
  "name": "TimeStone1"."manifest_version": 2."version": "1.0"."description": "TimeStone Extension"."page_action": {
    "default_icon": "images/icon.png"."default_title": "TimeStone plug-in"."default_popup": "html/home.html"
  },
  "background": {
    "scripts": ["js/background.js"]},"options_page": "html/options.html"."homepage_url": "https://juejin.cn/user/4230576473387773"."permissions": ["tabs"."activeTab"."declarativeContent"]}Copy the code

Dark mode thinking

The dark mode I use here is to control the display of the page through the FILTER property of CSS. You can check it out

Open the chrome: / / extensions /

Then load the decompressed extension program as follows

Create /background.js under home.html and js files

  • home.html
<! DOCTYPE HTML > < HTML > <head> <title>TimeStone plugin home page </title> <meta charset="utf-8" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <link type="text/css" rel="stylesheet" href=".. /css/index.css" />
  </head>
  <body>
    <div class="time-stone">
      <button class="time-stone_btn" id="ChangeBg"<script SRC = "button" style = "max-width: 100%; clear: both; min-height: 1em".. /js/home.js" type="text/javascript"></script>
    </div>
  </body>
</html>

Copy the code
  • home.js
/** * get the URL */function getCurrentTabUrl(callback) {
  let queryInfo = {
    active: true,
    currentWindow: true,
  }

  chrome.tabs.query(queryInfo, (tabs) => {
    let tab = tabs[0]
    let url = tab.url
    console.assert(typeof url === 'string'.'tab.url should be a string'Callback (url)})} /** * Changes the background color of the current page. * * /function changeBackgroundStyle() {
  const script = 'document.body.style.filter = "grayscale(1)"; '
  // See https://developer.chrome.com/extensions/tabs#method-executeScript./ / to the page into the JavaScript code. Chrome tabs. ExecuteScript ({code: script,})} / / the plugin will be loaded users choose the color of the last time, if they exist. document.addEventListener('DOMContentLoaded', () = > {getCurrentTabUrl ((url) = > {/ / change the background color ChangeBg. AddEventListener ('click'.function () {
      changeBackgroundStyle()
    })
  })
})

Copy the code
  • background.js
chrome.runtime.onInstalled.addListener(function () {
  // Replace all rules ...
  chrome.declarativeContent.onPageChanged.removeRules(undefined, function () {
    // With a new rule ...
    chrome.declarativeContent.onPageChanged.addRules([
      {
        // That fires when a page's URL contains a 'g'... conditions: [ new chrome.declarativeContent.PageStateMatcher({ pageUrl: { urlContains: 'jd.com' }, }), ], // And shows the extension's page action.
        actions: [new chrome.declarativeContent.ShowPageAction()],
      },
    ])
  })
})

Copy the code

The source address

  • Long-link Demo address
  • Dark mode source code
  • Official program source code

If you have any problem with the above code debugging, please leave a message or issue, thank you!

The following will update some right-click menu, web interception request, right-click menu instances and other demo, thank you for your attention.