페이지에서 복사한 내용을 background로 전송할 수 있는지 확인해보겠습니다.
popup, background, content 간의 직접적인 통신은 불가능하다고 했습니다. 따라서 chrome이 제공하는 message api를 사용하거나 BroadcastChannel, MessageChannel을 통해 연결을 맺고 통신해야 합니다.
자세한 사용법은 사이트 참고(https://developer.chrome.com/docs/extensions/mv3/messaging/)
먼저 runtime을 사용하는 방법부터 봅시다.chrome.runtime.sendMessage
를 통해 메세지를 보내고 chrome.runtime.onMessage
를 통해 메세지에 응답하면 됩니다.
// scripts/content.js
// copy 이벤트 발생시 Hello from Content 메세지를 전송
document.addEventListener("copy",async () => {
await chrome.runtime.sendMessage("Hello from Content");
});
// scripts/background.js
// addListener로 이벤트 등록 (addEventListener가 아님에 유의)
chrome.runtime.onMessage.addListener((message,sender,sendResponse)=>{
console.log(message.action);
});
이제 아무 사이트나 들어가서 텍스트를 복사하면 위와 같이 sendMessage
로 전송한 텍스트가 onMessage
로 전달된 것을 확인할 수 있습니다.
onMessage
에서 파라미터로 받은 sendResponse
를 통해 응답을 보낼 수도 있습니다. 아래와 같이 코드를 수정하겠습니다.
// scripts/content.js
// copy 이벤트 발생시 Hello from Content 메세지를 전송
document.addEventListener("copy",async () => {
const response = await chrome.runtime.sendMessage("Hello from Content");
});
// scripts/background.js
// addListener로 이벤트 등록 (addEventListener가 아님에 유의)
chrome.runtime.onMessage.addListener((message,sender,sendResponse)=>{
console.log(message.action);
sendResponse("receive message");
});
lorem ipsum 사이트에서 텍스트를 복사한 결과입니다. receive message가 잘 전달된 것을 볼 수 있습니다.
content에서 background로 보내는 예시만 있지만, popup에서 background로 메세지를 전송하는 경우에도 같은 방식을 이용하며, 잘 동작합니다.
A message can contain any valid JSON object (null, boolean, number, string, array, or object).
크롬 익스텐션 개발자 문서를 보면 메세지는 JSON 객체를 포함할 수 있다고 합니다. 웬만한 메세지는 전부 보낼 수 있지만, 사진 등에 사용하는 Blob 객체를 전송할 수 없습니다. Blob을 전송하고 싶다면 MessageChannel이나 BroadcastChannel을 이용해야 합니다.
이번엔 BroadcastChannel을 이용해 popup과 background 간에 통신을 만들어보겠습니다.
<html>
<head>
<link href="/assets/css/theme.css" rel="stylesheet"></link>
</head>
<body>
<h1 id="title">Copy Stack</h1>
<script src="popup.js"></script>
</body>
popup/index.html
에서 popup/popup.js
를 호출하도록 스크립트를 작성했습니다.
popup에는 아래와 같이 코드를 작성합니다.
// popup/popup.js
const channel = new BroadcastChannel("MY_BROADCAST");
channel.onmessage = (msg) => {
console.log(msg);
};
channel.postMessage("hello from popup");
background에도 같은 이름의 BroadcastChannel을 추가해야합니다.
// scripts/background.js
...
// 새로 추가된 코드
const channel = new BroadcastChannel("MY_BROADCAST"); //popup과 background 모두 동일한 "MY_BROADCAST" 문자열을 씀에 유의
channel.onmessage = (msg) => {
console.log(msg);
channel.postMessage("response from background");
};
background에서 MessageEvent
를 받고 이어서 popup에서도 MessageEvent
를 받은 것을 확인할 수 있습니다.
runtime.sendMessage
와 BroadcastChannel
과의 차이를 보기 위해 Blob을 만들어 전송해보겠습니다.
popup에서 background로 Blob을 전송합니다.
// popup/popup.js
const obj = {
msg: "i am popup",
};
const blob = new Blob([JSON.stringify(obj, null, 2)], {
type: "application/json",
});
chrome.runtime.sendMessage(blob);
// scripts/background.js
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
console.log(message);
});
Blob이 아니라 Object가 전송되고 내용도 텅 비어서 오는 것을 확인할 수 있습니다.
이번엔 BroadcastChannel을 통해 Blob을 전송합니다.
// popup/popup.js
const obj = {
msg: "i am popup",
};
const blob = new Blob([JSON.stringify(obj, null, 2)], {
type: "application/json",
});
const channel = new BroadcastChannel("MY_BROADCAST");
channel.postMessage(blob);
// scripts/background.js
const channel = new BroadcastChannel("MY_BROADCAST");
channel.onmessage = (msg) => {
console.log(msg);
};
BroadcastChannel을 통해 전송한 Blob은 제대로 전송된 것을 확인할 수 있습니다.
content에서 copy 이벤트가 발생하면 background로 copy한 내용을 전송하도록 코드를 작성해보겠습니다.
// scripts/content.js
"use strict";
document.addEventListener("copy", async (evt) => {
const text = await navigator.clipboard.readText();
await chrome.runtime.sendMessage(text);
});
// scripts/background.js
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
console.log(message);
});
ipsum 사이트에서 Lorem Ipsum
텍스트를 복사해보겠습니다.
텍스트가 잘 출력되는 것을 볼 수 있습니다.
결론적으로 copy 이벤트를 캐치하고 background로 전송하는 것은 구현 가능성을 확인했습니다. 다음 글에서 context menu를 추가하고 이미지 데이터를 전송할 수 있는지 확인하겠습니다.