从0到1开发一个chrome插件实现用户登录

1,490 阅读7分钟

前言

  1. 微前端项目中, 登录模块是集成在主服务中,那么每个子模块都要创建一个独立的登录,就很烦。
  2. 遇到比较新的关键词想要百度, 那么chrome插件,也有相关api,都可以集成在你的插件中。
  3. 无聊想划水了,那么偷偷的写个扫雷,五子棋,也可以偷偷摸摸的玩。
  4. 想获取书签的信息,集成到自己的页面中。重新布局也可以实现。
  5. 自从看了这篇文章,那你就与浏览器打开了沟通的桥梁。 .....

扬帆起航

1.介绍

每一个扩展、可安装的WebApp、都有一个JSON格式的manifest文件,叫manifest.json,里面提供了重要的信息,这个文件也就是chrome插件.

创建一个文件夹 -> 新建一个manifest.json文件

1.1- manifest.json 详解


{
    // 清单文件的版本,这个必须写,而且必须是2, 不过马上更新到3了。
    "manifest_version": 2,
    // 插件的名称
    "name": "小明同学c_chrome插件",
    // 插件的版本
    "version": "1.0.0",
    // 插件描述
    "description": "小明同学的chrome插件教学时间",
    // 图标,一般偷懒全部用一个尺寸的也没问题
    "icons":
    {
        "16": "img/icon.png",
        "48": "img/icon.png",
        "128": "img/icon.png"
    },
    // 会一直常驻的后台JS或后台页面
    "background":
    {
        // 2种指定方式,如果指定JS,那么会自动生成一个背景页
        //"page": "background.html"
        "scripts": ["js/background.js"]
    },
    // 浏览器右上角图标设置,browser_action、page_action、app必须三选一
    "browser_action": 
    {
        "default_icon": "img/icon.png",
        // 图标悬停时的标题,可选
        "default_title": "小明同学c的chrome插件",
        "default_popup": "index.html"
    },
    // 当某些特定页面打开才显示的图标
    /*"page_action":
    {
        "default_icon": "img/icon.png",
        "default_title": "小明同学c的chrome插件",
        "default_popup": "index.html"
    },*/
    // 需要直接注入页面的JS
    "content_scripts": 
    [
        {
            //"matches": ["http://*/*", "https://*/*"],
            // "<all_urls>" 表示匹配所有地址
            "matches": ["<all_urls>"],
            // 多个JS按顺序注入
            "js": ["js/axios.js", "js/content.js"],
            // JS的注入可以随便一点,但是CSS的注意就要千万小心了,因为一不小心就可能影响全局样式
            "css": ["css/index.css"],
            // 代码注入的时间,可选值: "document_start", "document_end", or "document_idle",最后一个表示页面空闲时,默认document_idle
            "run_at": "document_start"
        },
        // 这里仅仅是为了演示content-script可以配置多个规则
        {
            "matches": ["*://*/*.png", "*://*/*.jpg", "*://*/*.gif", "*://*/*.bmp"],
            "js": ["js/content-script.js"]
        }
    ],
    // 权限申请
    "permissions":
    [
        "contextMenus", // 右键菜单
        "tabs", // 标签
        "notifications", // 通知
        "webRequest", // web请求
        "webRequestBlocking",
        "storage", // 插件本地存储
        "http://*/*", // 可以通过executeScript或者insertCSS访问的网站
        "https://*/*" // 可以通过executeScript或者insertCSS访问的网站
    ],
    // 普通页面能够直接访问的插件资源列表,如果不设置是无法直接访问的
    "web_accessible_resources": ["js/injectdom.js"],
    // 插件主页,这个很重要,不要浪费了这个免费广告位
    "homepage_url": "https://www.baidu.com",
    // 覆盖浏览器默认页面
    "chrome_url_overrides":
    {
        // 覆盖浏览器默认的新标签页
        "newtab": "newtab.html"
    }
}

1.2- 使用

打开chrome浏览器,右上角 ... 竖的标志 -> 更多工具 -> 拓展程序

右上角打开 开发者模式 -> 点击左上角 加载已解压的拓展程序 -> 找到我们刚刚创建的文件夹, 点击确定or选择。即可

image.png

image.png

1.3 基础描述与图标配置

现在我们已经做好了一个chrome插件了,但是呢,没有功能,还比较丑,现在我们来优化它。都是基础配置, 我就先配置了哈。后面讲通讯再讲重点


"name": "小明同学c_chrome插件",
"version": "1.0.0",
"manifest_version": 2,
"icons": { // 图标配置
    "16": "images/icon16.png", // 适用于浏览器tabbar上面的图标配置
    "48": "images/icon48.png", // 拓展程序中的 图标配置
    "128": "images/icon128.png" // 
},
"browser_action": {
    "default_icon": "img/icon.png", // 图标
    "default_title": "小明的Chrome插件", // 标题
    "default_popup": "index.html" // popup页面
}

这里browser_actiondefault_popup : 指向的是一个html页面。即点击插件时,所展开的页面

image.png

如何点击登陆调用接口,往浏览器的cookies或者localstorage存放数据呢? 往下看

2.backaground和content_script 怎么实现用户界面的登陆和存储

  1. background

    这里理解为->后台,也可以理解为是你插件的服务端,随时提供为你提供服务的。它随着你的浏览器打开而打开,关闭而关闭。在chrome插件中, 不同的配置项拥有不同的权限,即获取浏览器相关api的权限。, background的权限几乎是最高的,几乎所有的浏览器操作,都是在这个里面完成的。比如存cookies,获取当前tab标签页,获取书签信息....

    { 
        // 会一直常驻的后台JS或后台页面 
        "background": { 
        // 2种指定方式,如果指定JS,那么会自动生成一个背景页 
        //"page": "background.html" 
        "scripts": ["js/background.js"] }
    }
    
  2. content_script

    这个是chrome插件向页面注入脚本(js/css)的一种形式, 可以通过该配置,向选中的标签页动态注入css和js,

    {
     // 需要直接注入页面的JS
      "content_scripts": 
      {
          //"matches": ["http://*/*", "https://*/*"],
          // "<all_urls>" 表示匹配所有地址
          "matches": ["<all_urls>"],
          // 多个JS按顺序注入
          "js": ["js/axios.js", "js/content.js"],
          // JS的注入可以随便一点,但是CSS的注意就要千万小心了,因为一不小心就可能影响全局样式
          "css": ["css/index.css"],
          // 代码注入的时间,可选值: "document_start", "document_end", or "document_idle",最后一个表示页面空闲时,默认document_idle
          "run_at": "document_start"
      },
    }
    
  3. 实现登陆的思路

    我们在popup点击按钮触发事件,已知: backaground 是调用chrome浏览器的相关API的, content_script是注入到页面的js。

    实现: popup中的Click触发,通知 background 找到当前选中的tab标签页, 通过content_script注入js执行登陆请求,并存储token, 完事告诉background 我执行完了 。

    通讯:?

  4. popupbackgroundcontent_script 怎么通讯?

    popup -> background 是可以直接调用 background 中的方法的。

       // background.js
       function sendContentScript (form) {
          console.log(form) // 
       }
    
       // popup.js 即 index.html 中 scirpt 标签引入的js 文件
       
       let bg = chrome.extension.getBackgroundPage();
       bg.sendContentScript({ type: 'login', userInfo: { user: '', pass: '' } })
       
    

    background -> content_script 通过 chrome.tabs.sendMessage(tabs[0].id, message, function(){})

       // background.js
       function sendContentScript (form) {
           // active 选中的标签,currentwindow 当前浏览器中的,总结获取tab标签的
           chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
               //参数1. 获取当前选中的tab标签,参数2,传递的消息体,即参数。 
               chrome.tabs.sendMessage(tabs[0].id, form, function(response) {
                  console.log(response); // 参数3: 接收消息后的回调函数
                });
           })
       }
    
        // content_script
        // 时刻监听传递来的讯息
        chrome.extension.onMessage.addListener(
          // 参数1. 请求时的消息体,参数
          // 参数2:当前选择的浏览器的信息
          function(request, sender, sendResponse) {
            // 即backgroundjs中的参数3
            sendResponse("content_scripts回复处理结果");
            if (request.type === 'login') {
              goLogin(request.userInfo) //
            }
          }
        )
            
    

    请求完成后,想告诉backgroundjs 来个桌面通知的消息,即 content -> background

        // content_script
        function success() {
          chrome.runtime.sendMessage({ type: 'success' });
        }
    
        // background.js
        chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
          if (request.type === 'success') {
            chrome.notifications.create(null, {
              type: 'basic',
              iconUrl: 'img/icon.png',
              title: 'Julius-通知',
              message: '登录成功,开启开发者模式~'
            });
          }
         })
    
  5. 刚刚通信已经基本讲到了,哪应该有即时通信吧。真有

这里再单独说明一下。Chrome插件中有2种通信方式,一个是短连接(chrome.tabs.sendMessagechrome.runtime.sendMessage),一个是长连接(chrome.tabs.connectchrome.runtime.connect

短连接的话就是挤牙膏一样,我发送一下,你收到了再回复一下,如果对方不回复,你只能重新发,而长连接类似WebSocket会一直建立连接,双方可以随时互发消息。

示例:

    // popup - 
    function connect () {
     chrome.tabs.query({active: true, currentWindow: true},function(tabs) {
       let tabId = tabs[0].id
       var port = chrome.tabs.connect(tabId, {name: 'connect'});
       console.log(port);
       port.postMessage({message: '你是谁?'});
       port.onMessage.addListener(function(msg) {
         if(msg.content && msg.content.startsWith('我是')) {
           port.postMessage({message: '哦,原来是你!'});
         }
       });
     })
    }
    // content_script 
    
    chrome.runtime.onConnect.addListener(function(port) { 
       console.log(port);
       if(port.name == 'connect') { 
        port.onMessage.addListener(function(msg) { 
            if(msg.message == '你是谁?') port.postMessage({content: '我是你爸!'});
        });
       }
    });

总结

  1. 通信概述

标题content-scriptpopup-jsbackground
content-script-chrome.runtime.sendMessage chrome.runtime.connectchrome.runtime.sendMessage chrome.runtime.connect
popup-jschrome.tabs.sendMessage chrome.tabs.connect-chrome.extension. getBackgroundPage()
backgroundchrome.tabs.sendMessage chrome.tabs.connectchrome.extension.getViews-
  1. 权限概述
| JS种类可访问的APIDOM访问情况JS访问情况直接跨域
content script只能访问 extension、runtime等部分API可以访问不可以不可以
popup js可访问绝大部分API不可直接访问不可以可以
background js可访问绝大部分API不可直接访问不可以可以

看完这个回想刚刚 好像可以直接在popup直接与content_script通信了,都不用经过background了, 对吧。嘿嘿...

  1. 调试概述

JS类型 | 调试方式 | 图片说明 | | --------------- | -------------- | ---------------------------------------------------------------------------------------------- | | | content-script | 打开Console,如图切换 | | | popup-js | popup页面右键审查元素 | | | background | 插件管理页点击背景页即可 |

  1. 设置右键搜索小工具
// 设置百度搜索
chrome.contextMenus.create({
    title: '小明同学Go:%s', // %s表示当前选中的文字
    contexts: ['selection'], // 只有当选中文字时才会出现此右键菜单
    onclick: function(params) {
        // 注意不能使用location.href,因为location是属于background的window对象
        chrome.tabs.create({url: 'https://www.baidu.com/s?ie=utf-8&wd=' + encodeURI(params.selectionText)});
    }
});
  1. 成品

image.png

  1. 更多chrome中文文档点击查看

点关注,不迷路,感谢观看

image.png