通信
而对于插件background
、popup
、content
、Devtool
是可以相互调用的,具体通信可以看下图:
脚本权限
我们已经了解了存在的几种通信路径,通信意味着各种API的相互调用,因此在实践之前,也需要去了解一点关于chrome 插件的脚本权限
脚本的类型决定着脚本存在什么权限:比如Chrome API
、DOM 访问
、跨域访问
、原页面JS访问
,具体如图:
JS种类 | 可访问的API | DOM访问情况 | JS访问情况 | 直接跨域 |
---|---|---|---|---|
injected script | 和普通JS无任何差别,不能访问任何扩展API | 可以访问 | 可以访问 | 不可以 |
content script | 只能访问 extension、runtime等部分API | 可以访问 | 不可以 | 不可以 |
popup js | 可访问绝大部分API,除了devtools系列 | 不可直接访问 | 不可以 | 可以 |
background js | 可访问绝大部分API,除了devtools系列 | 不可直接访问 | 不可以 | 可以 |
devtools js | 只能访问 devtools、extension、runtime等部分API | 可以访问devtools | 可以访问devtools | 不可以 |
通讯方法
Injected script | Content script | Popup script | Background script | |
---|---|---|---|---|
Injected script | ❎ | window.postMessgae | ❎ | ❎ |
Content script | window.postMessgae | ❎ | chrome.runtime.sendMessagechrome.runtime.connectchrome.tabs.sendMessage | chrome.runtime.sendMessagechrome.runtime.connect |
Popup script | ❎ | chrome.tabs.connectchrome.tabs.sendMessage | ❎ | chrome.runtime.sendMessagechrome.runtime.onMessage |
Background script | ❎ | chrome.runtime.sendMessagechrome.runtime.onMessagechrome.tabs.sendMessage | chrome.extension.getViewschrome.runtime.sendMessagechrome.runtime.connect | ❎ |
Devtools script | chrome.devtools.inspectedwindow.eval | ❎ | chrome.runtime.sendMessage | chrome.runtime. sendMessage |
popup给background发送消息
background.ts
const add = (...rest: number[]) => rest.reduce((a, b) => a + b, 0)
chrome.runtime.onMessage.addListener((request, _sender, sendResponse) => {
const {val1, val2} = request;
console.log('background.js收到popup.js信息')
sendResponse({res: add(val1, val2)});
});
popup.tsx
import { Button } from '@arco-design/web-react';
import React, { useState } from 'react';
const App = () => {
const [num, setNumber] = useState<number | undefined>()
const handleSendBackgroundMessage = () => {
chrome.runtime.sendMessage({val1: 1, val2: 2}, (response) => {
console.log('popup.js收到background.js信息')
setNumber(response.res);
});
}
return (
<div>
<Button onClick={handleSendBackgroundMessage}>Background通信</Button>
<div>计算1+2=<span>{num}</span></div>
</div>
);
};
export default App;
background给popup发送消息
由于不激活popup是不会加载popup.js的,所以需要要在popup.js激活状态下进行
background.ts
chrome.tabs.onActivated.addListener(() => {
chrome.runtime.sendMessage({ val1: 1, val2: 2 }, (response) => {
console.log('background.js收到popup.js信息', response);
});
});
popup.tsx
import { Button } from '@arco-design/web-react';
import React, { useLayoutEffect, useState } from 'react';
import { add } from 'lodash';
const App = () => {
useLayoutEffect(() => {
chrome.runtime.onMessage.addListener((request, _sender, sendResponse) => {
const { val1, val2 } = request;
console.log('popup.js收到background.js信息 ---> 接受');
sendResponse({ res: add(val1, val2) });
});
}, []);
return (
<div>
激活我
</div>
);
};
export default App;
content给background发送消息
background.ts
const add = (...rest: number[]) => rest.reduce((a, b) => a + b, 0);
chrome.runtime.onMessage.addListener((request, _sender, sendResponse) => {
const { val1, val2, from } = request;
if (from === 'content') {
console.log('background.js收到content.js信息');
return sendResponse({ res: add(val1, val2) });
}
});
content.tsx
import { Button } from '@arco-design/web-react';
import React, { useState } from 'react';
const App = () => {
const [num, setNumber] = useState<number | undefined>()
const handleSendBackgroundMessage = () => {
chrome.runtime.sendMessage({val1: 1, val2: 2}, (response) => {
console.log('content.js收到background.js信息')
setNumber(response.res);
});
}
return (
<div>
<Button onClick={handleSendBackgroundMessage}>Background通信</Button>
<div>计算1+2=<span>{num}</span></div>
</div>
);
};
export default App;
background给content发送消息
由于content.js可能存在多个tab下,所以要和某个tab下content.js通信,要找到当前tab
background.ts
chrome.tabs.onActivated.addListener(() => {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
chrome.tabs.sendMessage(tabs[0].id!, { from: 'background.js', val1: 1, val2: 2 }, (response) => {
console.log('background -> content script infos have been sended', response);
});
});
});
content.tsx
/* eslint-disable no-undef */
import React, { useLayoutEffect } from 'react';
import { Button } from '@arco-design/web-react';
const App = () => {
useLayoutEffect(() => {
chrome.runtime.onMessage.addListener((request, _sender, sendResponse) => {
const { val1, val2 } = request;
console.log('content.js收到background.js信息 ---> 接受');
sendResponse({ res: add(val1, val2) });
});
}, []);
return (
<div className="flex flex-col">
<Button onClick={handleSendBackgroundMessage}>Background通信</Button>
<div>
计算1+2=<span>{num}</span>
</div>
</div>
);
};
export default App;
popup给content发送消息 & content给popup发送消息
由于content.js可能存在多个tab下,所以要和某个tab下content.js通信,要找到当前tab
content.tsx
/* eslint-disable no-undef */
import React, { useLayoutEffect } from 'react';
import { Button } from '@arco-design/web-react';
import { useState } from 'react';
import { add } from 'lodash';
const App = () => {
const [num1, setNumber1] = useState<number | undefined>();
const handleSendPopupMessage = () => {
chrome.runtime.sendMessage({ val1: 5, val2: 3, from: 'content' }, (response) => {
console.log('content.js收到popup.js信息 ---> 发起');
setNumber1(response.res);
});
};
useLayoutEffect(() => {
chrome.runtime.onMessage.addListener((request, _sender, sendResponse) => {
const { val1, val2, from } = request;
if (from === 'popup') {
console.log('content.js收到popup.js信息 ---> 接受');
return sendResponse({ res: add(val1, val2) });
}
});
}, []);
return (
<div className="flex flex-col">
<Button onClick={handleSendPopupMessage}>Popup通信</Button>
<div>
计算3+5=<span>{num1}</span>
</div>
</div>
);
};
export default App;
popup.tsx
/* eslint-disable no-undef */
import { Button } from '@arco-design/web-react';
import React, { useLayoutEffect, useState } from 'react';
import { add } from 'lodash';
const getCurrentTab = async () => {
let queryOptions = { active: true, currentWindow: true };
let [tab] = await chrome.tabs.query(queryOptions);
return tab;
};
const App = () => {
const [num1, setNumber1] = useState<number | undefined>();
const handleSendContentMessage = async () => {
const tab = await getCurrentTab();
chrome.tabs.sendMessage(tab.id!, { from: 'popup', val1: 5, val2: 2 }, (response) => {
console.log('popup.js收到content.js信息 ---> 发起');
setNumber1(response.res);
});
};
useLayoutEffect(() => {
chrome.runtime.onMessage.addListener((request, _sender, sendResponse) => {
const { val1, val2, from } = request;
if (from === 'content') {
console.log('popup.js收到content.js信息 ---> 接受');
return sendResponse({ res: add(val1, val2) });
}
});
}, []);
return (
<div>
<Button onClick={handleSendContentMessage}>Content通信</Button>
<div>
计算5+2=<span>{num1}</span>
</div>
</div>
);
};
export default App;
DevTools Page和background通信
放到DevTools介绍