[Copy Stack] 크롬익스텐션 데모 만들기 - copy한 내용 전달 가능성 확인

dev2820·2022년 12월 15일
0

프로젝트: Copy Stack

목록 보기
4/28
post-thumbnail

페이지에서 복사한 내용을 background로 전송할 수 있는지 확인해보겠습니다.

popup,background,content 간의 통신

popup, background, content 간의 직접적인 통신은 불가능하다고 했습니다. 따라서 chrome이 제공하는 message api를 사용하거나 BroadcastChannel, MessageChannel을 통해 연결을 맺고 통신해야 합니다.

runtime을 이용한 message send

자세한 사용법은 사이트 참고(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로 메세지를 전송하는 경우에도 같은 방식을 이용하며, 잘 동작합니다.

sendMessage의 한계

A message can contain any valid JSON object (null, boolean, number, string, array, or object).

크롬 익스텐션 개발자 문서를 보면 메세지는 JSON 객체를 포함할 수 있다고 합니다. 웬만한 메세지는 전부 보낼 수 있지만, 사진 등에 사용하는 Blob 객체를 전송할 수 없습니다. Blob을 전송하고 싶다면 MessageChannel이나 BroadcastChannel을 이용해야 합니다.

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를 호출하도록 스크립트를 작성했습니다.

channel을 통한 통신

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를 받은 것을 확인할 수 있습니다.

channel 인스턴스 전송 테스트

runtime.sendMessageBroadcastChannel과의 차이를 보기 위해 Blob을 만들어 전송해보겠습니다.

sendMessage를 통한 전송

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을 통한 전송

이번엔 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은 제대로 전송된 것을 확인할 수 있습니다.

copy 전송 테스트

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를 추가하고 이미지 데이터를 전송할 수 있는지 확인하겠습니다.

profile
공부,번역하고 정리하는 곳

0개의 댓글