忽然发现插件是绕不过去的, 那么从chrome开始吧. chrome extension

最终还是从stackoverflow入门:
  • https://stackoverflow.com/questions/32467151/how-to-disable-javascript-in-chrome-developer-tools-programmatically
  • 这其中Joshua Dannemann 的答案:
You can write a simple Chrome extension to do what you want. Chrome provides a JavaScript API were you can allow or block JavaScript using contentSettings and the property you will need to set or unset is JavascriptContentSetting.
https://developer.chrome.com/extensions/contentSettings
https://developer.chrome.com/extensions/contentSettings#type-JavascriptContentSetting
To add the keyboard shortcut, you add it to the manifest as described here:
https://developer.chrome.com/extensions/commands
Just in case you have not built an extension before (don't worry, it is pretty easy), here is a walk-though on putting together your first:
https://developer.chrome.com/extensions/getstarted
Hope this helps.
入门的顺序
  • https://developer.chrome.com/extensions/getstarted
    • 这个例子是针对tab写的权限, 所以很多时候这个插件并不能够激活, 是灰色的无法应用状态.
    • 这个例子最终结果很挫, 要用option改变按钮颜色, 按钮只有一个. 并不是正常的ui思路, 只是为了展示插件的技术.
  • https://crxdoc-zh.appspot.com/extensions/getstarted
    • 中文的这个入门更搓, 代码和文字明显不匹配了.
    • 不过他的改变背景色是有选择的, 可以参考.
    • icon是一个19x19的png. 这个貌似也不对, 在英文的例子里面icon有四种16, 32, 48, 128

####关键文档

  • https://developer.chrome.com/extensions/overview
  • 这个文档很关键, 可以对于chrome插件形成全局观
文件部分:
  • 插件的id在开发过程中就是路径, 避免硬编码可以用: chrome.runtime.getURL()
  • manifest.json这个是配置文件, 这个名字是固定的. 插件甚至于只有这个文件
  • background脚本, 控制事件的脚本. 这个并不是必须的, 甚至于干正事也不需要他.
  • ui组件, 包括html和对应的js, 这个大部分时候是要的, 总是要给用户点反馈.
    • aciton有两种
      • browser
      • page
    • context menus
    • omnibox 是地址栏快捷键
    • keyboard shortcut
  • popup页面和js 也属于ui组件的一部分, 但是, 这个非常重要
  • content 脚本 和dom交互的脚本, 也不是必须的. google的项目总喜欢把事情分层复杂化. 用一个复杂的结构解决复杂的问题. 分治的非常勉强.
  • options 页面, 插件的设置选项的页面, 其实也没啥用. 一个插件还需要设置.
api部分

所有的api都是chrome.xxxx形式.

同步和异步
//api是异步的
//一般情况, 异步函数是这样调用的, Signature for an asynchronous method
chrome.tabs.query(object queryInfo, function callback)
//实际代码
chrome.tabs.query({'active': true}, function(tabs) {
  chrome.tabs.update(tabs[0].id, {url: newUrl});  //这个后执行, 并且它虽然是异步函数, 但是并没有回调函数.
});
someOtherFunction(); //这个先执行

//也有同步代码: // Synchronous methods have no callback option and returns a type of string
string chrome.runtime.getURL()

页面间通讯
  • chrome.extension

  • getViews()

  • getBcakgronundPage()

  • 也可以用storage接口的message passing

  • Incognito mode 这个模式的意思是window不可以被tracks, 也就是说插件保留自己的配置是可以的, 但是, 想要保留页面历史, 则必须不包含incognito mode的页面.

    • 用tabs.Tab或者windows.Window的incognito属性来测试是否incognito mode.

    • function saveTabData(tab) {
        if (tab.incognito) {
          return;
        } else {
          chrome.storage.local.set({data: tab.url});
        }
      }
      

看了这个overview之后, 回头再看getstarted, 清晰了很多.

总结:

  1. browser_action的设计比较简单
  2. page_action 需要一个chrome.declarativeContent的声明
  3. 那么问题来了, brower和page的目标是什么呢?
    1. https://developer.chrome.com/extensions/pageAction
    2. https://developer.chrome.com/extensions/browserAction
  4. 官方的说明
    1. page受限于页面
    2. browser总是有效
  5. 那么我的几个需求都是browser比较合理

这个官方文档其实是一个连连看

  • overview竟然还有子条目, 这些子条目竟然只存在于左边的目录树.
  • 并没有下一步.
  • 因此, 需要顺序阅读左边的子条目才可以.

调试

  • 调试文档并没有太多有价值内容. 和一般的js调试是基本一致的.
  • 特别重要的一点, 用插件的id是可以调试代码的.
  • 比如我的popup.html: chrome-extension://plfilniddlhhfmhhcmganobhdjpjcmef/popup.html
  • 鼠标右键在弹出窗口上面也可以直接呼出调试界面.
  • 参考这个文档的调试部分, 非常有用: https://www.cnblogs.com/liuxianan/p/chrome-plugin-develop.html
生命周期的一个疑问

用popup呼叫background的函数, 这个函数执行的进程生命周期是在background还是popup, 不太好查, 直接测试一下.

// popup.js
var bg = chrome.extension.getBackgroundPage();
bg.test(); // 访问bg的函数
alert(bg.document.body.innerHTML); // 访问bg的DOM

所以说, 要整体学习下chrome extension的生命周期, 这两份文档有用. 官方文档难于检索.

  • https://itnext.io/all-youll-ever-need-to-know-about-chrome-extensions-ceede9c28836
  • https://www.cnblogs.com/liuxianan/p/chrome-plugin-develop.html

声明周期描述

  • popup的周期就是那个弹出的网页, 关闭就木了.
  • content注入的是当前的网页, 并不是tab, 也就是说如果tab发生跳转, 那么久木了.
  • background运行在浏览器声明周期, 只要插件没有卸载, 浏览器没有关闭, 这个就在.

主要的三个沟通的核心相关api

  • Tabs
  • Messaging
  • Storage

有四种情况background会忙起来:

  • The extension is first installed or updated to a new version.
  • The background page was listening for an event, and the event is dispatched.
  • A content script or other extension sends a message.
  • Another view in the extension, such as a popup, calls `runtime.getBackgroundPage’

back的注意:

  • background可以注册多个, 因此可以模块化管理.

  • 如果用了chrome.webRequest, 那么就不能用合格eventpage模式了, 应该用background的持久化模式.

  • 因为tab不支持event filter, 所以如果要用event filter, 那么用 webNavigation.onCompleted 代替 tabs.onUpdated例如:

      chrome.webNavigation.onCompleted.addListener(function() {
          alert("This is my favorite website!");
      }, {url: [{urlMatches : 'https://www.google.com/'}]});
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     //这个意思就是只针对google.com才出上面的alert.
    
content script
  • 注入的match parttern可以写多个, 那是一个数组.

    "*://*/*"  //这个意思是http或者https的任意链接
    
  • css也是可以注入的: https://developer.chrome.com/extensions/tabs#method-insertCSS

    chrome.tabs.insertCSS(tabs[0].id,{
      code: '* {background-color: '+color+';}'
    });
    
  • js注入

    chrome.tabs.executeScript({
      code: 'document.body.style.backgroundColor="orange"'
    });
    
  • json配置注入

    "content_scripts": [
    		{
    			"matches": [
    				"*://*/*"
    			],
    			"all_frames": true,
    			"js": [
    				"lib/lib.js",
    				"inject/baser.js",
    				"inject/downbutton.js"
    			]
    		}
    	],
    

特别关注的api

download: 批量没找到, 但是设置地址是可以的.

chrome.downloads.download({url:p,filename:'big/'+name})// 这样就设置到了download的big目录下
有用的附录:
  • 入门文档好中文:https://www.cnblogs.com/liuxianan/p/chrome-plugin-develop.html
  • 入门文档好英文:https://itnext.io/all-youll-ever-need-to-know-about-chrome-extensions-ceede9c28836
  • 官方参考好事件: https://developer.chrome.com/extensions/background_pages
  • 官方参考好消息: https://crxdoc-zh.appspot.com/apps/messaging#external-webpage
  • 官方overview也是好文档: https://developer.chrome.com/extensions/overview
无用的附录: 曲折的上手弯路, 大家不要这么干了
  • 打开extension的开发模式, 在右边三点菜单找到more tools->extensions
  • 根目录必须有manifest.json
  • 打包之后是crx
  • 具体的介绍参考这个: https://www.cnblogs.com/liuxianan/p/chrome-plugin-develop.html
  • 从知乎找到根源
    1. 本来360对于这个部分有翻译.
    2. 但是google有官方的翻译了, 所以360也就不更新了.
    3. 入门: https://crxdoc-zh.appspot.com/extensions/getstarted
    4. 概述: https://crxdoc-zh.appspot.com/extensions/overview
    5. 开发指南: https://crxdoc-zh.appspot.com/extensions/devguide
    6. google的官方文档很全面, 并且除了扩展之外, chrome程序的文档也在一起.