插件文件安装地址

/Users/xxx/Library/Application Support/Google/Chrome/Default/Extensions

Refused to evaluate a string as JavaScript because ‘unsafe-eval’ is not an allowed source of script in the following Content Security Policy directive: “script-src ‘self’ blob: filesystem:”

“content_security_policy”: “script-src ‘self’ ‘unsafe-eval’; object-src ‘self’;”,

目录:

  • Tabs 相关
  • storage 数据储存获取与 onMessage 通信相关
  • 语言本地化
  • 消息传递 & 跨扩展程序消息传递
  • 读取页面内全局变量 & content_scripts & web_accessible_resources
  • 遗留问题
  • 其他重要备忘

Tabs 相关

  1. chrome.tabs.getSelected(null, tab => {
  2. // ...
  3. });
  4. chrome.tabs.getCurrent(tab => {
  5. // ...
  6. });

可以通过上面这两种方式获取当前 Tab 标签页,得到其 id、url 等属性,之后可以进行多种操作,例如往该标签页执行特定 js 文件,如下:

  1. chrome.tabs.executeScript(tab.id, {
  2. file: 'logic.js'
  3. });
  1. document.addEventListener('visibilitychange', () => {
  2. if (document.visibilityState === 'visible') {
  3. // 当 Tab 可见 do something
  4. } else {
  5. // 当 Tab 不可见 do something
  6. }

storage 数据储存获取与 onMessage 通信相关

Unchecked runtime.lastError while running storage.set: QUOTA_BYTES_PER_ITEM quota exceeded

This error comes when you use chrome.storage.sync.set…

to set the data greater than 8,192 bytes for a single item as chrome.storage.sync.set allows 8,192 QUOTA_BYTES_PER_ITEM.

按说应该只在 background 的初始化中创建特定对象,并通过 storage 存储

  1. // 创建与存储
  2. let testObj = {
  3. 0: false,
  4. 1: false,
  5. 2: false,
  6. 3: false,
  7. 4: false,
  8. 5: false
  9. };
  10. chrome.storage.local.set({ testObj: testObj });

之后在其他页面中只需要通过 storage 获取需要的数据对象,可以是直接修改后重新存入,也可以通过 sendMessage 向 background 传递 payload,统一在 background 进行数据的处理存储

  1. // 在 background 中注册 onMessage 事件
  2. chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  3. if (request.to === 'background') {
  4. switch(request.msg) {
  5. case 'toggleItem':
  6. chrome.storage.local.get(['testObj'], r => {
  7. testObj = r.testObj;
  8. testObj[request.payload.id] = request.payload.flag;
  9. chrome.storage.local.set({
  10. testObj: testObj
  11. });
  12. });
  13. break;
  14. // ...
  15. }
  16. }
  17. });
  18. // 这里补充事件发送
  19. sth.addEventListener('click', (e) => {
  20. // ...
  21. chrome.runtime.sendMessage({
  22. to: 'background',
  23. msg: 'toggleItem',
  24. payload: {
  25. id: tmpId,
  26. flag: tmpFlag
  27. }
  28. });
  29. });

此外,其他特定页面为了保持数据一致,可设置事件 onChanged 监听 storage,一旦特定对象有修改,可进行相应的同步操作

  1. chrome.storage.onChanged.addListener(function(changes, namespace) {
  2. for (var key in changes) {
  3. var storageChange = changes[key];
  4. console.log('Storage key "%s" in namespace "%s" changed. ' +
  5. 'Old value was "%s", new value is "%s".',
  6. key,
  7. namespace,
  8. storageChange.oldValue,
  9. storageChange.newValue);
  10. console.log('storageChange.oldValue: ', storageChange.oldValue);
  11. console.log('storageChange.newValue: ', storageChange.newValue);
  12. if (key === 'testObj') {
  13. renderBox(storageChange.newValue);
  14. }
  15. }
  16. });

语言本地化

其中一种方式,可以自建对象集合,以 window.navigator.language 为依据来选用具体对象

  1. var msg = {
  2. en: {
  3. noPinDomain: "Sorry, pinning is not allowed from this domain. Please contact the site operator if you have any questions.",
  4. noPinMeta: "Sorry, pinning is not allowed from this page. Please contact the site operator if you have any questions.",
  5. noPinnablesFound: "Sorry, couldn't find any pinnable things on this page."
  6. },
  7. zh: {
  8. noPinDomain: "抱歉,不允许从此域收藏 Pin 图。如有疑虑请联系网站运营商。",
  9. noPinMeta: "抱歉,不允许从此域收藏 Pin 图。如有疑虑请联系网站运营商。",
  10. noPinnablesFound: "抱歉,未在此页面中找到可收藏的 Pin 图。"
  11. },
  12. // ...
  13. };
  14. var local = stringsHandleFunc(window.navigator.language);
  15. var theObjWeNeed = msg[local];
  16. // ...

消息传递 & 跨扩展程序消息传递

page 中 content、logic 只能向 bg 发送消息

关键词 onMessageExternal、onConnectExternal,以及 manifest 中的 “externally_connectable”

读取页面内全局变量 & content_scripts & web_accessible_resources

回忆以下内容


编译文件 直接在项目 html 模板注入 & 通过插件 content_scripts 形式注入

前者可以读到 window 下 xxx 对象,后者不行

“dist/dll/reactForPinit.dll.js”,
“dist/js/pinit.min.js”


通过 content_scripts 注入的内容应该是执行在一个独立、特殊的(虚拟?)环境

和网页本身的 window 不共享

所以当需要’读取页面内全局变量’时,建议通过如下方式注入 css、script

  1. function loadCSS(url) {
  2. var head = document.getElementsByTagName('head')[0];
  3. var link = document.createElement('link');
  4. link.type = 'text/css';
  5. link.rel = 'stylesheet';
  6. url = chrome.extension.getURL(url);
  7. console.log('loadCSS: ', url);
  8. link.href = url;
  9. head.appendChild(link);
  10. }
  11. function loadScript(url) {
  12. var tail = document.body;
  13. var script = document.createElement('script');
  14. script.type = 'text/javascript';
  15. url = chrome.extension.getURL(url);
  16. console.log('loadScript: ', url);
  17. script.src = url;
  18. tail.appendChild(script);
  19. }
  20. loadCSS(cssArr[0]);
  21. loadScript(jsArr[0]);

此外,从以上内容出发,可以扩展到’本地 js 调试线上页面’,如利用 sources 下 overrides、文件代理替换等方式

利用chrome的overrides实时调试线上js

遗留问题


    1. 按说一般网页不可调用 chrome 的一些 api,但是在已授权权限情况下,content.js 可以调用 chrome.storage.local.get,而又不可调用 chrome.tabs,之后不妨了解下还有哪些可调用的

关于通信后 debug 调试

比方从 background 向 logic.js sendMessage 之后,因为代码是在闭包内,如果有错误代码中断了,控制台看不到,很要命,目前完全不知道怎么办

其他重要备忘

关于 web_accessible_resources,浏览器对插件内资源授权访问

比如要在页面内添加 iframe,src 为插件内 /html/create.html、/html/grid.html,则需要在 manifest.json 中添加如下:

  1. "web_accessible_resources": [ "/html/create.html", "/html/grid.html" ]

How to inject CSS using content script file in Chrome extension?

通信过程中值传递需要注意

比方在 logic.js 将 document.images 通过 background 中转到 grid 所在 iframe,纠结纳闷了好一会,为什么得到的数据是个空对象 {} 的数组?

其实是环境变了,原本值本是个指向当前文档特定 DOM 的指针。